* mm-util.el (mm-charset-eval-alist): Mark as risky local variable.
[gnus] / lisp / gnus-group.el
index ae80239..97eb37a 100644 (file)
@@ -1,7 +1,7 @@
 ;;; 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 Free Software Foundation, Inc.
+;;   2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -10,7 +10,7 @@
 
 ;; 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
 
 ;; 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 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -29,7 +29,7 @@
 
 (eval-when-compile
   (require 'cl)
 
 (eval-when-compile
   (require 'cl)
-  (defvar tool-bar-map))
+  (defvar tool-bar-mode))
 
 (require 'gnus)
 (require 'gnus-start)
 
 (require 'gnus)
 (require 'gnus-start)
@@ -135,7 +135,7 @@ for the groups to be sorted.  Pre-made functions include
 `gnus-group-sort-by-score', `gnus-group-sort-by-method',
 `gnus-group-sort-by-server', and `gnus-group-sort-by-rank'.
 
 `gnus-group-sort-by-score', `gnus-group-sort-by-method',
 `gnus-group-sort-by-server', and `gnus-group-sort-by-rank'.
 
-This variable can also be a list of sorting functions. In that case,
+This variable can also be a list of sorting functions.  In that case,
 the most significant sort function should be the last function in the
 list."
   :group 'gnus-group-listing
 the most significant sort function should be the last function in the
 list."
   :group 'gnus-group-listing
@@ -197,7 +197,7 @@ with some simple extensions.
 
 Note that this format specification is not always respected.  For
 reasons of efficiency, when listing killed groups, this specification
 
 Note that this format specification is not always respected.  For
 reasons of efficiency, when listing killed groups, this specification
-is ignored altogether. If the spec is changed considerably, your
+is ignored altogether.  If the spec is changed considerably, your
 output may end up looking strange when listing both alive and killed
 groups.
 
 output may end up looking strange when listing both alive and killed
 groups.
 
@@ -382,6 +382,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 +420,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.
@@ -1010,8 +1012,9 @@ Setter function for custom variables."
     (with-current-buffer gnus-group-buffer
       (gnus-group-make-tool-bar t))))
 
     (with-current-buffer gnus-group-buffer
       (gnus-group-make-tool-bar t))))
 
-;; The default will be changed when the new icons have been checked in:
-(defcustom gnus-group-tool-bar 'gnus-group-tool-bar-retro
+(defcustom gnus-group-tool-bar (if (eq gmm-tool-bar-style 'gnome)
+                                  'gnus-group-tool-bar-gnome
+                                'gnus-group-tool-bar-retro)
   "Specifies the Gnus group tool bar.
 
 It can be either a list or a symbol refering to a list.  See
   "Specifies the Gnus group tool bar.
 
 It can be either a list or a symbol refering to a list.  See
@@ -1030,31 +1033,38 @@ Pre-defined symbols include `gnus-group-tool-bar-gnome' and
   :group 'gnus-group)
 
 (defcustom gnus-group-tool-bar-gnome
   :group 'gnus-group)
 
 (defcustom gnus-group-tool-bar-gnome
-  '((gnus-group-post-news "compose")
-    (gnus-group-get-new-news "inbox") ;; Add... nil :visible gnus-plugged ?
-    ;; FIXME: gnus-*-read-group should have a better help text.
-    (gnus-topic-read-group "open" nil :visible gnus-topic-mode)
-    (gnus-group-read-group "open" nil :visible (not gnus-topic-mode))
-    ;; (gnus-group-find-new-groups "???" nil)
-    (gnus-group-save-newsrc "save")
-    (gnus-group-describe-group "describe")
-    (gnus-group-unsubscribe-current-group "toggle-subscription")
-    ;; (gnus-group-subscribe "subscribe" t
-    ;;                           :help "Subscribe to the current group")
-    ;; (gnus-group-unsubscribe "unsubscribe" t
-    ;;                             :help "Unsubscribe from the current group")
-    ;;
+  '((gnus-group-post-news "mail/compose")
     ;; Some useful agent icons?  I don't use the agent so agent users should
     ;; suggest useful commands:
     ;; Some useful agent icons?  I don't use the agent so agent users should
     ;; suggest useful commands:
-    (gnus-group-send-queue "outbox" t
-                          :visible (and gnus-agent gnus-plugged)
-                          :help "Send articles from the queue group")
-    (gnus-agent-toggle-plugged "connect" nil
+    (gnus-agent-toggle-plugged "disconnect" t
+                              :help "Gnus is currently unplugged.  Click to work online."
                               :visible (and gnus-agent (not gnus-plugged)))
                               :visible (and gnus-agent (not gnus-plugged)))
-    (gnus-agent-toggle-plugged "disconnect" nil
+    (gnus-agent-toggle-plugged "connect" t
+                              :help "Gnus is currently plugged.  Click to work offline."
                               :visible (and gnus-agent gnus-plugged))
                               :visible (and gnus-agent gnus-plugged))
-    ;;
-    (gnus-group-exit "exit-mode")
+    ;; FIXME: gnus-agent-toggle-plugged (in gnus-agent-group-make-menu-bar)
+    ;; should have a better help text.
+    (gnus-group-send-queue "mail/outbox" t
+                          :visible (and gnus-agent gnus-plugged)
+                          :help "Send articles from the queue group")
+    (gnus-group-get-new-news "mail/inbox" nil
+                            :visible (or (not gnus-agent)
+                                         gnus-plugged))
+    ;; FIXME: gnus-*-read-group should have a better help text.
+    (gnus-topic-read-group "open" nil
+                          :visible (and (boundp 'gnus-topic-mode)
+                                        gnus-topic-mode))
+    (gnus-group-read-group "open" nil
+                          :visible (not (and (boundp 'gnus-topic-mode)
+                                             gnus-topic-mode)))
+    ;; (gnus-group-find-new-groups "???" nil)
+    (gnus-group-save-newsrc "save")
+    (gnus-group-describe-group "describe")
+    (gnus-group-unsubscribe-current-group "gnus/toggle-subscription")
+    (gnus-group-prev-unread-group "left-arrow")
+    (gnus-group-next-unread-group "right-arrow")
+    (gnus-group-exit "exit")
+    (gmm-customize-mode "preferences" t :help "Edit mode preferences")
     (gnus-info-find-node "help"))
   "List of functions for the group tool bar (GNOME style).
 
     (gnus-info-find-node "help"))
   "List of functions for the group tool bar (GNOME style).
 
@@ -1066,15 +1076,15 @@ See `gmm-tool-bar-from-list' for the format of the list."
   :group 'gnus-group)
 
 (defcustom gnus-group-tool-bar-retro
   :group 'gnus-group)
 
 (defcustom gnus-group-tool-bar-retro
-  '((gnus-group-get-new-news "get-news")
-    (gnus-group-get-new-news-this-group "gnntg")
-    (gnus-group-catchup-current "catchup")
-    (gnus-group-describe-group "describe-group")
-    (gnus-group-subscribe "subscribe" t
+  '((gnus-group-get-new-news "gnus/get-news")
+    (gnus-group-get-new-news-this-group "gnus/gnntg")
+    (gnus-group-catchup-current "gnus/catchup")
+    (gnus-group-describe-group "gnus/describe-group")
+    (gnus-group-subscribe "gnus/subscribe" t
                          :help "Subscribe to the current group")
                          :help "Subscribe to the current group")
-    (gnus-group-unsubscribe "unsubscribe" t
+    (gnus-group-unsubscribe "gnus/unsubscribe" t
                            :help "Unsubscribe from the current group")
                            :help "Unsubscribe from the current group")
-    (gnus-group-exit "exit-gnus" gnus-group-mode-map))
+    (gnus-group-exit "gnus/exit-gnus" gnus-group-mode-map))
   "List of functions for the group tool bar (retro look).
 
 See `gmm-tool-bar-from-list' for the format of the list."
   "List of functions for the group tool bar (retro look).
 
 See `gmm-tool-bar-from-list' for the format of the list."
@@ -1084,17 +1094,6 @@ See `gmm-tool-bar-from-list' for the format of the list."
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
-;; FIXME: Moving through the Group buffer (in topic mode) e.g. with C-n
-;; doesn't update the state (enabled/disabled) of the icon
-;; `gnus-group-describe-group'.  After `C-l' the state is correct.
-;; See the following report on emacs-devel
-;; <http://thread.gmane.org/v9acdmrcse.fsf@marauder.physik.uni-ulm.de>:
-;; From: Reiner Steib
-;; Subject: tool bar icons not updated according to :active condition
-;; Newsgroups: gmane.emacs.devel
-;; Date: Mon, 23 Jan 2006 19:59:13 +0100
-;; Message-ID: <v9acdmrcse.fsf@marauder.physik.uni-ulm.de>
-
 (defcustom gnus-group-tool-bar-zap-list t
   "List of icon items from the global tool bar.
 These items are not displayed in the Gnus group mode tool bar.
 (defcustom gnus-group-tool-bar-zap-list t
   "List of icon items from the global tool bar.
 These items are not displayed in the Gnus group mode tool bar.
@@ -1106,15 +1105,27 @@ See `gmm-tool-bar-from-list' for the format of the list."
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
   :set 'gnus-group-tool-bar-update
   :group 'gnus-group)
 
+(defvar image-load-path)
+
 (defun gnus-group-make-tool-bar (&optional force)
   "Make a group mode tool bar from `gnus-group-tool-bar'.
 When FORCE, rebuild the tool bar."
 (defun gnus-group-make-tool-bar (&optional force)
   "Make a group mode tool bar from `gnus-group-tool-bar'.
 When FORCE, rebuild the tool bar."
-  (when (or (not gnus-group-tool-bar-map) force)
-    (let ((map (when (default-value 'tool-bar-mode)
-                (let ((load-path (mm-image-load-path)))
-                  (gmm-tool-bar-from-list gnus-group-tool-bar
-                                              gnus-group-tool-bar-zap-list
-                                              'gnus-group-mode-map)))))
+  (when (and (not (featurep 'xemacs))
+            (boundp 'tool-bar-mode)
+            tool-bar-mode
+            ;; The Gnus 5.10.6 code checked (default-value 'tool-bar-mode).
+            ;; Why?  --rsteib
+            (or (not gnus-group-tool-bar-map) force))
+    (let* ((load-path
+           (gmm-image-load-path-for-library "gnus"
+                                            "gnus/toggle-subscription.xpm"
+                                            nil t))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp 'image-load-path)
+                                    image-load-path)))
+          (map (gmm-tool-bar-from-list gnus-group-tool-bar
+                                       gnus-group-tool-bar-zap-list
+                                       'gnus-group-mode-map)))
       (if map
          (set (make-local-variable 'tool-bar-map) map))))
   gnus-group-tool-bar-map)
       (if map
          (set (make-local-variable 'tool-bar-map) map))))
   gnus-group-tool-bar-map)
@@ -1124,7 +1135,7 @@ When FORCE, rebuild the tool bar."
 
 All normal editing commands are switched off.
 \\<gnus-group-mode-map>
 
 All normal editing commands are switched off.
 \\<gnus-group-mode-map>
-The group buffer lists (some of) the groups available. For instance,
+The group buffer lists (some of) the groups available.  For instance,
 `\\[gnus-group-list-groups]' will list all subscribed groups with unread articles, while `\\[gnus-group-list-zombies]'
 lists all zombie groups.
 
 `\\[gnus-group-list-groups]' will list all subscribed groups with unread articles, while `\\[gnus-group-list-zombies]'
 lists all zombie groups.
 
@@ -1209,7 +1220,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
@@ -1489,6 +1503,36 @@ if it is a string, only list groups matching REGEXP."
                (gnus-range-difference (list active) (gnus-info-read info))
                seen))))))
 
                (gnus-range-difference (list active) (gnus-info-read info))
                seen))))))
 
+;; Moving through the Group buffer (in topic mode) e.g. with C-n doesn't
+;; update the state (enabled/disabled) of the icon `gnus-group-describe-group'
+;; automatically.  After `C-l' the state is correct.  See the following report
+;; on emacs-devel
+;; <http://thread.gmane.org/v9acdmrcse.fsf@marauder.physik.uni-ulm.de>:
+;; From: Reiner Steib
+;; Subject: tool bar icons not updated according to :active condition
+;; Newsgroups: gmane.emacs.devel
+;; Date: Mon, 23 Jan 2006 19:59:13 +0100
+;; Message-ID: <v9acdmrcse.fsf@marauder.physik.uni-ulm.de>
+
+(defcustom gnus-group-update-tool-bar
+  (and (not (featurep 'xemacs))
+       (boundp 'tool-bar-mode)
+       tool-bar-mode
+       ;; Using `redraw-frame' (see `gnus-tool-bar-update') in Emacs 21 might
+       ;; be confusing, so maybe we shouldn't call it by default.
+       (fboundp 'force-window-update))
+  "Force updating the group buffer tool bar."
+  :group 'gnus-group
+  :version "22.1"
+  :initialize 'custom-initialize-default
+  :set (lambda (symbol value)
+        (set-default symbol value)
+        (when (gnus-alive-p)
+          (with-current-buffer gnus-group-buffer
+            ;; FIXME: Is there a better way to redraw the group buffer?
+            (gnus-group-get-new-news 0))))
+  :type 'boolean)
+
 (defun gnus-group-insert-group-line (gnus-tmp-group gnus-tmp-level
                                                    gnus-tmp-marked number
                                                    gnus-tmp-method)
 (defun gnus-group-insert-group-line (gnus-tmp-group gnus-tmp-level
                                                    gnus-tmp-marked number
                                                    gnus-tmp-method)
@@ -1553,8 +1597,10 @@ if it is a string, only list groups matching REGEXP."
          (if (member gnus-tmp-group gnus-group-marked)
              gnus-process-mark ? ))
         (buffer-read-only nil)
          (if (member gnus-tmp-group gnus-group-marked)
              gnus-process-mark ? ))
         (buffer-read-only nil)
+        beg end
         header gnus-tmp-header)        ; passed as parameter to user-funcs.
     (beginning-of-line)
         header gnus-tmp-header)        ; passed as parameter to user-funcs.
     (beginning-of-line)
+    (setq beg (point))
     (gnus-add-text-properties
      (point)
      (prog1 (1+ (point))
     (gnus-add-text-properties
      (point)
      (prog1 (1+ (point))
@@ -1569,6 +1615,12 @@ if it is a string, only list groups matching REGEXP."
                  gnus-marked ,gnus-tmp-marked-mark
                  gnus-indentation ,gnus-group-indentation
                  gnus-level ,gnus-tmp-level))
                  gnus-marked ,gnus-tmp-marked-mark
                  gnus-indentation ,gnus-group-indentation
                  gnus-level ,gnus-tmp-level))
+    (setq end (point))
+    (when gnus-group-update-tool-bar
+      (gnus-put-text-property beg end 'point-entered
+                             'gnus-tool-bar-update)
+      (gnus-put-text-property beg end 'point-left
+                             'gnus-tool-bar-update))
     (forward-line -1)
     (when (inline (gnus-visual-p 'group-highlight 'highlight))
       (gnus-run-hooks 'gnus-group-update-hook))
     (forward-line -1)
     (when (inline (gnus-visual-p 'group-highlight 'highlight))
       (gnus-run-hooks 'gnus-group-update-hook))
@@ -1983,7 +2035,7 @@ and with point over the group in question."
 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
 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
+auto-selected upon group entry.  If GROUP is non-nil, fetch that
 group."
   (interactive "P")
   (let ((no-display (eq all 0))
 group."
   (interactive "P")
   (let ((no-display (eq all 0))
@@ -2024,11 +2076,11 @@ articles in the group."
     (forward-line -1))
   (gnus-group-read-group all t))
 
     (forward-line -1))
   (gnus-group-read-group all t))
 
-(defun gnus-group-quick-select-group (&optional all)
-  "Select the current group \"quickly\".
-This means that no highlighting or scoring will be performed.
-If ALL (the prefix argument) is 0, don't even generate the summary
-buffer.
+(defun gnus-group-quick-select-group (&optional all group)
+  "Select the GROUP \"quickly\".
+This means that no highlighting or scoring will be performed.  If
+ALL (the prefix argument) is 0, don't even generate the summary
+buffer.  If GROUP is nil, use current group.
 
 This might be useful if you want to toggle threading
 before entering the group."
 
 This might be useful if you want to toggle threading
 before entering the group."
@@ -2039,7 +2091,7 @@ before entering the group."
        gnus-home-score-file
        gnus-apply-kill-hook
        gnus-summary-expunge-below)
        gnus-home-score-file
        gnus-apply-kill-hook
        gnus-summary-expunge-below)
-    (gnus-group-read-group all t)))
+    (gnus-group-read-group all t group)))
 
 (defun gnus-group-visible-select-group (&optional all)
   "Select the current group without hiding any articles."
 
 (defun gnus-group-visible-select-group (&optional all)
   "Select the current group without hiding any articles."
@@ -2063,14 +2115,86 @@ 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 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 (group)
+    (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.
 ;;;###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."
 Returns whether the fetching was successful or not."
-  (interactive (list (completing-read "Group name: " gnus-active-hashtb)))
-  (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-no-server))
-  (gnus-group-read-group articles nil group))
+  (gnus-group-read-group (if articles nil t) nil group articles))
 
 ;;;###autoload
 (defun gnus-fetch-group-other-frame (group)
 
 ;;;###autoload
 (defun gnus-fetch-group-other-frame (group)
@@ -2128,10 +2252,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)
@@ -2183,17 +2304,14 @@ Return the name of the group if selection was successful."
 If PROMPT (the prefix) is a number, use the prompt specified in
 `gnus-group-jump-to-group-prompt'."
   (interactive
 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"))
@@ -2384,17 +2502,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: ")
@@ -2402,6 +2519,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)))
@@ -2692,15 +2813,18 @@ If called with a prefix argument, ask for the file type."
                          (t (setq err (format "%c unknown. " char))
                             nil))))
       (setq type found)))
                          (t (setq err (format "%c unknown. " char))
                             nil))))
       (setq type found)))
-  (let* ((file (expand-file-name file))
-        (name (gnus-generate-new-group-name
+  (setq file (expand-file-name file))
+  (let* ((name (gnus-generate-new-group-name
                (gnus-group-prefixed-name
                (gnus-group-prefixed-name
-                (file-name-nondirectory file) '(nndoc "")))))
+                (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
-     (gnus-group-real-name name)
-     (list 'nndoc 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)
@@ -2754,25 +2878,23 @@ 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
+                                             (or (cdr (assoc 'title
+                                                             feedinfo))
+                                                 "")))))
+              (desc  (read-from-minibuffer "Description: "
+                                           (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))))
@@ -2832,7 +2954,7 @@ Given a prefix, create a full group."
 (defun gnus-group-make-directory-group (dir)
   "Create an nndir group.
 The user will be prompted for a directory.  The contents of this
 (defun gnus-group-make-directory-group (dir)
   "Create an nndir group.
 The user will be prompted for a directory.  The contents of this
-directory will be used as a newsgroup. The directory should contain
+directory will be used as a newsgroup.  The directory should contain
 mail messages or news articles in files that have numeric names."
   (interactive
    (list (read-file-name "Create group from directory: ")))
 mail messages or news articles in files that have numeric names."
   (interactive
    (list (read-file-name "Create group from directory: ")))
@@ -3167,7 +3289,7 @@ sort in reverse order."
 (defun gnus-group-sort-by-unread (info1 info2)
   "Sort by number of unread articles."
   (let ((n1 (gnus-group-unread (gnus-info-group info1)))
 (defun gnus-group-sort-by-unread (info1 info2)
   "Sort by number of unread articles."
   (let ((n1 (gnus-group-unread (gnus-info-group info1)))
-       (n2 (gnus-group-unread (gnus-info-group info1))))
+       (n2 (gnus-group-unread (gnus-info-group info2))))
     (< (or (and (numberp n1) n1) 0)
        (or (and (numberp n2) n2) 0))))
 
     (< (or (and (numberp n1) n1) 0)
        (or (and (numberp n2) n2) 0))))
 
@@ -3287,13 +3409,15 @@ up is returned."
          (when (eq 'nnvirtual (car method))
            (nnvirtual-catchup-group
             (gnus-group-real-name group) (nth 1 method) all)))
          (when (eq 'nnvirtual (car method))
            (nnvirtual-catchup-group
             (gnus-group-real-name group) (nth 1 method) all)))
-       (if (>= (gnus-group-level group) gnus-level-zombie)
-           (gnus-message 2 "Dead groups can't be caught up")
-         (if (prog1
-                 (gnus-group-goto-group group)
-               (gnus-group-catchup group all))
-             (gnus-group-update-group-line)
-           (setq ret (1+ ret)))))
+       (cond
+        ((>= (gnus-group-level group) gnus-level-zombie)
+         (gnus-message 2 "Dead groups can't be caught up"))
+        ((prog1
+             (gnus-group-goto-group group)
+           (gnus-group-catchup group all))
+         (gnus-group-update-group-line))
+        (t
+         (setq ret (1+ ret)))))
       (gnus-group-next-unread-group 1)
       ret)))
 
       (gnus-group-next-unread-group 1)
       ret)))
 
@@ -3331,10 +3455,12 @@ or nil if no action could be taken."
        (gnus-add-marked-articles group 'dormant nil nil 'force))
       ;; Do auto-expirable marks if that's required.
       (when (gnus-group-auto-expirable-p group)
        (gnus-add-marked-articles group 'dormant nil nil 'force))
       ;; Do auto-expirable marks if that's required.
       (when (gnus-group-auto-expirable-p group)
-        (gnus-range-map (lambda (article)
-                          (gnus-add-marked-articles group 'expire (list article))
-                          (gnus-request-set-mark group (list (list (list article) 'add '(expire)))))
-                        unread))
+        (gnus-range-map
+        (lambda (article)
+          (gnus-add-marked-articles group 'expire (list article))
+          (gnus-request-set-mark group (list (list (list article)
+                                                   'add '(expire)))))
+        unread))
       (let ((gnus-newsgroup-name group))
        (gnus-run-hooks 'gnus-group-catchup-group-hook))
       num)))
       (let ((gnus-newsgroup-name group))
        (gnus-run-hooks 'gnus-group-catchup-group-hook))
       num)))
@@ -3462,12 +3588,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)
@@ -3500,7 +3622,7 @@ group line."
 
 (defun gnus-group-transpose-groups (n)
   "Move the current newsgroup up N places.
 
 (defun gnus-group-transpose-groups (n)
   "Move the current newsgroup up N places.
-If given a negative prefix, move down instead. The difference between
+If given a negative prefix, move down instead.  The difference between
 N and the number of steps taken is returned."
   (interactive "p")
   (unless (gnus-group-group-name)
 N and the number of steps taken is returned."
   (interactive "p")
   (unless (gnus-group-group-name)
@@ -3751,7 +3873,10 @@ re-scanning.  If ARG is non-nil and not a number, this will force
 
     ;; We might read in new NoCeM messages here.
     (when (and gnus-use-nocem
 
     ;; We might read in new NoCeM messages here.
     (when (and gnus-use-nocem
-              (null arg))
+              (or (and (numberp gnus-use-nocem)
+                       (numberp arg)
+                       (>= 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)))
       (gnus-nocem-scan-groups))
     ;; If ARG is not a number, then we read the active file.
     (when (and arg (not (numberp arg)))
@@ -3851,7 +3976,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
@@ -3879,7 +4004,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
@@ -4105,12 +4230,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
@@ -4210,7 +4335,7 @@ and the second element is the address."
        (unless entry
          (error "Trying to change non-existent group %s" method-only-group))
        ;; We have received parts of the actual group info - either the
        (unless entry
          (error "Trying to change non-existent group %s" method-only-group))
        ;; We have received parts of the actual group info - either the
-       ;; select method or the group parameters.        We first check
+       ;; select method or the group parameters.  We first check
        ;; whether we have to extend the info, and if so, do that.
        (let ((len (length info))
              (total (if (eq part 'method) 5 6)))
        ;; whether we have to extend the info, and if so, do that.
        (let ((len (length info))
              (total (if (eq part 'method) 5 6)))
@@ -4235,9 +4360,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