Bind RET and TAB on images for better UX.
[gnus] / lisp / gnus-group.el
index 83b5a6e..5cc4ef6 100644 (file)
@@ -1,35 +1,37 @@
 ;;; gnus-group.el --- group mode commands for Gnus
 
 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 ;;; gnus-group.el --- group mode commands for Gnus
 
 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007 Free Software Foundation, Inc.
+;;   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.
 
 
 ;; 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
+;; 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
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; 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
 
 ;; 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
+;; 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
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;;; Code:
 
 
 ;;; Commentary:
 
 ;;; Code:
 
+;; For Emacs < 22.2.
+(eval-and-compile
+  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
+
 (eval-when-compile
 (eval-when-compile
-  (require 'cl)
-  (defvar tool-bar-mode))
+  (require 'cl))
+(defvar tool-bar-mode)
 
 (require 'gnus)
 (require 'gnus-start)
 
 (require 'gnus)
 (require 'gnus-start)
@@ -108,6 +110,18 @@ If nil, no groups are permanently visible."
   :group 'gnus-group-listing
   :type '(choice regexp (const nil)))
 
   :group 'gnus-group-listing
   :type '(choice regexp (const nil)))
 
+(defcustom gnus-safe-html-newsgroups "\\`nnrss[+:]"
+  "Groups in which links in html articles are considered all safe.
+The value may be a regexp matching those groups, a list of group names,
+or nil.  This overrides `mm-w3m-safe-url-regexp' (which see).  This is
+effective only when emacs-w3m renders html articles, i.e., in the case
+`mm-text-html-renderer' is set to `w3m'."
+  :version "23.2"
+  :group 'gnus-group-various
+  :type '(choice regexp
+                (repeat :tag "List of group names" (string :tag "Group"))
+                (const nil)))
+
 (defcustom gnus-list-groups-with-ticked-articles t
   "*If non-nil, list groups that have only ticked articles.
 If nil, only list groups that have unread articles."
 (defcustom gnus-list-groups-with-ticked-articles t
   "*If non-nil, list groups that have only ticked articles.
 If nil, only list groups that have unread articles."
@@ -155,7 +169,7 @@ list."
                         (function-item gnus-group-sort-by-rank)
                         (function :tag "other" nil))))
 
                         (function-item gnus-group-sort-by-rank)
                         (function :tag "other" nil))))
 
-(defcustom gnus-group-line-format "%M\%S\%p\%P\%5y:%B%(%g%)%O\n"
+(defcustom gnus-group-line-format "%M\%S\%p\%P\%5y:%B%(%g%)\n"
   "*Format of group lines.
 It works along the same lines as a normal formatting string,
 with some simple extensions.
   "*Format of group lines.
 It works along the same lines as a normal formatting string,
 with some simple extensions.
@@ -382,6 +396,7 @@ score: The score of the group.
 ticked: The number of ticked articles."
   :group 'gnus-group-visual
   :type '(repeat (cons (sexp :tag "Form") face)))
 ticked: The number of ticked articles."
   :group 'gnus-group-visual
   :type '(repeat (cons (sexp :tag "Form") face)))
+(put 'gnus-group-highlight 'risky-local-variable t)
 
 (defcustom gnus-new-mail-mark ?%
   "Mark used for groups with new mail."
 
 (defcustom gnus-new-mail-mark ?%
   "Mark used for groups with new mail."
@@ -419,6 +434,7 @@ score: The score of the group.
 ticked: The number of ticked articles."
   :group 'gnus-group-icons
   :type '(repeat (cons (sexp :tag "Form") file)))
 ticked: The number of ticked articles."
   :group 'gnus-group-icons
   :type '(repeat (cons (sexp :tag "Form") file)))
+(put 'gnus-group-icon-list 'risky-local-variable t)
 
 (defcustom gnus-group-name-charset-method-alist nil
   "Alist of method and the charset for group names.
 
 (defcustom gnus-group-name-charset-method-alist nil
   "Alist of method and the charset for group names.
@@ -644,7 +660,6 @@ simple manner.")
   "h" gnus-group-make-help-group
   "u" gnus-group-make-useful-group
   "a" gnus-group-make-archive-group
   "h" gnus-group-make-help-group
   "u" gnus-group-make-useful-group
   "a" gnus-group-make-archive-group
-  "k" gnus-group-make-kiboze-group
   "l" gnus-group-nnimap-edit-acl
   "m" gnus-group-make-group
   "E" gnus-group-edit-group
   "l" gnus-group-nnimap-edit-acl
   "m" gnus-group-make-group
   "E" gnus-group-edit-group
@@ -664,13 +679,6 @@ simple manner.")
   "\177" gnus-group-delete-group
   [delete] gnus-group-delete-group)
 
   "\177" gnus-group-delete-group
   [delete] gnus-group-delete-group)
 
-(gnus-define-keys (gnus-group-soup-map "s" gnus-group-group-map)
-  "b" gnus-group-brew-soup
-  "w" gnus-soup-save-areas
-  "s" gnus-soup-send-replies
-  "p" gnus-soup-pack-packet
-  "r" nnsoup-pack-replies)
-
 (gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
   "s" gnus-group-sort-groups
   "a" gnus-group-sort-groups-by-alphabet
 (gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
   "s" gnus-group-sort-groups
   "a" gnus-group-sort-groups-by-alphabet
@@ -922,7 +930,6 @@ simple manner.")
        ["Add the archive group" gnus-group-make-archive-group t]
        ["Make a doc group..." gnus-group-make-doc-group t]
        ["Make a web group..." gnus-group-make-web-group t]
        ["Add the archive group" gnus-group-make-archive-group t]
        ["Make a doc group..." gnus-group-make-doc-group t]
        ["Make a web group..." gnus-group-make-web-group t]
-       ["Make a kiboze group..." gnus-group-make-kiboze-group t]
        ["Make a virtual group..." gnus-group-make-empty-virtual t]
        ["Add a group to a virtual..." gnus-group-add-to-virtual t]
        ["Make an ephemeral group..." gnus-group-read-ephemeral-group t]
        ["Make a virtual group..." gnus-group-make-empty-virtual t]
        ["Add a group to a virtual..." gnus-group-add-to-virtual t]
        ["Make an ephemeral group..." gnus-group-read-ephemeral-group t]
@@ -956,13 +963,6 @@ simple manner.")
     (easy-menu-define
      gnus-group-misc-menu gnus-group-mode-map ""
      `("Gnus"
     (easy-menu-define
      gnus-group-misc-menu gnus-group-mode-map ""
      `("Gnus"
-       ("SOUP"
-       ["Pack replies" nnsoup-pack-replies (fboundp 'nnsoup-request-group)]
-       ["Send replies" gnus-soup-send-replies
-        (fboundp 'gnus-soup-pack-packet)]
-       ["Pack packet" gnus-soup-pack-packet (fboundp 'gnus-soup-pack-packet)]
-       ["Save areas" gnus-soup-save-areas (fboundp 'gnus-soup-pack-packet)]
-       ["Brew SOUP" gnus-group-brew-soup (fboundp 'gnus-soup-pack-packet)])
        ["Send a mail" gnus-group-mail t]
        ["Send a message (mail or news)" gnus-group-post-news t]
        ["Create a local message" gnus-group-news t]
        ["Send a mail" gnus-group-mail t]
        ["Send a message (mail or news)" gnus-group-post-news t]
        ["Create a local message" gnus-group-news t]
@@ -980,7 +980,6 @@ simple manner.")
        ["Browse foreign server..." gnus-group-browse-foreign-server t]
        ["Enter server buffer" gnus-group-enter-server-mode t]
        ["Expire all expirable articles" gnus-group-expire-all-groups t]
        ["Browse foreign server..." gnus-group-browse-foreign-server t]
        ["Enter server buffer" gnus-group-enter-server-mode t]
        ["Expire all expirable articles" gnus-group-expire-all-groups t]
-       ["Generate any kiboze groups" nnkiboze-generate-groups t]
        ["Gnus version" gnus-version t]
        ["Save .newsrc files" gnus-group-save-newsrc t]
        ["Suspend Gnus" gnus-group-suspend t]
        ["Gnus version" gnus-version t]
        ["Save .newsrc files" gnus-group-save-newsrc t]
        ["Suspend Gnus" gnus-group-suspend t]
@@ -1025,7 +1024,7 @@ Pre-defined symbols include `gnus-group-tool-bar-gnome' and
                 (const :tag "Retro look" gnus-group-tool-bar-retro)
                 (repeat :tag "User defined list" gmm-tool-bar-item)
                 (symbol))
                 (const :tag "Retro look" gnus-group-tool-bar-retro)
                 (repeat :tag "User defined list" gmm-tool-bar-item)
                 (symbol))
-  :version "23.0" ;; No Gnus
+  :version "23.1" ;; No Gnus
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
@@ -1068,7 +1067,7 @@ Pre-defined symbols include `gnus-group-tool-bar-gnome' and
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type '(repeat gmm-tool-bar-item)
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type '(repeat gmm-tool-bar-item)
-  :version "23.0" ;; No Gnus
+  :version "23.1" ;; No Gnus
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
@@ -1087,7 +1086,7 @@ See `gmm-tool-bar-from-list' for the format of the list."
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type '(repeat gmm-tool-bar-item)
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type '(repeat gmm-tool-bar-item)
-  :version "23.0" ;; No Gnus
+  :version "23.1" ;; No Gnus
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
@@ -1098,12 +1097,13 @@ These items are not displayed in the Gnus group mode tool bar.
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type 'gmm-tool-bar-zap-list
 
 See `gmm-tool-bar-from-list' for the format of the list."
   :type 'gmm-tool-bar-zap-list
-  :version "23.0" ;; No Gnus
+  :version "23.1" ;; No Gnus
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
 (defvar image-load-path)
   :initialize 'custom-initialize-default
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
 (defvar image-load-path)
+(defvar tool-bar-map)
 
 (defun gnus-group-make-tool-bar (&optional force)
   "Make a group mode tool bar from `gnus-group-tool-bar'.
 
 (defun gnus-group-make-tool-bar (&optional force)
   "Make a group mode tool bar from `gnus-group-tool-bar'.
@@ -1182,8 +1182,8 @@ The following commands are available:
       (goto-char (point-min))
       (setq gnus-group-mark-positions
            (list (cons 'process (and (search-forward
       (goto-char (point-min))
       (setq gnus-group-mark-positions
            (list (cons 'process (and (search-forward
-                                      (mm-string-as-multibyte "\200") nil t)
-                                     (- (point) 2))))))))
+                                      (mm-string-to-multibyte "\200") nil t)
+                                     (- (point) (point-min) 1))))))))
 
 (defun gnus-mouse-pick-group (e)
   "Enter the group under the mouse pointer."
 
 (defun gnus-mouse-pick-group (e)
   "Enter the group under the mouse pointer."
@@ -1218,7 +1218,10 @@ The following commands are available:
 (defun gnus-group-name-charset (method group)
   (if (null method)
       (setq method (gnus-find-method-for-group group)))
 (defun gnus-group-name-charset (method group)
   (if (null method)
       (setq method (gnus-find-method-for-group group)))
-  (let ((item (assoc method gnus-group-name-charset-method-alist))
+  (let ((item (or (assoc method gnus-group-name-charset-method-alist)
+                 (and (consp method)
+                      (assoc (list (car method) (cadr method))
+                             gnus-group-name-charset-method-alist))))
        (alist gnus-group-name-charset-group-alist)
        result)
     (if item
        (alist gnus-group-name-charset-group-alist)
        result)
     (if item
@@ -1352,7 +1355,8 @@ if it is a string, only list groups matching REGEXP."
          (setq not-in-list (delete group not-in-list)))
        (when (gnus-group-prepare-logic
               group
          (setq not-in-list (delete group not-in-list)))
        (when (gnus-group-prepare-logic
               group
-              (and unread              ; This group might be unchecked
+              (and (or unread          ; This group might be unchecked
+                       predicate)      ; Check if this group should be listed
                    (or (not (stringp regexp))
                        (string-match regexp group))
                    (<= (setq clevel (gnus-info-level info)) level)
                    (or (not (stringp regexp))
                        (string-match regexp group))
                    (<= (setq clevel (gnus-info-level info)) level)
@@ -1366,7 +1370,7 @@ if it is a string, only list groups matching REGEXP."
                       (if (eq unread t) ; Unactivated?
                           gnus-group-list-inactive-groups
                                        ; We list unactivated
                       (if (eq unread t) ; Unactivated?
                           gnus-group-list-inactive-groups
                                        ; We list unactivated
-                        (> unread 0))
+                        (and (numberp unread) (> unread 0)))
                                        ; We list groups with unread articles
                       (and gnus-list-groups-with-ticked-articles
                            (cdr (assq 'tick (gnus-info-marks info))))
                                        ; We list groups with unread articles
                       (and gnus-list-groups-with-ticked-articles
                            (cdr (assq 'tick (gnus-info-marks info))))
@@ -1650,6 +1654,24 @@ if it is a string, only list groups matching REGEXP."
         (ticked (gnus-range-length (cdr (assq 'tick marked))))
         (group-age (gnus-group-timestamp-delta group))
         (inhibit-read-only t))
         (ticked (gnus-range-length (cdr (assq 'tick marked))))
         (group-age (gnus-group-timestamp-delta group))
         (inhibit-read-only t))
+    ;; FIXME: http://thread.gmane.org/gmane.emacs.gnus.general/65451/focus=65465
+    ;; ======================================================================
+    ;; From: Richard Stallman
+    ;; Subject: Re: Rewriting gnus-group-highlight-line (was: [...])
+    ;; Cc: ding@gnus.org
+    ;; Date: Sat, 27 Oct 2007 19:41:20 -0400
+    ;; Message-ID: <E1IlvHM-0006TS-7t@fencepost.gnu.org>
+    ;;
+    ;; [...]
+    ;; The kludge is that the alist elements contain expressions that refer
+    ;; to local variables with short names.  Perhaps write your own tiny
+    ;; evaluator that handles just `and', `or', and numeric comparisons
+    ;; and just a few specific variables.
+    ;; ======================================================================
+    ;;
+    ;; Similar for other evaluated variables.  Grep for risky-local-variable
+    ;; to find them!  -- rsteib
+    ;;
     ;; Eval the cars of the lists until we find a match.
     (while (and list
                (not (eval (caar list))))
     ;; Eval the cars of the lists until we find a match.
     (while (and list
                (not (eval (caar list))))
@@ -1666,72 +1688,66 @@ if it is a string, only list groups matching REGEXP."
   "Update all lines where GROUP appear.
 If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't
 already."
   "Update all lines where GROUP appear.
 If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't
 already."
-  ;; Can't use `save-excursion' here, so we do it manually.
-  (let ((buf (current-buffer))
-       mark)
-    (set-buffer gnus-group-buffer)
-    (setq mark (point-marker))
-    ;; The buffer may be narrowed.
-    (save-restriction
-      (widen)
-      (let ((ident (gnus-intern-safe group gnus-active-hashtb))
-           (loc (point-min))
-           found buffer-read-only)
-       ;; Enter the current status into the dribble buffer.
-       (let ((entry (gnus-group-entry group)))
-         (when (and entry
-                    (not (gnus-ephemeral-group-p group)))
-           (gnus-dribble-enter
-            (concat "(gnus-group-set-info '"
-                    (gnus-prin1-to-string (nth 2 entry))
-                    ")"))))
-       ;; Find all group instances.  If topics are in use, each group
-       ;; may be listed in more than once.
-       (while (setq loc (text-property-any
-                         loc (point-max) 'gnus-group ident))
-         (setq found t)
-         (goto-char loc)
-         (let ((gnus-group-indentation (gnus-group-group-indentation)))
-           (gnus-delete-line)
-           (gnus-group-insert-group-line-info group)
-           (save-excursion
-             (forward-line -1)
-             (gnus-run-hooks 'gnus-group-update-group-hook)))
-         (setq loc (1+ loc)))
-       (unless (or found visible-only)
-         ;; No such line in the buffer, find out where it's supposed to
-         ;; go, and insert it there (or at the end of the buffer).
-         (if gnus-goto-missing-group-function
-             (funcall gnus-goto-missing-group-function group)
-           (let ((entry (cddr (gnus-group-entry group))))
-             (while (and entry (car entry)
-                         (not
-                          (gnus-goto-char
-                           (text-property-any
-                            (point-min) (point-max)
-                            'gnus-group (gnus-intern-safe
-                                         (caar entry) gnus-active-hashtb)))))
-               (setq entry (cdr entry)))
-             (or entry (goto-char (point-max)))))
-         ;; Finally insert the line.
-         (let ((gnus-group-indentation (gnus-group-group-indentation)))
-           (gnus-group-insert-group-line-info group)
-           (save-excursion
-             (forward-line -1)
-             (gnus-run-hooks 'gnus-group-update-group-hook))))
-       (when gnus-group-update-group-function
-         (funcall gnus-group-update-group-function group))
-       (gnus-group-set-mode-line)))
-    (goto-char mark)
-    (set-marker mark nil)
-    (set-buffer buf)))
+  (with-current-buffer gnus-group-buffer
+    (save-excursion
+      ;; The buffer may be narrowed.
+      (save-restriction
+        (widen)
+        (let ((ident (gnus-intern-safe group gnus-active-hashtb))
+              (loc (point-min))
+              found buffer-read-only)
+          ;; Enter the current status into the dribble buffer.
+          (let ((entry (gnus-group-entry group)))
+            (when (and entry
+                       (not (gnus-ephemeral-group-p group)))
+              (gnus-dribble-enter
+               (concat "(gnus-group-set-info '"
+                       (gnus-prin1-to-string (nth 2 entry))
+                       ")"))))
+          ;; Find all group instances.  If topics are in use, each group
+          ;; may be listed in more than once.
+          (while (setq loc (text-property-any
+                            loc (point-max) 'gnus-group ident))
+            (setq found t)
+            (goto-char loc)
+            (let ((gnus-group-indentation (gnus-group-group-indentation)))
+              (gnus-delete-line)
+              (gnus-group-insert-group-line-info group)
+              (save-excursion
+                (forward-line -1)
+                (gnus-run-hooks 'gnus-group-update-group-hook)))
+            (setq loc (1+ loc)))
+          (unless (or found visible-only)
+            ;; No such line in the buffer, find out where it's supposed to
+            ;; go, and insert it there (or at the end of the buffer).
+            (if gnus-goto-missing-group-function
+                (funcall gnus-goto-missing-group-function group)
+              (let ((entry (cddr (gnus-group-entry group))))
+                (while (and entry (car entry)
+                            (not
+                             (gnus-goto-char
+                              (text-property-any
+                               (point-min) (point-max)
+                               'gnus-group (gnus-intern-safe
+                                            (caar entry)
+                                            gnus-active-hashtb)))))
+                  (setq entry (cdr entry)))
+                (or entry (goto-char (point-max)))))
+            ;; Finally insert the line.
+            (let ((gnus-group-indentation (gnus-group-group-indentation)))
+              (gnus-group-insert-group-line-info group)
+              (save-excursion
+                (forward-line -1)
+                (gnus-run-hooks 'gnus-group-update-group-hook))))
+          (when gnus-group-update-group-function
+            (funcall gnus-group-update-group-function group))
+          (gnus-group-set-mode-line))))))
 
 (defun gnus-group-set-mode-line ()
   "Update the mode line in the group buffer."
   (when (memq 'group gnus-updated-mode-lines)
     ;; Yes, we want to keep this mode line updated.
 
 (defun gnus-group-set-mode-line ()
   "Update the mode line in the group buffer."
   (when (memq 'group gnus-updated-mode-lines)
     ;; Yes, we want to keep this mode line updated.
-    (save-excursion
-      (set-buffer gnus-group-buffer)
+    (with-current-buffer gnus-group-buffer
       (let* ((gformat (or gnus-group-mode-line-format-spec
                          (gnus-set-format 'group-mode)))
             (gnus-tmp-news-server (cadr gnus-select-method))
       (let* ((gformat (or gnus-group-mode-line-format-spec
                          (gnus-set-format 'group-mode)))
             (gnus-tmp-news-server (cadr gnus-select-method))
@@ -1744,8 +1760,7 @@ already."
              (and gnus-dribble-buffer
                   (buffer-name gnus-dribble-buffer)
                   (buffer-modified-p gnus-dribble-buffer)
              (and gnus-dribble-buffer
                   (buffer-name gnus-dribble-buffer)
                   (buffer-modified-p gnus-dribble-buffer)
-                  (save-excursion
-                    (set-buffer gnus-dribble-buffer)
+                  (with-current-buffer gnus-dribble-buffer
                     (not (zerop (buffer-size))))))
             (mode-string (eval gformat)))
        ;; Say whether the dribble buffer has been modified.
                     (not (zerop (buffer-size))))))
             (mode-string (eval gformat)))
        ;; Say whether the dribble buffer has been modified.
@@ -2028,10 +2043,15 @@ and with point over the group in question."
 (defun gnus-group-read-group (&optional all no-article group select-articles)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
 (defun gnus-group-read-group (&optional all no-article group select-articles)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
-readable.  IF ALL is a number, fetch this number of articles.  If the
-optional argument NO-ARTICLE is non-nil, no article will be
-auto-selected upon group entry.  If GROUP is non-nil, fetch that
-group."
+readable.
+
+If ALL is a positive number, fetch this number of the latest
+articles in the group.  If ALL is a negative number, fetch this
+number of the earliest articles in the group.
+
+If the optional argument NO-ARTICLE is non-nil, no article will
+be auto-selected upon group entry.  If GROUP is non-nil, fetch
+that group."
   (interactive "P")
   (let ((no-display (eq all 0))
        (group (or group (gnus-group-group-name)))
   (interactive "P")
   (let ((no-display (eq all 0))
        (group (or group (gnus-group-group-name)))
@@ -2110,28 +2130,87 @@ be permanent."
     (gnus-group-read-ephemeral-group
      (gnus-group-prefixed-name group method) method)))
 
     (gnus-group-read-ephemeral-group
      (gnus-group-prefixed-name group method) method)))
 
-(defun group-name-at-point ()
-  (let ((regexp "[^-a-zA-Z+.:_]"))
-    (save-excursion
-      (buffer-substring
-       (progn
-        (re-search-backward regexp nil t)
-        (forward-char 1)
-        (point))
-       (progn
-        (re-search-forward regexp nil t)
-        (forward-char -1)
-        (point))))))
+(defun gnus-group-name-at-point ()
+  "Return a group name from around point if it exists, or nil."
+  (if (eq major-mode 'gnus-group-mode)
+      (let ((group (gnus-group-group-name)))
+       (when group
+         (gnus-group-decoded-name group)))
+    (let ((regexp "[][\C-@-\t\v-*,/:-@\\^`{-\C-?]*\
+\\(nn[a-z]+\\(?:\\+[^][\C-@-*,/:-@\\^`{-\C-?]+\\)?:\
+\[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)*\
+\\|[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)+\\)")
+         (start (point))
+         (case-fold-search nil))
+      (prog1
+         (if (or (and (not (or (eobp)
+                               (looking-at "[][\C-@-*,/;-@\\^`{-\C-?]")))
+                      (prog1 t
+                        (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                             (point-at-bol))))
+                 (and (looking-at "[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*$")
+                      (prog1 t
+                        (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
+                        (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                             (point-at-bol))))
+                 (string-match "\\`[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*\\'"
+                               (buffer-substring (point-at-bol) (point))))
+             (when (looking-at regexp)
+               (match-string 1))
+           (let (group distance)
+             (when (looking-at regexp)
+               (setq group (match-string 1)
+                     distance (- (match-beginning 1) (match-beginning 0))))
+             (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
+             (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
+                                  (point-at-bol))
+             (if (looking-at regexp)
+                 (if (and group (<= distance (- start (match-end 0))))
+                     group
+                   (match-string 1))
+               group)))
+       (goto-char start)))))
+
+(defun gnus-group-completing-read (prompt &optional collection predicate
+                                         require-match initial-input hist def
+                                         &rest args)
+  "Read a group name with completion.  Non-ASCII group names are allowed.
+The arguments are the same as `completing-read' except that COLLECTION
+and HIST default to `gnus-active-hashtb' and `gnus-group-history'
+respectively if they are omitted."
+  (let ((completion-styles (and (boundp 'completion-styles)
+                               completion-styles))
+       group)
+    (push 'substring completion-styles)
+    (mapatoms (lambda (symbol)
+               (setq group (symbol-name symbol))
+               (set (intern (if (string-match "[^\000-\177]" group)
+                                (gnus-group-decoded-name group)
+                              group)
+                            collection)
+                    group))
+             (prog1
+                 (or collection
+                     (setq collection (or gnus-active-hashtb [0])))
+               (setq collection (gnus-make-hashtable (length collection)))))
+    (setq group (apply 'completing-read prompt collection predicate
+                      require-match initial-input
+                      (or hist 'gnus-group-history)
+                      def args))
+    (or (prog1
+           (symbol-value (intern-soft group collection))
+         (setq collection nil))
+       (mm-encode-coding-string group (gnus-group-name-charset nil group)))))
 
 ;;;###autoload
 (defun gnus-fetch-group (group &optional articles)
   "Start Gnus if necessary and enter GROUP.
 If ARTICLES, display those articles.
 Returns whether the fetching was successful or not."
 
 ;;;###autoload
 (defun gnus-fetch-group (group &optional articles)
   "Start Gnus if necessary and enter GROUP.
 If ARTICLES, display those articles.
 Returns whether the fetching was successful or not."
-  (interactive (list (completing-read "Group name: " gnus-active-hashtb
-                                     nil nil nil nil
-                                     (group-name-at-point))))
-  (unless (get-buffer gnus-group-buffer)
+  (interactive (list (gnus-group-completing-read "Group name: "
+                                                nil nil nil
+                                                (gnus-group-name-at-point))))
+  (unless (gnus-alive-p)
     (gnus-no-server))
   (gnus-group-read-group (if articles nil t) nil group articles))
 
     (gnus-no-server))
   (gnus-group-read-group (if articles nil t) nil group articles))
 
@@ -2191,10 +2270,7 @@ Return the name of the group if selection was successful."
   (interactive
    (list
     ;; (gnus-read-group "Group name: ")
   (interactive
    (list
     ;; (gnus-read-group "Group name: ")
-    (completing-read
-     "Group: " gnus-active-hashtb
-     nil nil nil
-     'gnus-group-history)
+    (gnus-group-completing-read "Group: ")
     (gnus-read-method "From method: ")))
   ;; Transform the select method into a unique server.
   (when (stringp method)
     (gnus-read-method "From method: ")))
   ;; Transform the select method into a unique server.
   (when (stringp method)
@@ -2240,23 +2316,154 @@ Return the name of the group if selection was successful."
         (message "Quit reading the ephemeral group")
         nil)))))
 
         (message "Quit reading the ephemeral group")
         nil)))))
 
+(defcustom gnus-gmane-group-download-format
+  "http://download.gmane.org/%s/%s/%s"
+  "URL for downloading mbox files.
+It must contain three \"%s\".  They correspond to the group, the
+minimal and maximal article numbers, respectively."
+  :group 'gnus-group-foreign
+  :version "23.1" ;; No Gnus
+  :type 'string)
+
+(autoload 'url-insert-file-contents "url-handlers")
+;; FIXME:
+;; - Add documentation, menu, key bindings, ...
+
+(defun gnus-read-ephemeral-gmane-group (group start &optional range)
+  "Read articles from Gmane group GROUP as an ephemeral group.
+START is the first article.  RANGE specifies how many articles
+are fetched.  The articles are downloaded via HTTP using the URL
+specified by `gnus-gmane-group-download-format'."
+  ;; See <http://gmane.org/export.php> for more information.
+  (interactive
+   (list
+    (gnus-group-completing-read "Gmane group: ")
+    (read-number "Start article number: ")
+    (read-number "How many articles: ")))
+  (unless range (setq range 500))
+  (when (< range 1)
+    (error "Invalid range: %s" range))
+  (let ((tmpfile (mm-make-temp-file
+                 (format "%s.start-%s.range-%s." group start range)))
+       (gnus-thread-sort-functions '(gnus-thread-sort-by-number)))
+    (with-temp-file tmpfile
+      (url-insert-file-contents
+       (format gnus-gmane-group-download-format
+              group start (+ start range)))
+      (write-region (point-min) (point-max) tmpfile)
+      (gnus-group-read-ephemeral-group
+       (format "%s.start-%s.range-%s" group start range)
+       `(nndoc ,tmpfile
+              (nndoc-article-type mbox))))
+    (delete-file tmpfile)))
+
+(defun gnus-read-ephemeral-gmane-group-url (url)
+  "Create an ephemeral Gmane group from URL.
+
+Valid input formats include:
+\"http://thread.gmane.org/gmane.foo.bar/12300/focus=12399\",
+\"http://thread.gmane.org/gmane.foo.bar/12345/\",
+\"http://article.gmane.org/gmane.foo.bar/12345/\",
+\"http://news.gmane.org/group/gmane.foo.bar/thread=12345\""
+  ;; - Feel free to add other useful Gmane URLs here!  Maybe the URLs should
+  ;;   be customizable?
+  ;; - The URLs should be added to `gnus-button-alist'.  Probably we should
+  ;;   prompt the user to decide: "View via `browse-url' or in Gnus? "
+  ;;   (`gnus-read-ephemeral-gmane-group-url')
+  (interactive
+   (list (gnus-group-completing-read "Gmane URL: ")))
+  (let (group start range)
+    (cond
+     ;; URLs providing `group', `start' and `range':
+     ((string-match
+       ;; http://thread.gmane.org/gmane.emacs.devel/86326/focus=86525
+       "^http://thread\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)/focus=\\([0-9]+\\)$"
+       url)
+      (setq group (match-string 1 url)
+           start (string-to-number (match-string 2 url))
+           ;; Ensure that `range' is large enough to ensure focus article is
+           ;; included.
+           range (- (string-to-number (match-string 3 url))
+                    start -1)))
+     ;; URLs providing `group' and `start':
+     ((or (string-match
+          ;; http://article.gmane.org/gmane.comp.gnu.make.bugs/3584
+          "^http://\\(?:thread\\|article\\|permalink\\)\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)"
+          url)
+         (string-match
+          ;; Don't advertise these in the doc string yet:
+          "^\\(?:nntp\\|news\\)://news\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)"
+          url)
+         (string-match
+          ;; http://news.gmane.org/group/gmane.emacs.gnus.general/thread=65099/force_load=t
+          "^http://news\.gmane\.org/group/\\([^/]+\\)/thread=\\([0-9]+\\)"
+          url))
+      (setq group (match-string 1 url)
+           start (string-to-number (match-string 2 url))))
+     (t
+      (error "Can't parse URL %s" url)))
+    (gnus-read-ephemeral-gmane-group group start range)))
+
+(defcustom gnus-bug-group-download-format-alist
+  '((emacs . "http://debbugs.gnu.org/%s;mbox=yes")
+    (debian
+     . "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s&mbox=yes"))
+  "Alist of symbols for bug trackers and the corresponding URL format string.
+The URL format string must contain a single \"%s\", specifying
+the bug number, and browsing the URL must return mbox output."
+  :group 'gnus-group-foreign
+  :version "23.2" ;; No Gnus
+  :type '(repeat (cons (symbol) (string :tag "URL format string"))))
+
+(defun gnus-read-ephemeral-bug-group (number mbox-url)
+  "Browse bug NUMBER as ephemeral group."
+  (interactive (list (read-string "Enter bug number: "
+                                 (thing-at-point 'word) nil)
+                    ;; FIXME: Add completing-read from
+                    ;; `gnus-emacs-bug-group-download-format' ...
+                    (cdr (assoc 'emacs gnus-bug-group-download-format-alist))))
+  (when (stringp number)
+    (setq number (string-to-number number)))
+  (let ((tmpfile (mm-make-temp-file "gnus-temp-group-")))
+    (with-temp-file tmpfile
+      (url-insert-file-contents (format mbox-url number))
+      (write-region (point-min) (point-max) tmpfile)
+      (gnus-group-read-ephemeral-group
+       "gnus-read-ephemeral-bug"
+       `(nndoc ,tmpfile
+              (nndoc-article-type mbox))))
+    (delete-file tmpfile)))
+
+(defun gnus-read-ephemeral-debian-bug-group (number)
+  "Browse Debian bug NUMBER as ephemeral group."
+  (interactive (list (read-string "Enter bug number: "
+                                 (thing-at-point 'word) nil)))
+  (gnus-read-ephemeral-bug-group
+   number
+   (cdr (assoc 'debian gnus-bug-group-download-format-alist))))
+
+(defun gnus-read-ephemeral-emacs-bug-group (number)
+  "Browse Emacs bug NUMBER as ephemeral group."
+  (interactive (list (read-string "Enter bug number: "
+                                 (thing-at-point 'word) nil)))
+  (gnus-read-ephemeral-bug-group
+   number
+   (cdr (assoc 'emacs gnus-bug-group-download-format-alist))))
+
 (defun gnus-group-jump-to-group (group &optional prompt)
   "Jump to newsgroup GROUP.
 
 If PROMPT (the prefix) is a number, use the prompt specified in
 `gnus-group-jump-to-group-prompt'."
   (interactive
 (defun gnus-group-jump-to-group (group &optional prompt)
   "Jump to newsgroup GROUP.
 
 If PROMPT (the prefix) is a number, use the prompt specified in
 `gnus-group-jump-to-group-prompt'."
   (interactive
-   (list (mm-string-make-unibyte
-         (completing-read
-          "Group: " gnus-active-hashtb nil
-          (gnus-read-active-file-p)
-          (if current-prefix-arg
-              (cdr (assq current-prefix-arg gnus-group-jump-to-group-prompt))
-            (or (and (stringp gnus-group-jump-to-group-prompt)
-                     gnus-group-jump-to-group-prompt)
-                (let ((p (cdr (assq 0 gnus-group-jump-to-group-prompt))))
-                  (and (stringp p) p))))
-          'gnus-group-history))))
+   (list (gnus-group-completing-read
+         "Group: " nil nil (gnus-read-active-file-p)
+         (if current-prefix-arg
+             (cdr (assq current-prefix-arg gnus-group-jump-to-group-prompt))
+           (or (and (stringp gnus-group-jump-to-group-prompt)
+                    gnus-group-jump-to-group-prompt)
+               (let ((p (cdr (assq 0 gnus-group-jump-to-group-prompt))))
+                 (and (stringp p) p)))))))
 
   (when (equal group "")
     (error "Empty group name"))
 
   (when (equal group "")
     (error "Empty group name"))
@@ -2447,17 +2654,16 @@ If EXCLUDE-GROUP, do not go to that group."
 (defun gnus-group-make-group-simple (&optional group)
   "Add a new newsgroup.
 The user will be prompted for GROUP."
 (defun gnus-group-make-group-simple (&optional group)
   "Add a new newsgroup.
 The user will be prompted for GROUP."
-  (interactive
-   (list (completing-read "Group: " gnus-active-hashtb
-                         nil nil nil 'gnus-group-history)))
-  (gnus-group-make-group
-   (gnus-group-real-name group)
-   (gnus-group-server group)))
+  (interactive (list (gnus-group-completing-read "Group: ")))
+  (gnus-group-make-group (gnus-group-real-name group)
+                        (gnus-group-server group)
+                        nil nil t))
 
 
-(defun gnus-group-make-group (name &optional method address args)
+(defun gnus-group-make-group (name &optional method address args encoded)
   "Add a new newsgroup.
 The user will be prompted for a NAME, for a select METHOD, and an
   "Add a new newsgroup.
 The user will be prompted for a NAME, for a select METHOD, and an
-ADDRESS."
+ADDRESS.  NAME should be a human-readable string (i.e., not be encoded
+even if it contains non-ASCII characters) unless ENCODED is non-nil."
   (interactive
    (list
     (gnus-read-group "Group name: ")
   (interactive
    (list
     (gnus-read-group "Group name: ")
@@ -2465,6 +2671,10 @@ ADDRESS."
 
   (when (stringp method)
     (setq method (or (gnus-server-to-method method) method)))
 
   (when (stringp method)
     (setq method (or (gnus-server-to-method method) method)))
+  (unless encoded
+    (setq name (mm-encode-coding-string
+               name
+               (gnus-group-name-charset method name))))
   (let* ((meth (gnus-method-simplify
                (when (and method
                           (not (gnus-server-equal method gnus-select-method)))
   (let* ((meth (gnus-method-simplify
                (when (and method
                           (not (gnus-server-equal method gnus-select-method)))
@@ -2555,14 +2765,19 @@ be removed from the server, even when it's empty."
 When used interactively, GROUP is the group under point
 and NEW-NAME will be prompted for."
   (interactive
 When used interactively, GROUP is the group under point
 and NEW-NAME will be prompted for."
   (interactive
-   (list
-    (gnus-group-group-name)
-    (progn
-      (unless (gnus-check-backend-function
-              'request-rename-group (gnus-group-group-name))
-       (error "This back end does not support renaming groups"))
-      (gnus-read-group "Rename group to: "
-                      (gnus-group-real-name (gnus-group-group-name))))))
+   (let ((group (gnus-group-group-name))
+        method new-name)
+     (unless (gnus-check-backend-function 'request-rename-group group)
+       (error "This back end does not support renaming groups"))
+     (setq new-name (gnus-read-group
+                    "Rename group to: "
+                    (gnus-group-real-name (gnus-group-decoded-name group)))
+          method (gnus-info-method (gnus-get-info group)))
+     (list group (mm-encode-coding-string
+                 new-name
+                 (gnus-group-name-charset
+                  method
+                  (gnus-group-prefixed-name new-name method))))))
 
   (unless (gnus-check-backend-function 'request-rename-group group)
     (error "This back end does not support renaming groups"))
 
   (unless (gnus-check-backend-function 'request-rename-group group)
     (error "This back end does not support renaming groups"))
@@ -2581,29 +2796,34 @@ and NEW-NAME will be prompted for."
           (gnus-group-real-name new-name)
           (gnus-info-method (gnus-get-info group)))))
 
           (gnus-group-real-name new-name)
           (gnus-info-method (gnus-get-info group)))))
 
-  (when (gnus-active new-name)
-    (error "The group %s already exists" new-name))
+  (let ((decoded-group (gnus-group-decoded-name group))
+       (decoded-new-name (gnus-group-decoded-name new-name)))
+    (when (gnus-active new-name)
+      (error "The group %s already exists" decoded-new-name))
 
 
-  (gnus-message 6 "Renaming group %s to %s..." group new-name)
-  (prog1
-      (if (progn
-           (gnus-group-goto-group group)
-           (not (when (< (gnus-group-group-level) gnus-level-zombie)
-                  (gnus-request-rename-group group new-name))))
-         (gnus-error 3 "Couldn't rename group %s to %s" group new-name)
-       ;; We rename the group internally by killing it...
-       (gnus-group-kill-group)
-       ;; ... changing its name ...
-       (setcar (cdar gnus-list-of-killed-groups) new-name)
-       ;; ... and then yanking it.  Magic!
-       (gnus-group-yank-group)
-       (gnus-set-active new-name (gnus-active group))
-       (gnus-message 6 "Renaming group %s to %s...done" group new-name)
-       new-name)
-    (setq gnus-killed-list (delete group gnus-killed-list))
-    (gnus-set-active group nil)
-    (gnus-dribble-touch)
-    (gnus-group-position-point)))
+    (gnus-message 6 "Renaming group %s to %s..."
+                 decoded-group decoded-new-name)
+    (prog1
+       (if (progn
+             (gnus-group-goto-group group)
+             (not (when (< (gnus-group-group-level) gnus-level-zombie)
+                    (gnus-request-rename-group group new-name))))
+           (gnus-error 3 "Couldn't rename group %s to %s"
+                       decoded-group decoded-new-name)
+         ;; We rename the group internally by killing it...
+         (gnus-group-kill-group)
+         ;; ... changing its name ...
+         (setcar (cdar gnus-list-of-killed-groups) new-name)
+         ;; ... and then yanking it.  Magic!
+         (gnus-group-yank-group)
+         (gnus-set-active new-name (gnus-active group))
+         (gnus-message 6 "Renaming group %s to %s...done"
+                       decoded-group decoded-new-name)
+         new-name)
+      (setq gnus-killed-list (delete group gnus-killed-list))
+      (gnus-set-active group nil)
+      (gnus-dribble-touch)
+      (gnus-group-position-point))))
 
 (defun gnus-group-edit-group (group &optional part)
   "Edit the group on the current line."
 
 (defun gnus-group-edit-group (group &optional part)
   "Edit the group on the current line."
@@ -2696,7 +2916,10 @@ and NEW-NAME will be prompted for."
    (let ((entry (assoc (completing-read "Create group: " gnus-useful-groups
                                        nil t)
                       gnus-useful-groups)))
    (let ((entry (assoc (completing-read "Create group: " gnus-useful-groups
                                        nil t)
                       gnus-useful-groups)))
-     (list (cadr entry) (caddr entry))))
+     (list (cadr entry)
+          ;; Don't use `caddr' here since macros within the `interactive'
+          ;; form won't be expanded.
+          (car (cddr entry)))))
   (setq method (gnus-copy-sequence method))
   (let (entry)
     (while (setq entry (memq (assq 'eval method) method))
   (setq method (gnus-copy-sequence method))
   (let (entry)
     (while (setq entry (memq (assq 'eval method) method))
@@ -2756,19 +2979,17 @@ If called with a prefix argument, ask for the file type."
                             nil))))
       (setq type found)))
   (setq file (expand-file-name file))
                             nil))))
       (setq type found)))
   (setq file (expand-file-name file))
-  (let ((name (gnus-generate-new-group-name
-              (gnus-group-prefixed-name
-               (file-name-nondirectory file) '(nndoc ""))))
-       (encodable (mm-coding-system-p 'utf-8)))
+  (let* ((name (gnus-generate-new-group-name
+               (gnus-group-prefixed-name
+                (file-name-nondirectory file) '(nndoc ""))))
+        (method (list 'nndoc file
+                      (list 'nndoc-address file)
+                      (list 'nndoc-article-type (or type 'guess))))
+        (coding (gnus-group-name-charset method name)))
+    (setcar (cdr method) (mm-encode-coding-string file coding))
     (gnus-group-make-group
     (gnus-group-make-group
-     (if encodable
-        (mm-encode-coding-string (gnus-group-real-name name) 'utf-8)
-       (gnus-group-real-name name))
-     (list 'nndoc (if encodable
-                     (mm-encode-coding-string file 'utf-8)
-                   file)
-          (list 'nndoc-address file)
-          (list 'nndoc-article-type (or type 'guess))))))
+     (mm-encode-coding-string (gnus-group-real-name name) coding)
+     method nil nil t)))
 
 (defvar nnweb-type-definition)
 (defvar gnus-group-web-type-history nil)
 
 (defvar nnweb-type-definition)
 (defvar gnus-group-web-type-history nil)
@@ -2809,8 +3030,8 @@ If SOLID (the prefix), create a solid group."
        (cons (current-buffer)
             (if (eq major-mode 'gnus-summary-mode) 'summary 'group))))))
 
        (cons (current-buffer)
             (if (eq major-mode 'gnus-summary-mode) 'summary 'group))))))
 
+(defvar nnrss-group-alist)
 (eval-when-compile
 (eval-when-compile
-  (defvar nnrss-group-alist)
   (defun nnrss-discover-feed (arg))
   (defun nnrss-save-server-data (arg)))
 (defun gnus-group-make-rss-group (&optional url)
   (defun nnrss-discover-feed (arg))
   (defun nnrss-save-server-data (arg)))
 (defun gnus-group-make-rss-group (&optional url)
@@ -2822,65 +3043,36 @@ If there is, use Gnus to create an nnrss group"
       (setq url (read-from-minibuffer "URL to Search for RSS: ")))
   (let ((feedinfo (nnrss-discover-feed url)))
     (if feedinfo
       (setq url (read-from-minibuffer "URL to Search for RSS: ")))
   (let ((feedinfo (nnrss-discover-feed url)))
     (if feedinfo
-       (let ((title (gnus-newsgroup-savable-name
-                     (read-from-minibuffer "Title: "
-                                           (gnus-newsgroup-savable-name
-                                            (or (cdr (assoc 'title
-                                                            feedinfo))
-                                                "")))))
-             (desc  (read-from-minibuffer "Description: "
-                                          (cdr (assoc 'description
-                                                      feedinfo))))
-             (href (cdr (assoc 'href feedinfo)))
-             (encodable (mm-coding-system-p 'utf-8)))
-         (when encodable
+       (let* ((title (gnus-newsgroup-savable-name
+                      (read-from-minibuffer "Title: "
+                                            (gnus-newsgroup-savable-name
+                                             (mapconcat
+                                              'identity
+                                              (split-string
+                                               (or (cdr (assoc 'title
+                                                               feedinfo))
+                                                   ""))
+                                              " ")))))
+              (desc  (read-from-minibuffer "Description: "
+                                           (mapconcat
+                                            'identity
+                                            (split-string
+                                             (or (cdr (assoc 'description
+                                                             feedinfo))
+                                                 ""))
+                                            " ")))
+              (href (cdr (assoc 'href feedinfo)))
+              (coding (gnus-group-name-charset '(nnrss "") title)))
+         (when coding
            ;; Unify non-ASCII text.
            (setq title (mm-decode-coding-string
            ;; Unify non-ASCII text.
            (setq title (mm-decode-coding-string
-                        (mm-encode-coding-string title 'utf-8) 'utf-8)))
-         (gnus-group-make-group (if encodable
-                                    (mm-encode-coding-string title 'utf-8)
-                                  title)
-                                '(nnrss ""))
+                        (mm-encode-coding-string title coding)
+                        coding)))
+         (gnus-group-make-group title '(nnrss ""))
          (push (list title href desc) nnrss-group-alist)
          (nnrss-save-server-data nil))
       (error "No feeds found for %s" url))))
 
          (push (list title href desc) nnrss-group-alist)
          (nnrss-save-server-data nil))
       (error "No feeds found for %s" url))))
 
-(defvar nnwarchive-type-definition)
-(defvar gnus-group-warchive-type-history nil)
-(defvar gnus-group-warchive-login-history nil)
-(defvar gnus-group-warchive-address-history nil)
-
-(defun gnus-group-make-warchive-group ()
-  "Create a nnwarchive group."
-  (interactive)
-  (require 'nnwarchive)
-  (let* ((group (gnus-read-group "Group name: "))
-        (default-type (or (car gnus-group-warchive-type-history)
-                          (symbol-name (caar nnwarchive-type-definition))))
-        (type
-         (gnus-string-or
-          (completing-read
-           (format "Warchive type (default %s): " default-type)
-           (mapcar (lambda (elem) (list (symbol-name (car elem))))
-                   nnwarchive-type-definition)
-           nil t nil 'gnus-group-warchive-type-history)
-          default-type))
-        (address (read-string "Warchive address: "
-                              nil 'gnus-group-warchive-address-history))
-        (default-login (or (car gnus-group-warchive-login-history)
-                           user-mail-address))
-        (login
-         (gnus-string-or
-          (read-string
-           (format "Warchive login (default %s): " user-mail-address)
-           default-login 'gnus-group-warchive-login-history)
-          user-mail-address))
-        (method
-         `(nnwarchive ,address
-                      (nnwarchive-type ,(intern type))
-                      (nnwarchive-login ,login))))
-    (gnus-group-make-group group method)))
-
 (defun gnus-group-make-archive-group (&optional all)
   "Create the (ding) Gnus archive group of the most recent articles.
 Given a prefix, create a full group."
 (defun gnus-group-make-archive-group (&optional all)
   "Create the (ding) Gnus archive group of the most recent articles.
 Given a prefix, create a full group."
@@ -2921,39 +3113,6 @@ mail messages or news articles in files that have numeric names."
      (gnus-group-real-name group)
      (list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir)))))
 
      (gnus-group-real-name group)
      (list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir)))))
 
-(defvar nnkiboze-score-file)
-(defun gnus-group-make-kiboze-group (group address scores)
-  "Create an nnkiboze group.
-The user will be prompted for a name, a regexp to match groups, and
-score file entries for articles to include in the group."
-  (interactive
-   (list
-    (read-string "nnkiboze group name: ")
-    (read-string "Source groups (regexp): ")
-    (let ((headers (mapcar 'list
-                          '("subject" "from" "number" "date" "message-id"
-                            "references" "chars" "lines" "xref"
-                            "followup" "all" "body" "head")))
-         scores header regexp regexps)
-      (while (not (equal "" (setq header (completing-read
-                                         "Match on header: " headers nil t))))
-       (setq regexps nil)
-       (while (not (equal "" (setq regexp (read-string
-                                           (format "Match on %s (regexp): "
-                                                   header)))))
-         (push (list regexp nil nil 'r) regexps))
-       (push (cons header regexps) scores))
-      scores)))
-  (gnus-group-make-group group "nnkiboze" address)
-  (let* ((nnkiboze-current-group group)
-        (score-file (car (nnkiboze-score-file "")))
-        (score-dir (file-name-directory score-file)))
-    (unless (file-exists-p score-dir)
-      (make-directory score-dir))
-    (with-temp-file score-file
-      (let (emacs-lisp-mode-hook)
-       (gnus-pp scores)))))
-
 (defun gnus-group-add-to-virtual (n vgroup)
   "Add the current group to a virtual group."
   (interactive
 (defun gnus-group-add-to-virtual (n vgroup)
   "Add the current group to a virtual group."
   (interactive
@@ -3004,10 +3163,9 @@ score file entries for articles to include in the group."
                       'summary 'group)))
       (error "Couldn't enter %s" dir))))
 
                       'summary 'group)))
       (error "Couldn't enter %s" dir))))
 
-(eval-and-compile
-  (autoload 'nnimap-expunge "nnimap")
-  (autoload 'nnimap-acl-get "nnimap")
-  (autoload 'nnimap-acl-edit "nnimap"))
+(autoload 'nnimap-expunge "nnimap")
+(autoload 'nnimap-acl-get "nnimap")
+(autoload 'nnimap-acl-edit "nnimap")
 
 (defun gnus-group-nnimap-expunge (group)
   "Expunge deleted articles in current nnimap GROUP."
 
 (defun gnus-group-nnimap-expunge (group)
   "Expunge deleted articles in current nnimap GROUP."
@@ -3534,12 +3692,8 @@ If given numerical prefix, toggle the N next groups."
   "Toggle subscription to GROUP.
 Killed newsgroups are subscribed.  If SILENT, don't try to update the
 group line."
   "Toggle subscription to GROUP.
 Killed newsgroups are subscribed.  If SILENT, don't try to update the
 group line."
-  (interactive
-   (list (completing-read
-         "Group: " gnus-active-hashtb nil
-         (gnus-read-active-file-p)
-         nil
-         'gnus-group-history)))
+  (interactive (list (gnus-group-completing-read
+                     "Group: " nil nil (gnus-read-active-file-p))))
   (let ((newsrc (gnus-group-entry group)))
     (cond
      ((string-match "^[ \t]*$" group)
   (let ((newsrc (gnus-group-entry group)))
     (cond
      ((string-match "^[ \t]*$" group)
@@ -3828,23 +3982,13 @@ re-scanning.  If ARG is non-nil and not a number, this will force
                        (>= arg gnus-use-nocem))
                   (not arg)))
       (gnus-nocem-scan-groups))
                        (>= arg gnus-use-nocem))
                   (not arg)))
       (gnus-nocem-scan-groups))
-    ;; If ARG is not a number, then we read the active file.
-    (when (and arg (not (numberp arg)))
-      (let ((gnus-read-active-file t))
-       (gnus-read-active-file))
-      (setq arg nil)
-
-      ;; If the user wants it, we scan for new groups.
-      (when (eq gnus-check-new-newsgroups 'always)
-       (gnus-find-new-newsgroups)))
-
-    (setq arg (gnus-group-default-level arg t))
-    (if (and gnus-read-active-file (not arg))
-       (progn
-         (gnus-read-active-file)
-         (gnus-get-unread-articles arg))
-      (let ((gnus-read-active-file (if arg nil gnus-read-active-file)))
-       (gnus-get-unread-articles arg)))
+
+    (gnus-get-unread-articles arg)
+
+    ;; If the user wants it, we scan for new groups.
+    (when (eq gnus-check-new-newsgroups 'always)
+      (gnus-find-new-newsgroups))
+
     (gnus-check-reasonable-setup)
     (gnus-run-hooks 'gnus-after-getting-new-news-hook)
     (gnus-group-list-groups (and (numberp arg)
     (gnus-check-reasonable-setup)
     (gnus-run-hooks 'gnus-after-getting-new-news-hook)
     (gnus-group-list-groups (and (numberp arg)
@@ -3926,7 +4070,7 @@ to use."
 If given a prefix argument, prompt for a group."
   (interactive
    (list (or (when current-prefix-arg
 If given a prefix argument, prompt for a group."
   (interactive
    (list (or (when current-prefix-arg
-              (completing-read "Group: " gnus-active-hashtb))
+              (gnus-group-completing-read "Group: "))
             (gnus-group-group-name)
             gnus-newsgroup-name)))
   (unless group
             (gnus-group-group-name)
             gnus-newsgroup-name)))
   (unless group
@@ -3954,7 +4098,7 @@ If given a prefix argument, prompt for a group."
 If given a prefix argument, prompt for a group."
   (interactive
    (list (or (when current-prefix-arg
 If given a prefix argument, prompt for a group."
   (interactive
    (list (or (when current-prefix-arg
-              (completing-read "Group: " gnus-active-hashtb))
+              (gnus-group-completing-read "Group: "))
             (gnus-group-group-name)
             gnus-newsgroup-name)))
   (unless group
             (gnus-group-group-name)
             gnus-newsgroup-name)))
   (unless group
@@ -4180,12 +4324,12 @@ The hook `gnus-suspend-gnus-hook' is called before actually suspending."
   (gnus-offer-save-summaries)
   ;; Kill Gnus buffers except for group mode buffer.
   (let ((group-buf (get-buffer gnus-group-buffer)))
   (gnus-offer-save-summaries)
   ;; Kill Gnus buffers except for group mode buffer.
   (let ((group-buf (get-buffer gnus-group-buffer)))
-    (mapcar (lambda (buf)
-             (unless (or (member buf (list group-buf gnus-dribble-buffer))
-                         (with-current-buffer buf
-                           (eq major-mode 'message-mode)))
-               (gnus-kill-buffer buf)))
-           (gnus-buffers))
+    (dolist (buf (gnus-buffers))
+      (unless (or (eq buf group-buf)
+                 (eq buf gnus-dribble-buffer)
+                 (with-current-buffer buf
+                   (eq major-mode 'message-mode)))
+       (gnus-kill-buffer buf)))
     (setq gnus-backlog-articles nil)
     (gnus-kill-gnus-frames)
     (when group-buf
     (setq gnus-backlog-articles nil)
     (gnus-kill-gnus-frames)
     (when group-buf
@@ -4234,8 +4378,7 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
     (gnus-run-hooks 'gnus-exit-gnus-hook)
     (gnus-configure-windows 'group t)
     (when (and (gnus-buffer-live-p gnus-dribble-buffer)
     (gnus-run-hooks 'gnus-exit-gnus-hook)
     (gnus-configure-windows 'group t)
     (when (and (gnus-buffer-live-p gnus-dribble-buffer)
-              (not (zerop (save-excursion
-                           (set-buffer gnus-dribble-buffer)
+              (not (zerop (with-current-buffer gnus-dribble-buffer
                            (buffer-size)))))
       (gnus-dribble-enter
        ";;; Gnus was exited on purpose without saving the .newsrc files."))
                            (buffer-size)))))
       (gnus-dribble-enter
        ";;; Gnus was exited on purpose without saving the .newsrc files."))
@@ -4296,13 +4439,11 @@ and the second element is the address."
          (setcar (nthcdr (1- total) info) part-info)))
       (unless entry
        ;; This is a new group, so we just create it.
          (setcar (nthcdr (1- total) info) part-info)))
       (unless entry
        ;; This is a new group, so we just create it.
-       (save-excursion
-         (set-buffer gnus-group-buffer)
+       (with-current-buffer gnus-group-buffer
          (setq method (gnus-info-method info))
          (when (gnus-server-equal method "native")
            (setq method nil))
          (setq method (gnus-info-method info))
          (when (gnus-server-equal method "native")
            (setq method nil))
-         (save-excursion
-           (set-buffer gnus-group-buffer)
+         (with-current-buffer gnus-group-buffer
            (if method
                ;; It's a foreign group...
                (gnus-group-make-group
            (if method
                ;; It's a foreign group...
                (gnus-group-make-group
@@ -4310,9 +4451,10 @@ and the second element is the address."
                 (if (stringp method) method
                   (prin1-to-string (car method)))
                 (and (consp method)
                 (if (stringp method) method
                   (prin1-to-string (car method)))
                 (and (consp method)
-                     (nth 1 (gnus-info-method info))))
+                     (nth 1 (gnus-info-method info)))
+                nil t)
              ;; It's a native group.
              ;; It's a native group.
-             (gnus-group-make-group (gnus-info-group info))))
+             (gnus-group-make-group (gnus-info-group info) nil nil nil t)))
          (gnus-message 6 "Note: New group created")
          (setq entry
                (gnus-group-entry (gnus-group-prefixed-name
          (gnus-message 6 "Note: New group created")
          (setq entry
                (gnus-group-entry (gnus-group-prefixed-name
@@ -4365,8 +4507,7 @@ and the second element is the address."
   "Mark ARTICLE in GROUP with MARK, whether the group is displayed or not."
   (let ((buffer (gnus-summary-buffer-name group)))
     (if (gnus-buffer-live-p buffer)
   "Mark ARTICLE in GROUP with MARK, whether the group is displayed or not."
   (let ((buffer (gnus-summary-buffer-name group)))
     (if (gnus-buffer-live-p buffer)
-       (save-excursion
-         (set-buffer (get-buffer buffer))
+       (with-current-buffer (get-buffer buffer)
          (gnus-summary-add-mark article mark))
       (gnus-add-marked-articles group (cdr (assq mark gnus-article-mark-lists))
                                (list article)))))
          (gnus-summary-add-mark article mark))
       (gnus-add-marked-articles group (cdr (assq mark gnus-article-mark-lists))
                                (list article)))))
@@ -4566,5 +4707,4 @@ Compacting group %s... (this may take a long time)"
 
 (provide 'gnus-group)
 
 
 (provide 'gnus-group)
 
-;;; arch-tag: 2eb5440f-0bca-4091-814c-e37817536af6
 ;;; gnus-group.el ends here
 ;;; gnus-group.el ends here