Fix.
[elisp/gnus.git-] / lisp / gnus-salt.el
index af6d285..3727a4f 100644 (file)
@@ -1,5 +1,7 @@
 ;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
 ;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
-;; Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2001
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 
 (require 'gnus)
 (require 'gnus-sum)
 
 (require 'gnus)
 (require 'gnus-sum)
+(require 'gnus-win)
 
 ;;;
 ;;; gnus-pick-mode
 ;;;
 
 (defvar gnus-pick-mode nil
 
 ;;;
 ;;; gnus-pick-mode
 ;;;
 
 (defvar gnus-pick-mode nil
-  "Minor mode for providing a pick-and-read interface in Gnus summary buffers.")
+  "Minor mode for providing a pick-and-read interface in Gnus
+summary buffers.")
 
 (defcustom gnus-pick-display-summary nil
   "*Display summary while reading."
 
 (defcustom gnus-pick-display-summary nil
   "*Display summary while reading."
   :type 'hook
   :group 'gnus-summary-pick)
 
   :type 'hook
   :group 'gnus-summary-pick)
 
+(when (featurep 'xemacs)
+  (add-hook 'gnus-pick-mode-hook 'gnus-xmas-pick-menu-add))
+
 (defcustom gnus-mark-unpicked-articles-as-read nil
   "*If non-nil, mark all unpicked articles as read."
   :type 'boolean
   :group 'gnus-summary-pick)
 
 (defcustom gnus-pick-elegant-flow t
 (defcustom gnus-mark-unpicked-articles-as-read nil
   "*If non-nil, mark all unpicked articles as read."
   :type 'boolean
   :group 'gnus-summary-pick)
 
 (defcustom gnus-pick-elegant-flow t
-  "If non-nil, gnus-pick-start-reading will run gnus-summary-next-group when no articles have been picked."
+  "If non-nil, `gnus-pick-start-reading' runs
+ `gnus-summary-next-group' when no articles have been picked."
   :type 'boolean
   :group 'gnus-summary-pick)
 
 (defcustom gnus-summary-pick-line-format
   :type 'boolean
   :group 'gnus-summary-pick)
 
 (defcustom gnus-summary-pick-line-format
-  "%-5P %U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
+  "%-5P %U\%R\%z\%I\%(%[%4L: %-23,23n%]%) %s\n"
   "*The format specification of the lines in pick buffers.
 It accepts the same format specs that `gnus-summary-line-format' does."
   :type 'string
   "*The format specification of the lines in pick buffers.
 It accepts the same format specs that `gnus-summary-line-format' does."
   :type 'string
@@ -76,8 +84,7 @@ It accepts the same format specs that `gnus-summary-line-format' does."
     "u" gnus-pick-unmark-article-or-thread
     "." gnus-pick-article-or-thread
     gnus-down-mouse-2 gnus-pick-mouse-pick-region
     "u" gnus-pick-unmark-article-or-thread
     "." gnus-pick-article-or-thread
     gnus-down-mouse-2 gnus-pick-mouse-pick-region
-    "\r" gnus-pick-start-reading
-    ))
+    "\r" gnus-pick-start-reading))
 
 (defun gnus-pick-make-menu-bar ()
   (unless (boundp 'gnus-pick-menu)
 
 (defun gnus-pick-make-menu-bar ()
   (unless (boundp 'gnus-pick-menu)
@@ -121,7 +128,8 @@ It accepts the same format specs that `gnus-summary-line-format' does."
       ;; Set up the menu.
       (when (gnus-visual-p 'pick-menu 'menu)
        (gnus-pick-make-menu-bar))
       ;; Set up the menu.
       (when (gnus-visual-p 'pick-menu 'menu)
        (gnus-pick-make-menu-bar))
-      (gnus-add-minor-mode 'gnus-pick-mode " Pick" gnus-pick-mode-map)
+      (gnus-add-minor-mode 'gnus-pick-mode " Pick" gnus-pick-mode-map
+                          nil 'gnus-pick-mode)
       (gnus-run-hooks 'gnus-pick-mode-hook))))
 
 (defun gnus-pick-setup-message ()
       (gnus-run-hooks 'gnus-pick-mode-hook))))
 
 (defun gnus-pick-setup-message ()
@@ -147,11 +155,11 @@ If given a prefix, mark all unpicked articles as read."
   (interactive "P")
   (if gnus-newsgroup-processable
       (progn
   (interactive "P")
   (if gnus-newsgroup-processable
       (progn
-        (gnus-summary-limit-to-articles nil)
-        (when (or catch-up gnus-mark-unpicked-articles-as-read)
+       (gnus-summary-limit-to-articles nil)
+       (when (or catch-up gnus-mark-unpicked-articles-as-read)
          (gnus-summary-limit-mark-excluded-as-read))
          (gnus-summary-limit-mark-excluded-as-read))
-        (gnus-summary-first-article)
-        (gnus-configure-windows
+       (gnus-summary-first-article)
+       (gnus-configure-windows
         (if gnus-pick-display-summary 'article 'pick) t))
     (if gnus-pick-elegant-flow
        (progn
         (if gnus-pick-display-summary 'article 'pick) t))
     (if gnus-pick-elegant-flow
        (progn
@@ -163,8 +171,8 @@ If given a prefix, mark all unpicked articles as read."
       (error "No articles have been picked"))))
 
 (defun gnus-pick-goto-article (arg)
       (error "No articles have been picked"))))
 
 (defun gnus-pick-goto-article (arg)
-  "Go to the article number indicated by ARG.  If ARG is an invalid
-article number, then stay on current line."
+  "Go to the article number indicated by ARG.
+If ARG is an invalid article number, then stay on current line."
   (let (pos)
     (save-excursion
       (goto-char (point-min))
   (let (pos)
     (save-excursion
       (goto-char (point-min))
@@ -175,7 +183,7 @@ article number, then stay on current line."
       (goto-char pos))))
 
 (defun gnus-pick-article (&optional arg)
       (goto-char pos))))
 
 (defun gnus-pick-article (&optional arg)
-    "Pick the article on the current line.
+  "Pick the article on the current line.
 If ARG, pick the article on that line instead."
   (interactive "P")
   (when arg
 If ARG, pick the article on that line instead."
   (interactive "P")
   (when arg
@@ -183,25 +191,29 @@ If ARG, pick the article on that line instead."
   (gnus-summary-mark-as-processable 1))
 
 (defun gnus-pick-article-or-thread (&optional arg)
   (gnus-summary-mark-as-processable 1))
 
 (defun gnus-pick-article-or-thread (&optional arg)
-  "If gnus-thread-hide-subtree is t, then pick the thread on the current line.
+  "If `gnus-thread-hide-subtree' is t, then pick the thread on the current line.
 Otherwise pick the article on the current line.
 If ARG, pick the article/thread on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
 Otherwise pick the article on the current line.
 If ARG, pick the article/thread on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
-      (gnus-uu-mark-thread)
+      (progn
+       (save-excursion
+         (gnus-uu-mark-thread))
+       (forward-line 1))
     (gnus-summary-mark-as-processable 1)))
 
 (defun gnus-pick-unmark-article-or-thread (&optional arg)
     (gnus-summary-mark-as-processable 1)))
 
 (defun gnus-pick-unmark-article-or-thread (&optional arg)
-  "If gnus-thread-hide-subtree is t, then unmark the thread on current line.
+  "If `gnus-thread-hide-subtree' is t, then unmark the thread on current line.
 Otherwise unmark the article on current line.
 If ARG, unmark thread/article on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
 Otherwise unmark the article on current line.
 If ARG, unmark thread/article on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
-      (gnus-uu-unmark-thread)
+      (save-excursion
+       (gnus-uu-unmark-thread))
     (gnus-summary-unmark-as-processable 1)))
 
 (defun gnus-pick-mouse-pick (e)
     (gnus-summary-unmark-as-processable 1)))
 
 (defun gnus-pick-mouse-pick (e)
@@ -218,7 +230,7 @@ This must be bound to a button-down mouse event."
   (let* ((echo-keystrokes 0)
         (start-posn (event-start start-event))
         (start-point (posn-point start-posn))
   (let* ((echo-keystrokes 0)
         (start-posn (event-start start-event))
         (start-point (posn-point start-posn))
-         (start-line (1+ (count-lines 1 start-point)))
+        (start-line (1+ (count-lines 1 start-point)))
         (start-window (posn-window start-posn))
         (bounds (gnus-window-edges start-window))
         (top (nth 1 bounds))
         (start-window (posn-window start-posn))
         (bounds (gnus-window-edges start-window))
         (top (nth 1 bounds))
@@ -241,46 +253,46 @@ This must be bound to a button-down mouse event."
     ;; (but not outside the window where the drag started).
     (let (event end end-point (end-of-range (point)))
       (track-mouse
     ;; (but not outside the window where the drag started).
     (let (event end end-point (end-of-range (point)))
       (track-mouse
-       (while (progn
-                (setq event (cdr (gnus-read-event-char)))
-                (or (mouse-movement-p event)
-                    (eq (car-safe event) 'switch-frame)))
-         (if (eq (car-safe event) 'switch-frame)
-             nil
-           (setq end (event-end event)
-                 end-point (posn-point end))
-
-           (cond
-            ;; Are we moving within the original window?
-            ((and (eq (posn-window end) start-window)
-                  (integer-or-marker-p end-point))
-             ;; Go to START-POINT first, so that when we move to END-POINT,
-             ;; if it's in the middle of intangible text,
-             ;; point jumps in the direction away from START-POINT.
-             (goto-char start-point)
-             (goto-char end-point)
-             (gnus-pick-article)
-             ;; In case the user moved his mouse really fast, pick
-             ;; articles on the line between this one and the last one.
-             (let* ((this-line (1+ (count-lines 1 end-point)))
-                    (min-line (min this-line start-line))
-                    (max-line (max this-line start-line)))
-               (while (< min-line max-line)
-                 (goto-line min-line)
-                 (gnus-pick-article)
-                 (setq min-line (1+ min-line)))
-               (setq start-line this-line))
-             (when (zerop (% click-count 3))
-               (setq end-of-range (point))))
-            (t
-             (let ((mouse-row (cdr (cdr (mouse-position)))))
-               (cond
-                ((null mouse-row))
-                ((< mouse-row top)
-                 (mouse-scroll-subr start-window (- mouse-row top)))
-                ((>= mouse-row bottom)
-                 (mouse-scroll-subr start-window
-                                    (1+ (- mouse-row bottom)))))))))))
+       (while (progn
+               (setq event (cdr (gnus-read-event-char)))
+               (or (mouse-movement-p event)
+                   (eq (car-safe event) 'switch-frame)))
+        (if (eq (car-safe event) 'switch-frame)
+            nil
+          (setq end (event-end event)
+                end-point (posn-point end))
+
+          (cond
+           ;; Are we moving within the original window?
+           ((and (eq (posn-window end) start-window)
+                 (integer-or-marker-p end-point))
+            ;; Go to START-POINT first, so that when we move to END-POINT,
+            ;; if it's in the middle of intangible text,
+            ;; point jumps in the direction away from START-POINT.
+            (goto-char start-point)
+            (goto-char end-point)
+            (gnus-pick-article)
+            ;; In case the user moved his mouse really fast, pick
+            ;; articles on the line between this one and the last one.
+            (let* ((this-line (1+ (count-lines 1 end-point)))
+                   (min-line (min this-line start-line))
+                   (max-line (max this-line start-line)))
+              (while (< min-line max-line)
+                (goto-line min-line)
+                (gnus-pick-article)
+                (setq min-line (1+ min-line)))
+              (setq start-line this-line))
+            (when (zerop (% click-count 3))
+              (setq end-of-range (point))))
+           (t
+            (let ((mouse-row (cdr (cdr (mouse-position)))))
+              (cond
+               ((null mouse-row))
+               ((< mouse-row top)
+                (mouse-scroll-subr start-window (- mouse-row top)))
+               ((>= mouse-row bottom)
+                (mouse-scroll-subr start-window
+                                   (1+ (- mouse-row bottom)))))))))))
       (when (consp event)
        (let ((fun (key-binding (vector (car event)))))
          ;; Run the binding of the terminating up-event, if possible.
       (when (consp event)
        (let ((fun (key-binding (vector (car event)))))
          ;; Run the binding of the terminating up-event, if possible.
@@ -322,8 +334,8 @@ This must be bound to a button-down mouse event."
   (setq gnus-binary-mode-map (make-sparse-keymap))
 
   (gnus-define-keys
   (setq gnus-binary-mode-map (make-sparse-keymap))
 
   (gnus-define-keys
-   gnus-binary-mode-map
-   "g" gnus-binary-show-article))
+      gnus-binary-mode-map
+    "g" gnus-binary-show-article))
 
 (defun gnus-binary-make-menu-bar ()
   (unless (boundp 'gnus-binary-menu)
 
 (defun gnus-binary-make-menu-bar ()
   (unless (boundp 'gnus-binary-menu)
@@ -349,13 +361,14 @@ This must be bound to a button-down mouse event."
       ;; Set up the menu.
       (when (gnus-visual-p 'binary-menu 'menu)
        (gnus-binary-make-menu-bar))
       ;; Set up the menu.
       (when (gnus-visual-p 'binary-menu 'menu)
        (gnus-binary-make-menu-bar))
-      (gnus-add-minor-mode 'gnus-binary-mode " Binary" gnus-binary-mode-map)
+      (gnus-add-minor-mode 'gnus-binary-mode " Binary"
+                          gnus-binary-mode-map nil 'gnus-binary-mode)
       (gnus-run-hooks 'gnus-binary-mode-hook))))
 
 (defun gnus-binary-display-article (article &optional all-header)
   "Run ARTICLE through the binary decode functions."
   (when (gnus-summary-goto-subject article)
       (gnus-run-hooks 'gnus-binary-mode-hook))))
 
 (defun gnus-binary-display-article (article &optional all-header)
   "Run ARTICLE through the binary decode functions."
   (when (gnus-summary-goto-subject article)
-    (let ((gnus-view-pseudos 'automatic))
+    (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
       (gnus-uu-decode-uu))))
 
 (defun gnus-binary-show-article (&optional arg)
       (gnus-uu-decode-uu))))
 
 (defun gnus-binary-show-article (&optional arg)
@@ -412,6 +425,11 @@ Two predefined functions are available:
   :type 'hook
   :group 'gnus-summary-tree)
 
   :type 'hook
   :group 'gnus-summary-tree)
 
+(when (featurep 'xemacs)
+  (add-hook 'gnus-tree-mode-hook 'gnus-xmas-tree-menu-add)
+  (add-hook 'gnus-tree-mode-hook 'gnus-xmas-switch-horizontal-scrollbar-off))
+
+
 ;;; Internal variables.
 
 (defvar gnus-tree-line-format-alist
 ;;; Internal variables.
 
 (defvar gnus-tree-line-format-alist
@@ -431,6 +449,7 @@ Two predefined functions are available:
 (defvar gnus-selected-tree-overlay nil)
 
 (defvar gnus-tree-displayed-thread nil)
 (defvar gnus-selected-tree-overlay nil)
 
 (defvar gnus-tree-displayed-thread nil)
+(defvar gnus-tree-inhibit nil)
 
 (defvar gnus-tree-mode-map nil)
 (put 'gnus-tree-mode 'mode-class 'special)
 
 (defvar gnus-tree-mode-map nil)
 (put 'gnus-tree-mode 'mode-class 'special)
@@ -439,13 +458,13 @@ Two predefined functions are available:
   (setq gnus-tree-mode-map (make-keymap))
   (suppress-keymap gnus-tree-mode-map)
   (gnus-define-keys
   (setq gnus-tree-mode-map (make-keymap))
   (suppress-keymap gnus-tree-mode-map)
   (gnus-define-keys
-   gnus-tree-mode-map
-   "\r" gnus-tree-select-article
-   gnus-mouse-2 gnus-tree-pick-article
-   "\C-?" gnus-tree-read-summary-keys
-   "h" gnus-tree-show-summary
+      gnus-tree-mode-map
+    "\r" gnus-tree-select-article
+    gnus-mouse-2 gnus-tree-pick-article
+    "\C-?" gnus-tree-read-summary-keys
+    "h" gnus-tree-show-summary
 
 
-   "\C-c\C-i" gnus-info-find-node)
+    "\C-c\C-i" gnus-info-find-node)
 
   (substitute-key-definition
    'undefined 'gnus-tree-read-summary-keys gnus-tree-mode-map))
 
   (substitute-key-definition
    'undefined 'gnus-tree-read-summary-keys gnus-tree-mode-map))
@@ -481,15 +500,17 @@ Two predefined functions are available:
 (defun gnus-tree-read-summary-keys (&optional arg)
   "Read a summary buffer key sequence and execute it."
   (interactive "P")
 (defun gnus-tree-read-summary-keys (&optional arg)
   "Read a summary buffer key sequence and execute it."
   (interactive "P")
-  (let ((buf (current-buffer))
-       win)
-    (set-buffer gnus-article-buffer)
-    (gnus-article-read-summary-keys arg nil t)
-    (when (setq win (get-buffer-window buf))
-      (select-window win)
-      (when gnus-selected-tree-overlay
-       (goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
-      (gnus-tree-minimize))))
+  (unless gnus-tree-inhibit
+    (let ((buf (current-buffer))
+         (gnus-tree-inhibit t)
+         win)
+      (set-buffer gnus-article-buffer)
+      (gnus-article-read-summary-keys arg nil t)
+      (when (setq win (get-buffer-window buf))
+       (select-window win)
+       (when gnus-selected-tree-overlay
+         (goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
+       (gnus-tree-minimize)))))
 
 (defun gnus-tree-show-summary ()
   "Reconfigure windows to show summary buffer."
 
 (defun gnus-tree-show-summary ()
   "Reconfigure windows to show summary buffer."
@@ -534,7 +555,7 @@ Two predefined functions are available:
 (defun gnus-tree-recenter ()
   "Center point in the tree window."
   (let ((selected (selected-window))
 (defun gnus-tree-recenter ()
   "Center point in the tree window."
   (let ((selected (selected-window))
-       (tree-window (get-buffer-window gnus-tree-buffer t)))
+       (tree-window (gnus-get-buffer-window gnus-tree-buffer t)))
     (when tree-window
       (select-window tree-window)
       (when gnus-selected-tree-overlay
     (when tree-window
       (select-window tree-window)
       (when gnus-selected-tree-overlay
@@ -647,6 +668,10 @@ Two predefined functions are available:
       (let* ((score (or (cdr (assq article gnus-newsgroup-scored))
                        gnus-summary-default-score 0))
             (default gnus-summary-default-score)
       (let* ((score (or (cdr (assq article gnus-newsgroup-scored))
                        gnus-summary-default-score 0))
             (default gnus-summary-default-score)
+            (default-high gnus-summary-default-high-score)
+            (default-low gnus-summary-default-low-score)
+             (uncached (memq article gnus-newsgroup-undownloaded))
+             (downloaded (not uncached))
             (mark (or (gnus-summary-article-mark article) gnus-unread-mark)))
        ;; Eval the cars of the lists until we find a match.
        (while (and list
             (mark (or (gnus-summary-article-mark article) gnus-unread-mark)))
        ;; Eval the cars of the lists until we find a match.
        (while (and list
@@ -677,8 +702,8 @@ Two predefined functions are available:
       (gnus-tree-minimize)
       (gnus-tree-recenter)
       (let ((selected (selected-window)))
       (gnus-tree-minimize)
       (gnus-tree-recenter)
       (let ((selected (selected-window)))
-       (when (get-buffer-window (set-buffer gnus-tree-buffer) t)
-         (select-window (get-buffer-window (set-buffer gnus-tree-buffer) t))
+       (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
+         (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
          (gnus-horizontal-recenter)
          (select-window selected))))))
 
          (gnus-horizontal-recenter)
          (select-window selected))))))
 
@@ -816,6 +841,13 @@ Two predefined functions are available:
 (defun gnus-tree-close (group)
   (gnus-kill-buffer gnus-tree-buffer))
 
 (defun gnus-tree-close (group)
   (gnus-kill-buffer gnus-tree-buffer))
 
+(defun gnus-tree-perhaps-minimize ()
+  (when (and gnus-tree-minimize-window
+            (get-buffer gnus-tree-buffer))
+    (save-excursion
+      (set-buffer gnus-tree-buffer)
+      (gnus-tree-minimize))))
+
 (defun gnus-highlight-selected-tree (article)
   "Highlight the selected article in the tree."
   (let ((buf (current-buffer))
 (defun gnus-highlight-selected-tree (article)
   "Highlight the selected article in the tree."
   (let ((buf (current-buffer))
@@ -834,8 +866,8 @@ Two predefined functions are available:
       (gnus-tree-minimize)
       (gnus-tree-recenter)
       (let ((selected (selected-window)))
       (gnus-tree-minimize)
       (gnus-tree-recenter)
       (let ((selected (selected-window)))
-       (when (get-buffer-window (set-buffer gnus-tree-buffer) t)
-         (select-window (get-buffer-window (set-buffer gnus-tree-buffer) t))
+       (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
+         (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
          (gnus-horizontal-recenter)
          (select-window selected))))
     ;; If we remove this save-excursion, it updates the wrong mode lines?!?
          (gnus-horizontal-recenter)
          (select-window selected))))
     ;; If we remove this save-excursion, it updates the wrong mode lines?!?
@@ -851,7 +883,7 @@ Two predefined functions are available:
       (when (setq region (gnus-tree-article-region article))
        (gnus-put-text-property (car region) (cdr region) 'face face)
        (set-window-point
       (when (setq region (gnus-tree-article-region article))
        (gnus-put-text-property (car region) (cdr region) 'face face)
        (set-window-point
-        (get-buffer-window (current-buffer) t) (cdr region))))))
+        (gnus-get-buffer-window (current-buffer) t) (cdr region))))))
 
 ;;;
 ;;; gnus-carpal
 
 ;;;
 ;;; gnus-carpal
@@ -877,6 +909,7 @@ Two predefined functions are available:
     ("matching" . gnus-group-list-matching)
     ("post" . gnus-group-post-news)
     ("mail" . gnus-group-mail)
     ("matching" . gnus-group-list-matching)
     ("post" . gnus-group-post-news)
     ("mail" . gnus-group-mail)
+    ("local" . (lambda () (interactive) (gnus-group-news 0)))
     ("rescan" . gnus-group-get-new-news)
     ("browse-foreign" . gnus-group-browse-foreign)
     ("exit" . gnus-group-exit)))
     ("rescan" . gnus-group-get-new-news)
     ("browse-foreign" . gnus-group-browse-foreign)
     ("exit" . gnus-group-exit)))
@@ -907,7 +940,8 @@ Two predefined functions are available:
     ("kill" . gnus-summary-kill-thread)
     "post"
     ("post" . gnus-summary-post-news)
     ("kill" . gnus-summary-kill-thread)
     "post"
     ("post" . gnus-summary-post-news)
-    ("mail" . gnus-summary-mail)
+    ("local" . gnus-summary-news-other-window)
+    ("mail" . gnus-summary-mail-other-window)
     ("followup" . gnus-summary-followup-with-original)
     ("reply" . gnus-summary-reply-with-original)
     ("cancel" . gnus-summary-cancel-article)
     ("followup" . gnus-summary-followup-with-original)
     ("reply" . gnus-summary-reply-with-original)
     ("cancel" . gnus-summary-cancel-article)