;;; gnus-group.el --- group mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-;; Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;; 2005 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
;; 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;; Commentary:
(require 'time-date)
(require 'gnus-ems)
-(eval-when-compile
+(eval-when-compile
(require 'mm-url)
(let ((features (cons 'gnus-group features)))
(require 'gnus-sum))
(defcustom gnus-group-highlight
'(;; Mail.
((and mailp (= unread 0) (eq level 1)) .
- gnus-group-mail-1-empty-face)
+ gnus-group-mail-1-empty)
((and mailp (eq level 1)) .
- gnus-group-mail-1-face)
+ gnus-group-mail-1)
((and mailp (= unread 0) (eq level 2)) .
- gnus-group-mail-2-empty-face)
+ gnus-group-mail-2-empty)
((and mailp (eq level 2)) .
- gnus-group-mail-2-face)
+ gnus-group-mail-2)
((and mailp (= unread 0) (eq level 3)) .
- gnus-group-mail-3-empty-face)
+ gnus-group-mail-3-empty)
((and mailp (eq level 3)) .
- gnus-group-mail-3-face)
+ gnus-group-mail-3)
((and mailp (= unread 0)) .
- gnus-group-mail-low-empty-face)
+ gnus-group-mail-low-empty)
((and mailp) .
- gnus-group-mail-low-face)
+ gnus-group-mail-low)
;; News.
((and (= unread 0) (eq level 1)) .
- gnus-group-news-1-empty-face)
+ gnus-group-news-1-empty)
((and (eq level 1)) .
- gnus-group-news-1-face)
+ gnus-group-news-1)
((and (= unread 0) (eq level 2)) .
- gnus-group-news-2-empty-face)
+ gnus-group-news-2-empty)
((and (eq level 2)) .
- gnus-group-news-2-face)
+ gnus-group-news-2)
((and (= unread 0) (eq level 3)) .
- gnus-group-news-3-empty-face)
+ gnus-group-news-3-empty)
((and (eq level 3)) .
- gnus-group-news-3-face)
+ gnus-group-news-3)
((and (= unread 0) (eq level 4)) .
- gnus-group-news-4-empty-face)
+ gnus-group-news-4-empty)
((and (eq level 4)) .
- gnus-group-news-4-face)
+ gnus-group-news-4)
((and (= unread 0) (eq level 5)) .
- gnus-group-news-5-empty-face)
+ gnus-group-news-5-empty)
((and (eq level 5)) .
- gnus-group-news-5-face)
+ gnus-group-news-5)
((and (= unread 0) (eq level 6)) .
- gnus-group-news-6-empty-face)
+ gnus-group-news-6-empty)
((and (eq level 6)) .
- gnus-group-news-6-face)
+ gnus-group-news-6)
((and (= unread 0)) .
- gnus-group-news-low-empty-face)
+ gnus-group-news-low-empty)
(t .
- gnus-group-news-low-face))
+ gnus-group-news-low))
"*Controls the highlighting of group buffer lines.
Below is a list of `Form'/`Face' pairs. When deciding how a a
:type 'character)
(defgroup gnus-group-icons nil
- "Add Icons to your group buffer. "
+ "Add Icons to your group buffer."
:group 'gnus-group-visual)
(defcustom gnus-group-icon-list
If it is an alist, it must consist of \(NUMBER . PROMPT\) pairs, for example:
\((1 . \"\") (2 . \"nnfolder+archive:\")). The element with number 0 is
used when no prefix argument is given to `gnus-group-jump-to-group'."
- :version "21.4"
+ :version "22.1"
:group 'gnus-group-various
:type '(choice (string :tag "Prompt string")
(const :tag "Empty" nil)
(?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
(?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
(gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d)
- (?g gnus-tmp-group ?s)
+ (?g (if (boundp 'gnus-tmp-decoded-group)
+ gnus-tmp-decoded-group
+ gnus-tmp-group)
+ ?s)
(?G gnus-tmp-qualified-group ?s)
- (?c (gnus-short-group-name gnus-tmp-group) ?s)
+ (?c (gnus-short-group-name (if (boundp 'gnus-tmp-decoded-group)
+ gnus-tmp-decoded-group
+ gnus-tmp-group))
+ ?s)
(?C gnus-tmp-comment ?s)
(?D gnus-tmp-newsgroup-description ?s)
(?o gnus-tmp-moderated ?c)
"\M-e" gnus-group-edit-group-method
"^" gnus-group-enter-server-mode
gnus-mouse-2 gnus-mouse-pick-group
+ [follow-link] mouse-face
"<" beginning-of-buffer
">" end-of-buffer
"\C-c\C-b" gnus-bug
"r" gnus-group-rename-group
"R" gnus-group-make-rss-group
"c" gnus-group-customize
+ "z" gnus-group-compact-group
"x" gnus-group-nnimap-expunge
"\177" gnus-group-delete-group
[delete] gnus-group-delete-group)
(gnus-group-group-name)]
["Select quick" gnus-group-quick-select-group (gnus-group-group-name)]
["Customize" gnus-group-customize (gnus-group-group-name)]
+ ["Compact" gnus-group-compact-group
+ :active (gnus-group-group-name)]
("Edit"
["Parameters" gnus-group-edit-group-parameters
:included (not (gnus-topic-mode-p))
(gnus-undo-mode 1))
(when gnus-slave
(gnus-slave-mode))
- (gnus-run-hooks 'gnus-group-mode-hook))
+ (gnus-run-mode-hooks 'gnus-group-mode-hook))
(defun gnus-update-group-mark-positions ()
(save-excursion
(point)
(prog1 (1+ (point))
;; Insert the text.
- (let ((gnus-tmp-group (gnus-group-name-decode
- gnus-tmp-group group-name-charset)))
+ (let ((gnus-tmp-decoded-group (gnus-group-name-decode
+ gnus-tmp-group group-name-charset)))
(eval gnus-group-line-format-spec)))
`(gnus-group ,(gnus-intern-safe gnus-tmp-group gnus-active-hashtb)
gnus-unread ,(if (numberp number)
- (string-to-int gnus-tmp-number-of-unread)
+ (string-to-number gnus-tmp-number-of-unread)
t)
gnus-marked ,gnus-tmp-marked-mark
gnus-indentation ,gnus-group-indentation
If the number of articles in a newsgroup is greater than this value,
confirmation is required for selecting the newsgroup. If it is nil, no
confirmation is required."
- :version "21.4"
+ :version "22.1"
:group 'gnus-group-select
:type '(choice (const :tag "No limit" nil)
integer))
(defcustom gnus-fetch-old-ephemeral-headers nil
"Same as `gnus-fetch-old-headers', but only used for ephemeral newsgroups."
- :version "21.4"
+ :version "22.1"
:group 'gnus-thread
:type '(choice (const :tag "off" nil)
(const some)
(defun gnus-group-read-ephemeral-group (group method &optional activate
quit-config request-only
select-articles
- parameters)
+ parameters
+ number)
"Read GROUP from METHOD as an ephemeral group.
If ACTIVATE, request the group first.
If QUIT-CONFIG, use that window configuration when exiting from the
If REQUEST-ONLY, don't actually read the group; just request it.
If SELECT-ARTICLES, only select those articles.
If PARAMETERS, use those as the group parameters.
+If NUMBER, fetch this number of articles.
Return the name of the group if selection was successful."
(interactive
(when (let ((gnus-large-newsgroup gnus-large-ephemeral-newsgroup)
(gnus-fetch-old-headers
gnus-fetch-old-ephemeral-headers))
- (gnus-group-read-group t t group select-articles))
+ (gnus-group-read-group (or number t) t group select-articles))
group)
;;(error nil)
(quit
(nname (if method (gnus-group-prefixed-name name meth) name))
backend info)
(when (gnus-group-entry nname)
- (error "Group %s already exists" nname))
+ (error "Group %s already exists" (gnus-group-decoded-name nname)))
;; Subscribe to the new group.
(gnus-group-change-level
(setq info (list t nname gnus-level-default-subscribed nil nil meth))
(unless (gnus-check-backend-function 'request-delete-group group)
(error "This back end does not support group deletion"))
(prog1
- (if (and (not no-prompt)
- (not (gnus-yes-or-no-p
- (format
- "Do you really want to delete %s%s? "
- group (if force " and all its contents" "")))))
- () ; Whew!
- (gnus-message 6 "Deleting group %s..." group)
- (if (not (gnus-request-delete-group group force))
- (gnus-error 3 "Couldn't delete group %s" group)
- (gnus-message 6 "Deleting group %s...done" group)
- (gnus-group-goto-group group)
- (gnus-group-kill-group 1 t)
- (gnus-set-active group nil)
- t))
+ (let ((group-decoded (gnus-group-decoded-name group)))
+ (if (and (not no-prompt)
+ (not (gnus-yes-or-no-p
+ (format
+ "Do you really want to delete %s%s? "
+ group-decoded (if force " and all its contents" "")))))
+ () ; Whew!
+ (gnus-message 6 "Deleting group %s..." group-decoded)
+ (if (not (gnus-request-delete-group group force))
+ (gnus-error 3 "Couldn't delete group %s" group-decoded)
+ (gnus-message 6 "Deleting group %s...done" group-decoded)
+ (gnus-group-goto-group group)
+ (gnus-group-kill-group 1 t)
+ (gnus-set-active group nil)
+ t)))
(gnus-group-position-point)))
(defun gnus-group-rename-group (group new-name)
(gnus-group-position-point))
(defun gnus-group-make-doc-group (file type)
- "Create a group that uses a single file as the source."
+ "Create a group that uses a single file as the source.
+
+If called with a prefix argument, ask for the file type."
(interactive
(list (read-file-name "File name: ")
(and current-prefix-arg 'ask)))
char found)
(while (not found)
(message
- "%sFile type (mbox, babyl, digest, forward, mmdf, guess) [mbdfag]: "
+ "%sFile type (mbox, babyl, digest, forward, mmdf, guess) [m, b, d, f, a, g]: "
err)
(setq found (cond ((= (setq char (read-char)) ?m) 'mbox)
((= char ?b) 'babyl)
(setq url (read-from-minibuffer "URL to Search for RSS: ")))
(let ((feedinfo (nnrss-discover-feed url)))
(if feedinfo
- (let ((title (read-from-minibuffer "Title: "
- (cdr (assoc 'title
- 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))))
- (push (list title href desc)
- nnrss-group-alist)
- (gnus-group-unsubscribe-group
- (concat "nnrss:" title))
+ (href (cdr (assoc 'href feedinfo)))
+ (encodable (mm-coding-system-p 'utf-8)))
+ (when encodable
+ ;; 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 ""))
+ (push (list title href desc) nnrss-group-alist)
(nnrss-save-server-data nil))
(error "No feeds found for %s" url))))
;;; Clearing data
(defun gnus-group-clear-data (&optional arg)
- "Clear all marks and read ranges from the current group."
+ "Clear all marks and read ranges from the current group.
+Obeys the process/prefix convention."
(interactive "P")
(gnus-group-iterate arg
(lambda (group)
"Do you really want to mark all articles in %s as read? "
"Mark all unread articles in %s as read? ")
(if (= (length groups) 1)
- (car groups)
+ (gnus-group-decoded-name (car groups))
(format "these %d groups" (length groups)))))))
n
(while (setq group (pop groups))
(defun gnus-group-expire-articles-1 (group)
(when (gnus-check-backend-function 'request-expire-articles group)
- (gnus-message 6 "Expiring articles in %s..." group)
+ (gnus-message 6 "Expiring articles in %s..."
+ (gnus-group-decoded-name group))
(let* ((info (gnus-get-info group))
(expirable (if (gnus-group-total-expirable-p group)
(cons nil (gnus-list-of-read-articles group))
(gnus-request-expire-articles
(gnus-uncompress-sequence (cdr expirable)) group))))
(gnus-close-group group))
- (gnus-message 6 "Expiring articles in %s...done" group)
+ (gnus-message 6 "Expiring articles in %s...done"
+ (gnus-group-decoded-name group))
;; Return the list of un-expired articles.
(cdr expirable))))
(progn
(unless (gnus-group-process-prefix current-prefix-arg)
(error "No group on the current line"))
- (string-to-int
+ (string-to-number
(let ((s (read-string
(format "Level (default %s): "
(or (gnus-group-group-level)
(dolist (group (gnus-group-process-prefix n))
(gnus-group-remove-mark group)
(gnus-message 6 "Changed level of %s from %d to %d"
- group (or (gnus-group-group-level) gnus-level-killed)
+ (gnus-group-decoded-name group)
+ (or (gnus-group-group-level) gnus-level-killed)
level)
(gnus-group-change-level
group level (or (gnus-group-group-level) gnus-level-killed))
gnus-list-of-killed-groups))
(gnus-group-change-level
(if entry entry group) gnus-level-killed (if entry nil level))
- (message "Killed group %s" group))
+ (message "Killed group %s" (gnus-group-decoded-name group)))
;; If there are lots and lots of groups to be killed, we use
;; this thing instead.
(dolist (group (nreverse groups))
(gnus-add-marked-articles
group 'expire (list article))))))
+
+;;;
+;;; Group compaction
+;;;
+
+(defun gnus-group-compact-group (group)
+ "Conpact the current group.
+Compaction means removing gaps between article numbers. Hence, this
+operation is only meaningful for back ends using one file per article
+\(e.g. nnml)."
+ (interactive (list (gnus-group-group-name)))
+ (unless group
+ (error "No group to compact"))
+ (unless (gnus-check-backend-function 'request-compact-group group)
+ (error "This back end does not support group compaction"))
+ (let ((group-decoded (gnus-group-decoded-name group)))
+ (gnus-message 6 "\
+Compacting group %s... (this may take a long time)"
+ group-decoded)
+ (prog1
+ (if (not (gnus-request-compact-group group))
+ (gnus-error 3 "Couldn't compact group %s" group-decoded)
+ (gnus-message 6 "Compacting group %s...done" group-decoded)
+ t)
+ (gnus-group-update-group-line))))
+
(provide 'gnus-group)
;;; arch-tag: 2eb5440f-0bca-4091-814c-e37817536af6