190c020b3f2c96814e8bd7eba4d1adefdf7d11fc
[gnus] / lisp / gnus-group.el
1 ;;; gnus-group.el --- group mode commands for Gnus
2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
3 ;;        Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Keywords: news
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 (eval-when-compile (require 'cl))
30
31 (require 'gnus)
32 (require 'gnus-start)
33 (require 'nnmail)
34 (require 'gnus-spec)
35 (require 'gnus-int)
36 (require 'gnus-range)
37 (require 'gnus-win)
38 (require 'gnus-undo)
39 (require 'time-date)
40 (require 'gnus-ems)
41
42 (defcustom gnus-group-archive-directory
43   "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
44   "*The address of the (ding) archives."
45   :group 'gnus-group-foreign
46   :type 'directory)
47
48 (defcustom gnus-group-recent-archive-directory
49   "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
50   "*The address of the most recent (ding) articles."
51   :group 'gnus-group-foreign
52   :type 'directory)
53
54 (defcustom gnus-no-groups-message "No gnus is bad news"
55   "*Message displayed by Gnus when no groups are available."
56   :group 'gnus-start
57   :type 'string)
58
59 (defcustom gnus-keep-same-level nil
60   "*Non-nil means that the next newsgroup after the current will be on the same level.
61 When you type, for instance, `n' after reading the last article in the
62 current newsgroup, you will go to the next newsgroup.  If this variable
63 is nil, the next newsgroup will be the next from the group
64 buffer.
65 If this variable is non-nil, Gnus will either put you in the
66 next newsgroup with the same level, or, if no such newsgroup is
67 available, the next newsgroup with the lowest possible level higher
68 than the current level.
69 If this variable is `best', Gnus will make the next newsgroup the one
70 with the best level."
71   :group 'gnus-group-levels
72   :type '(choice (const nil)
73                  (const best)
74                  (sexp :tag "other" t)))
75
76 (defcustom gnus-group-goto-unread t
77   "*If non-nil, movement commands will go to the next unread and subscribed group."
78   :link '(custom-manual "(gnus)Group Maneuvering")
79   :group 'gnus-group-various
80   :type 'boolean)
81
82 (defcustom gnus-goto-next-group-when-activating t
83   "*If non-nil, the \\<gnus-group-mode-map>\\[gnus-group-get-new-news-this-group] command will advance point to the next group."
84   :link '(custom-manual "(gnus)Scanning New Messages")
85   :group 'gnus-group-various
86   :type 'boolean)
87
88 (defcustom gnus-permanently-visible-groups nil
89   "*Regexp to match groups that should always be listed in the group buffer.
90 This means that they will still be listed even when there are no
91 unread articles in the groups.
92
93 If nil, no groups are permanently visible."
94   :group 'gnus-group-listing
95   :type '(choice regexp (const nil)))
96
97 (defcustom gnus-list-groups-with-ticked-articles t
98   "*If non-nil, list groups that have only ticked articles.
99 If nil, only list groups that have unread articles."
100   :group 'gnus-group-listing
101   :type 'boolean)
102
103 (defcustom gnus-group-default-list-level gnus-level-subscribed
104   "*Default listing level.
105 Ignored if `gnus-group-use-permanent-levels' is non-nil."
106   :group 'gnus-group-listing
107   :type 'integer)
108
109 (defcustom gnus-group-list-inactive-groups t
110   "*If non-nil, inactive groups will be listed."
111   :group 'gnus-group-listing
112   :group 'gnus-group-levels
113   :type 'boolean)
114
115 (defcustom gnus-group-sort-function 'gnus-group-sort-by-alphabet
116   "*Function used for sorting the group buffer.
117 This function will be called with group info entries as the arguments
118 for the groups to be sorted.  Pre-made functions include
119 `gnus-group-sort-by-alphabet', `gnus-group-sort-by-real-name',
120 `gnus-group-sort-by-unread', `gnus-group-sort-by-level',
121 `gnus-group-sort-by-score', `gnus-group-sort-by-method',
122 `gnus-group-sort-by-server', and `gnus-group-sort-by-rank'.
123
124 This variable can also be a list of sorting functions.  In that case,
125 the most significant sort function should be the last function in the
126 list."
127   :group 'gnus-group-listing
128   :link '(custom-manual "(gnus)Sorting Groups")
129   :type '(repeat :value-to-internal (lambda (widget value)
130                                       (if (listp value) value (list value)))
131                  :match (lambda (widget value)
132                           (or (symbolp value)
133                               (widget-editable-list-match widget value)))
134                  (choice (function-item gnus-group-sort-by-alphabet)
135                          (function-item gnus-group-sort-by-real-name)
136                          (function-item gnus-group-sort-by-unread)
137                          (function-item gnus-group-sort-by-level)
138                          (function-item gnus-group-sort-by-score)
139                          (function-item gnus-group-sort-by-method)
140                          (function-item gnus-group-sort-by-server)
141                          (function-item gnus-group-sort-by-rank)
142                          (function :tag "other" nil))))
143
144 (defcustom gnus-group-line-format "%M\%S\%p\%P\%5y: %(%g%)%l\n"
145   "*Format of group lines.
146 It works along the same lines as a normal formatting string,
147 with some simple extensions.
148
149 %M    Only marked articles (character, \"*\" or \" \")
150 %S    Whether the group is subscribed (character, \"U\", \"K\", \"Z\" or \" \")
151 %L    Level of subscribedness (integer)
152 %N    Number of unread articles (integer)
153 %I    Number of dormant articles (integer)
154 %i    Number of ticked and dormant (integer)
155 %T    Number of ticked articles (integer)
156 %R    Number of read articles (integer)
157 %t    Estimated total number of articles (integer)
158 %y    Number of unread, unticked articles (integer)
159 %G    Group name (string)
160 %g    Qualified group name (string)
161 %c    Short (collapsed) group name.  See `gnus-group-uncollapsed-levels'.
162 %D    Group description (string)
163 %s    Select method (string)
164 %o    Moderated group (char, \"m\")
165 %p    Process mark (char)
166 %O    Moderated group (string, \"(m)\" or \"\")
167 %P    Topic indentation (string)
168 %m    Whether there is new(ish) mail in the group (char, \"%\")
169 %l    Whether there are GroupLens predictions for this group (string)
170 %n    Select from where (string)
171 %z    A string that look like `<%s:%n>' if a foreign select method is used
172 %d    The date the group was last entered.
173 %E    Icon as defined by `gnus-group-icon-list'.
174 %u    User defined specifier.  The next character in the format string should
175       be a letter.  Gnus will call the function gnus-user-format-function-X,
176       where X is the letter following %u.  The function will be passed the
177       current header as argument.  The function should return a string, which
178       will be inserted into the buffer just like information from any other
179       group specifier.
180
181 Text between %( and %) will be highlighted with `gnus-mouse-face' when
182 the mouse point move inside the area.  There can only be one such area.
183
184 Note that this format specification is not always respected.  For
185 reasons of efficiency, when listing killed groups, this specification
186 is ignored altogether.  If the spec is changed considerably, your
187 output may end up looking strange when listing both alive and killed
188 groups.
189
190 If you use %o or %O, reading the active file will be slower and quite
191 a bit of extra memory will be used.  %D will also worsen performance.
192 Also note that if you change the format specification to include any
193 of these specs, you must probably re-start Gnus to see them go into
194 effect."
195   :group 'gnus-group-visual
196   :type 'string)
197
198 (defcustom gnus-group-mode-line-format "Gnus: %%b {%M\%:%S}"
199   "*The format specification for the group mode line.
200 It works along the same lines as a normal formatting string,
201 with some simple extensions:
202
203 %S   The native news server.
204 %M   The native select method.
205 %:   \":\" if %S isn't \"\"."
206   :group 'gnus-group-visual
207   :type 'string)
208
209 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
210 (when (featurep 'xemacs)
211   (add-hook 'gnus-group-mode-hook 'gnus-xmas-group-menu-add)
212   (add-hook 'gnus-group-mode-hook 'gnus-xmas-setup-group-toolbar))
213
214 (defcustom gnus-group-menu-hook nil
215   "Hook run after the creation of the group mode menu."
216   :group 'gnus-group-various
217   :type 'hook)
218
219 (defcustom gnus-group-catchup-group-hook nil
220   "Hook run when catching up a group from the group buffer."
221   :group 'gnus-group-various
222   :link '(custom-manual "(gnus)Group Data")
223   :type 'hook)
224
225 (defcustom gnus-group-update-group-hook nil
226   "Hook called when updating group lines."
227   :group 'gnus-group-visual
228   :type 'hook)
229
230 (defcustom gnus-group-prepare-function 'gnus-group-prepare-flat
231   "*A function that is called to generate the group buffer.
232 The function is called with three arguments: The first is a number;
233 all group with a level less or equal to that number should be listed,
234 if the second is non-nil, empty groups should also be displayed.  If
235 the third is non-nil, it is a number.  No groups with a level lower
236 than this number should be displayed.
237
238 The only current function implemented is `gnus-group-prepare-flat'."
239   :group 'gnus-group-listing
240   :type 'function)
241
242 (defcustom gnus-group-prepare-hook nil
243   "Hook called after the group buffer has been generated.
244 If you want to modify the group buffer, you can use this hook."
245   :group 'gnus-group-listing
246   :type 'hook)
247
248 (defcustom gnus-suspend-gnus-hook nil
249   "Hook called when suspending (not exiting) Gnus."
250   :group 'gnus-exit
251   :type 'hook)
252
253 (defcustom gnus-exit-gnus-hook nil
254   "Hook called when exiting Gnus."
255   :group 'gnus-exit
256   :type 'hook)
257
258 (defcustom gnus-after-exiting-gnus-hook nil
259   "Hook called after exiting Gnus."
260   :group 'gnus-exit
261   :type 'hook)
262
263 (defcustom gnus-group-update-hook '(gnus-group-highlight-line)
264   "Hook called when a group line is changed.
265 The hook will not be called if `gnus-visual' is nil.
266
267 The default function `gnus-group-highlight-line' will
268 highlight the line according to the `gnus-group-highlight'
269 variable."
270   :group 'gnus-group-visual
271   :type 'hook)
272
273 (defcustom gnus-useful-groups
274   '(("(ding) mailing list mirrored at sunsite.auc.dk"
275      "emacs.ding"
276      (nntp "sunsite.auc.dk"
277            (nntp-address "sunsite.auc.dk")))
278     ("gnus-bug archive"
279      "gnus-bug"
280      (nndir "/ftp@ftp.ifi.uio.no:/pub/emacs/gnus/gnus-bug/"))
281     ("Gnus help group"
282      "gnus-help"
283      (nndoc "gnus-help"
284             (nndoc-article-type mbox)
285             (eval `(nndoc-address
286                     ,(let ((file (nnheader-find-etc-directory
287                                   "gnus-tut.txt" t)))
288                        (unless file
289                          (error "Couldn't find doc group"))
290                        file))))))
291   "*Alist of useful group-server pairs."
292   :group 'gnus-group-listing
293   :type '(repeat (list (string :tag "Description")
294                        (string :tag "Name")
295                        (sexp :tag "Method"))))
296
297 (defcustom gnus-group-highlight
298   '(;; Mail.
299     ((and mailp (= unread 0) (eq level 1)) .
300      gnus-group-mail-1-empty-face)
301     ((and mailp (eq level 1)) .
302      gnus-group-mail-1-face)
303     ((and mailp (= unread 0) (eq level 2)) .
304      gnus-group-mail-2-empty-face)
305     ((and mailp (eq level 2)) .
306      gnus-group-mail-2-face)
307     ((and mailp (= unread 0) (eq level 3)) .
308      gnus-group-mail-3-empty-face)
309     ((and mailp (eq level 3)) .
310      gnus-group-mail-3-face)
311     ((and mailp (= unread 0)) .
312      gnus-group-mail-low-empty-face)
313     ((and mailp) .
314      gnus-group-mail-low-face)
315     ;; News.
316     ((and (= unread 0) (eq level 1)) .
317      gnus-group-news-1-empty-face)
318     ((and (eq level 1)) .
319      gnus-group-news-1-face)
320     ((and (= unread 0) (eq level 2)) .
321      gnus-group-news-2-empty-face)
322     ((and (eq level 2)) .
323      gnus-group-news-2-face)
324     ((and (= unread 0) (eq level 3)) .
325      gnus-group-news-3-empty-face)
326     ((and (eq level 3)) .
327      gnus-group-news-3-face)
328     ((and (= unread 0) (eq level 4)) .
329      gnus-group-news-4-empty-face)
330     ((and (eq level 4)) .
331      gnus-group-news-4-face)
332     ((and (= unread 0) (eq level 5)) .
333      gnus-group-news-5-empty-face)
334     ((and (eq level 5)) .
335      gnus-group-news-5-face)
336     ((and (= unread 0) (eq level 6)) .
337      gnus-group-news-6-empty-face)
338     ((and (eq level 6)) .
339      gnus-group-news-6-face)
340     ((and (= unread 0)) .
341      gnus-group-news-low-empty-face)
342     (t .
343      gnus-group-news-low-face))
344   "*Controls the highlighting of group buffer lines.
345
346 Below is a list of `Form'/`Face' pairs.  When deciding how a a
347 particular group line should be displayed, each form is
348 evaluated.  The content of the face field after the first true form is
349 used.  You can change how those group lines are displayed by
350 editing the face field.
351
352 It is also possible to change and add form fields, but currently that
353 requires an understanding of Lisp expressions.  Hopefully this will
354 change in a future release.  For now, you can use the following
355 variables in the Lisp expression:
356
357 group: The name of the group.
358 unread: The number of unread articles in the group.
359 method: The select method used.
360 mailp: Whether it's a mail group or not.
361 level: The level of the group.
362 score: The score of the group.
363 ticked: The number of ticked articles."
364   :group 'gnus-group-visual
365   :type '(repeat (cons (sexp :tag "Form") face)))
366
367 (defcustom gnus-new-mail-mark ?%
368   "Mark used for groups with new mail."
369   :group 'gnus-group-visual
370   :type 'character)
371
372 (defgroup gnus-group-icons nil
373   "Add Icons to your group buffer.  "
374   :group 'gnus-group-visual)
375
376 (defcustom gnus-group-icon-list
377   nil
378   "*Controls the insertion of icons into group buffer lines.
379
380 Below is a list of `Form'/`File' pairs.  When deciding how a
381 particular group line should be displayed, each form is evaluated.
382 The icon from the file field after the first true form is used.  You
383 can change how those group lines are displayed by editing the file
384 field.  The File will either be found in the
385 `gnus-group-glyph-directory' or by designating absolute path to the
386 file.
387
388 It is also possible to change and add form fields, but currently that
389 requires an understanding of Lisp expressions.  Hopefully this will
390 change in a future release.  For now, you can use the following
391 variables in the Lisp expression:
392
393 group: The name of the group.
394 unread: The number of unread articles in the group.
395 method: The select method used.
396 mailp: Whether it's a mail group or not.
397 newsp: Whether it's a news group or not
398 level: The level of the group.
399 score: The score of the group.
400 ticked: The number of ticked articles."
401   :group 'gnus-group-icons
402   :type '(repeat (cons (sexp :tag "Form") file)))
403
404 (defcustom gnus-group-name-charset-method-alist nil
405   "Alist of method and the charset for group names.
406
407 For example:
408     (((nntp \"news.com.cn\") . cn-gb-2312))"
409   :version "21.1"
410   :group 'gnus-charset
411   :type '(repeat (cons (sexp :tag "Method") (symbol :tag "Charset"))))
412
413 (defcustom gnus-group-name-charset-group-alist
414   (if (or (and (fboundp 'find-coding-system) (find-coding-system 'utf-8))
415          (and (fboundp 'coding-system-p) (coding-system-p 'utf-8)))
416       '((".*" . utf-8))
417     nil)
418   "Alist of group regexp and the charset for group names.
419
420 For example:
421     ((\"\\.com\\.cn:\" . cn-gb-2312))"
422   :group 'gnus-charset
423   :type '(repeat (cons (regexp :tag "Group") (symbol :tag "Charset"))))
424
425 (defcustom gnus-group-jump-to-group-prompt nil
426   "Default prompt for `gnus-group-jump-to-group'.
427 If non-nil, the value should be a string, e.g. \"nnml:\",
428 in which case `gnus-group-jump-to-group' offers \"Group: nnml:\"
429 in the minibuffer prompt."
430   :group 'gnus-group-various
431   :type '(choice (string :tag "Prompt string")
432                  (const :tag "Empty" nil)))
433
434 (defvar gnus-group-listing-limit 1000
435   "*A limit of the number of groups when listing.
436 If the number of groups is larger than the limit, list them in a
437 simple manner.")
438
439 ;;; Internal variables
440
441 (defvar gnus-group-sort-alist-function 'gnus-group-sort-flat
442   "Function for sorting the group buffer.")
443
444 (defvar gnus-group-sort-selected-function 'gnus-group-sort-selected-flat
445   "Function for sorting the selected groups in the group buffer.")
446
447 (defvar gnus-group-indentation-function nil)
448 (defvar gnus-goto-missing-group-function nil)
449 (defvar gnus-group-update-group-function nil)
450 (defvar gnus-group-goto-next-group-function nil
451   "Function to override finding the next group after listing groups.")
452
453 (defvar gnus-group-edit-buffer nil)
454
455 (defvar gnus-group-line-format-alist
456   `((?M gnus-tmp-marked-mark ?c)
457     (?S gnus-tmp-subscribed ?c)
458     (?L gnus-tmp-level ?d)
459     (?N (cond ((eq number t) "*" )
460               ((numberp number)
461                (int-to-string
462                 (+ number
463                    (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
464                    (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))))
465               (t number)) ?s)
466     (?R gnus-tmp-number-of-read ?s)
467     (?t gnus-tmp-number-total ?d)
468     (?y gnus-tmp-number-of-unread ?s)
469     (?I (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
470     (?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
471     (?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
472            (gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d)
473     (?g gnus-tmp-group ?s)
474     (?G gnus-tmp-qualified-group ?s)
475     (?c (gnus-short-group-name gnus-tmp-group) ?s)
476     (?D gnus-tmp-newsgroup-description ?s)
477     (?o gnus-tmp-moderated ?c)
478     (?O gnus-tmp-moderated-string ?s)
479     (?p gnus-tmp-process-marked ?c)
480     (?s gnus-tmp-news-server ?s)
481     (?n gnus-tmp-news-method ?s)
482     (?P gnus-group-indentation ?s)
483     (?E gnus-tmp-group-icon ?s)
484     (?l gnus-tmp-grouplens ?s)
485     (?z gnus-tmp-news-method-string ?s)
486     (?m (gnus-group-new-mail gnus-tmp-group) ?c)
487     (?d (gnus-group-timestamp-string gnus-tmp-group) ?s)
488     (?u gnus-tmp-user-defined ?s)))
489
490 (defvar gnus-group-mode-line-format-alist
491   `((?S gnus-tmp-news-server ?s)
492     (?M gnus-tmp-news-method ?s)
493     (?u gnus-tmp-user-defined ?s)
494     (?: gnus-tmp-colon ?s)))
495
496 (defvar gnus-topic-topology nil
497   "The complete topic hierarchy.")
498
499 (defvar gnus-topic-alist nil
500   "The complete topic-group alist.")
501
502 (defvar gnus-group-marked nil)
503
504 (defvar gnus-group-list-mode nil)
505
506
507 (defvar gnus-group-icon-cache nil)
508
509 (defvar gnus-group-listed-groups nil)
510 (defvar gnus-group-list-option nil)
511
512 ;;;
513 ;;; Gnus group mode
514 ;;;
515
516 (put 'gnus-group-mode 'mode-class 'special)
517
518 (when t
519   (gnus-define-keys gnus-group-mode-map
520     " " gnus-group-read-group
521     "=" gnus-group-select-group
522     "\r" gnus-group-select-group
523     "\M-\r" gnus-group-quick-select-group
524     "\M- " gnus-group-visible-select-group
525     [(meta control return)] gnus-group-select-group-ephemerally
526     "j" gnus-group-jump-to-group
527     "n" gnus-group-next-unread-group
528     "p" gnus-group-prev-unread-group
529     "\177" gnus-group-prev-unread-group
530     [delete] gnus-group-prev-unread-group
531     [backspace] gnus-group-prev-unread-group
532     "N" gnus-group-next-group
533     "P" gnus-group-prev-group
534     "\M-n" gnus-group-next-unread-group-same-level
535     "\M-p" gnus-group-prev-unread-group-same-level
536     "," gnus-group-best-unread-group
537     "." gnus-group-first-unread-group
538     "u" gnus-group-unsubscribe-current-group
539     "U" gnus-group-unsubscribe-group
540     "c" gnus-group-catchup-current
541     "C" gnus-group-catchup-current-all
542     "\M-c" gnus-group-clear-data
543     "l" gnus-group-list-groups
544     "L" gnus-group-list-all-groups
545     "m" gnus-group-mail
546     "g" gnus-group-get-new-news
547     "\M-g" gnus-group-get-new-news-this-group
548     "R" gnus-group-restart
549     "r" gnus-group-read-init-file
550     "B" gnus-group-browse-foreign-server
551     "b" gnus-group-check-bogus-groups
552     "F" gnus-group-find-new-groups
553     "\C-c\C-d" gnus-group-describe-group
554     "\M-d" gnus-group-describe-all-groups
555     "\C-c\C-a" gnus-group-apropos
556     "\C-c\M-\C-a" gnus-group-description-apropos
557     "a" gnus-group-post-news
558     "\ek" gnus-group-edit-local-kill
559     "\eK" gnus-group-edit-global-kill
560     "\C-k" gnus-group-kill-group
561     "\C-y" gnus-group-yank-group
562     "\C-w" gnus-group-kill-region
563     "\C-x\C-t" gnus-group-transpose-groups
564     "\C-c\C-l" gnus-group-list-killed
565     "\C-c\C-x" gnus-group-expire-articles
566     "\C-c\M-\C-x" gnus-group-expire-all-groups
567     "V" gnus-version
568     "s" gnus-group-save-newsrc
569     "z" gnus-group-suspend
570     "q" gnus-group-exit
571     "Q" gnus-group-quit
572     "?" gnus-group-describe-briefly
573     "\C-c\C-i" gnus-info-find-node
574     "\M-e" gnus-group-edit-group-method
575     "^" gnus-group-enter-server-mode
576     gnus-mouse-2 gnus-mouse-pick-group
577     "<" beginning-of-buffer
578     ">" end-of-buffer
579     "\C-c\C-b" gnus-bug
580     "\C-c\C-s" gnus-group-sort-groups
581     "t" gnus-topic-mode
582     "\C-c\M-g" gnus-activate-all-groups
583     "\M-&" gnus-group-universal-argument
584     "#" gnus-group-mark-group
585     "\M-#" gnus-group-unmark-group)
586
587   (gnus-define-keys (gnus-group-mark-map "M" gnus-group-mode-map)
588     "m" gnus-group-mark-group
589     "u" gnus-group-unmark-group
590     "w" gnus-group-mark-region
591     "b" gnus-group-mark-buffer
592     "r" gnus-group-mark-regexp
593     "U" gnus-group-unmark-all-groups)
594
595   (gnus-define-keys (gnus-group-sieve-map "D" gnus-group-mode-map)
596     "u" gnus-sieve-update
597     "g" gnus-sieve-generate)
598
599   (gnus-define-keys (gnus-group-group-map "G" gnus-group-mode-map)
600     "d" gnus-group-make-directory-group
601     "h" gnus-group-make-help-group
602     "u" gnus-group-make-useful-group
603     "a" gnus-group-make-archive-group
604     "k" gnus-group-make-kiboze-group
605     "l" gnus-group-nnimap-edit-acl
606     "m" gnus-group-make-group
607     "E" gnus-group-edit-group
608     "e" gnus-group-edit-group-method
609     "p" gnus-group-edit-group-parameters
610     "v" gnus-group-add-to-virtual
611     "V" gnus-group-make-empty-virtual
612     "D" gnus-group-enter-directory
613     "f" gnus-group-make-doc-group
614     "w" gnus-group-make-web-group
615     "r" gnus-group-rename-group
616     "c" gnus-group-customize
617     "x" gnus-group-nnimap-expunge
618     "\177" gnus-group-delete-group
619     [delete] gnus-group-delete-group)
620
621   (gnus-define-keys (gnus-group-soup-map "s" gnus-group-group-map)
622     "b" gnus-group-brew-soup
623     "w" gnus-soup-save-areas
624     "s" gnus-soup-send-replies
625     "p" gnus-soup-pack-packet
626     "r" nnsoup-pack-replies)
627
628   (gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
629     "s" gnus-group-sort-groups
630     "a" gnus-group-sort-groups-by-alphabet
631     "u" gnus-group-sort-groups-by-unread
632     "l" gnus-group-sort-groups-by-level
633     "v" gnus-group-sort-groups-by-score
634     "r" gnus-group-sort-groups-by-rank
635     "m" gnus-group-sort-groups-by-method)
636
637   (gnus-define-keys (gnus-group-sort-selected-map "P" gnus-group-group-map)
638     "s" gnus-group-sort-selected-groups
639     "a" gnus-group-sort-selected-groups-by-alphabet
640     "u" gnus-group-sort-selected-groups-by-unread
641     "l" gnus-group-sort-selected-groups-by-level
642     "v" gnus-group-sort-selected-groups-by-score
643     "r" gnus-group-sort-selected-groups-by-rank
644     "m" gnus-group-sort-selected-groups-by-method)