;;; gnus.el --- a newsreader for GNU Emacs
-;; Copyright (C) 1987,88,89,90,93,94,95,96,97 Free Software Foundation, Inc.
+;; Copyright (C) 1987,88,89,90,93,94,95,96,97,98 Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
-;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news, mail
;; This file is part of GNU Emacs.
:group 'news
:group 'mail)
+(defgroup gnus-cache nil
+ "Cache interface."
+ :group 'gnus)
+
(defgroup gnus-start nil
"Starting your favorite newsreader."
:group 'gnus)
:link '(custom-manual "(gnus)Exiting Gnus")
:group 'gnus)
-(defconst gnus-version-number "0.22"
+(defconst gnus-version-number "0.23"
"Version number for this version of Gnus.")
-(defconst gnus-version (format "Quassia Gnus v%s" gnus-version-number)
+(defconst gnus-version (format "Pterodactyl Gnus v%s" gnus-version-number)
"Version string for this version of Gnus.")
(defcustom gnus-inhibit-startup-message nil
"Face used for normal interest read articles.")
+;;;
+;;; Gnus buffers
+;;;
+
+(defvar gnus-buffers nil)
+
+(defun gnus-get-buffer-create (name)
+ "Do the same as `get-buffer-create', but store the created buffer."
+ (or (get-buffer name)
+ (car (push (get-buffer-create name) gnus-buffers))))
+
+(defun gnus-add-buffer ()
+ "Add the current buffer to the list of Gnus buffers."
+ (push (current-buffer) gnus-buffers))
+
+(defun gnus-buffers ()
+ "Return a list of live Gnus buffers."
+ (while (and gnus-buffers
+ (not (buffer-name (car gnus-buffers))))
+ (pop gnus-buffers))
+ (let ((buffers gnus-buffers))
+ (while (cdr buffers)
+ (if (buffer-name (cadr buffers))
+ (pop buffers)
+ (setcdr buffers (cddr buffers)))))
+ gnus-buffers)
+
;;; Splash screen.
(defvar gnus-group-buffer "*Group*")
(defface gnus-splash-face
'((((class color)
(background dark))
- (:foreground "ForestGreen"))
+ (:foreground "Brown"))
(((class color)
(background light))
- (:foreground "ForestGreen"))
+ (:foreground "Brown"))
(t
()))
- "Level 1 newsgroup face.")
+ "Face of the splash screen.")
(defun gnus-splash ()
(save-excursion
- (switch-to-buffer (get-buffer-create gnus-group-buffer))
+ (switch-to-buffer (gnus-get-buffer-create gnus-group-buffer))
(let ((buffer-read-only nil))
(erase-buffer)
(unless gnus-inhibit-startup-message
(eval-when (load)
(let ((command (format "%s" this-command)))
- (when (and (string-match "gnus" command)
- (not (string-match "gnus-other-frame" command)))
- (gnus-splash))))
+ (if (and (string-match "gnus" command)
+ (not (string-match "gnus-other-frame" command)))
+ (gnus-splash)
+ (gnus-get-buffer-create gnus-group-buffer))))
;;; Do the rest.
(defcustom gnus-directory (or (getenv "SAVEDIR")
(nnheader-concat gnus-home-directory "News/"))
- "Directory variable from which all other Gnus file variables are derived."
+ "*Directory variable from which all other Gnus file variables are derived.
+
+Note that Gnus is mostly loaded when the `.gnus.el' file is read.
+This means that other directory variables that are initialized from
+this variable won't be set properly if you set this variable in `.gnus.el'.
+Set this variable in `.emacs' instead."
:group 'gnus-files
:type 'directory)
:group 'gnus-files
:group 'gnus-server
:type 'file)
-
+
;; This function is used to check both the environment variable
;; NNTPSERVER and the /etc/nntpserver file to see whether one can find
;; an nntp server name default.
(or (getenv "NNTPSERVER")
(and (file-readable-p gnus-nntpserver-file)
(save-excursion
- (set-buffer (get-buffer-create " *gnus nntp*"))
+ (set-buffer (gnus-get-buffer-create " *gnus nntp*"))
(buffer-disable-undo (current-buffer))
(insert-file-contents gnus-nntpserver-file)
(let ((name (buffer-string)))
nil
(list gnus-nntp-service)))
(error nil))
- "Default method for selecting a newsgroup.
+ "*Default method for selecting a newsgroup.
This variable should be a list, where the first element is how the
news is to be fetched, the second is the address.
,(nnheader-concat message-directory "archive/active"))
(nnfolder-get-new-mail nil)
(nnfolder-inhibit-expiry t))
- "Method used for archiving messages you've sent.
+ "*Method used for archiving messages you've sent.
This should be a mail method.
It's probably not a very effective to change this variable once you've
\"nnml+private:mail.misc\", for instance."
:group 'gnus-message
:type '(choice (const :tag "none" nil)
+ sexp
string))
(defcustom gnus-secondary-servers nil
"/ftp@nctuccca.edu.tw:/USENET/FAQ/"
"/ftp@hwarang.postech.ac.kr:/pub/usenet/"
"/ftp@ftp.hk.super.net:/mirror/faqs/")
- "Directory where the group FAQs are stored.
+ "*Directory where the group FAQs are stored.
This will most commonly be on a remote machine, and the file will be
fetched by ange-ftp.
(defcustom gnus-summary-prepare-exit-hook
'(gnus-summary-expire-articles)
- "A hook called when preparing to exit from the summary buffer.
+ "*A hook called when preparing to exit from the summary buffer.
It calls `gnus-summary-expire-articles' by default."
:group 'gnus-summary-exit
:type 'hook)
(defcustom gnus-expert-user nil
"*Non-nil means that you will never be asked for confirmation about anything.
-And that means *anything*."
+That doesn't mean *anything* anything; particularly destructive
+commands will still require prompting."
:group 'gnus-meta
:type 'boolean)
("nnsoup" post-mail address)
("nndraft" post-mail)
("nnfolder" mail respool address)
- ("nngateway" none address prompt-address physical-address)
+ ("nngateway" post-mail address prompt-address physical-address)
("nnweb" none)
+ ("nnlistserv" none)
("nnagent" post-mail))
- "An alist of valid select methods.
+ "*An alist of valid select methods.
The first element of each list lists should be a string with the name
of the select method. The other elements may be the category of
this method (i. e., `post', `mail', `none' or whatever) or other
browse-menu server-menu
page-marker tree-menu binary-menu pick-menu
grouplens-menu)
- "Enable visual features.
+ "*Enable visual features.
If `visual' is disabled, there will be no menus and few faces. Most of
the visual customization options below will be ignored. Gnus will use
less space and be faster as a result.
'highlight)
'default)
(error 'highlight))
- "Face used for group or summary buffer mouse highlighting.
+ "*Face used for group or summary buffer mouse highlighting.
The line beneath the mouse pointer will be highlighted with this
face."
:group 'gnus-visual
gnus-article-hide-boring-headers
gnus-article-treat-overstrike
gnus-article-maybe-highlight))
- "Controls how the article buffer will look.
+ "*Controls how the article buffer will look.
If you leave the list empty, the article will appear exactly as it is
stored on the disk. The list entries will hide or highlight various
\f
;;; Internal variables
+(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
(defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
(defvar gnus-original-article-buffer " *Original Article*")
(defvar gnus-newsgroup-name nil)
+(defvar gnus-ephemeral-servers nil)
(defvar gnus-agent nil
"Whether we want to use the Gnus agent or not.")
;; Variable holding the user answers to all method prompts.
(defvar gnus-method-history nil)
-(defvar gnus-group-history nil)
;; Variable holding the user answers to all mail method prompts.
(defvar gnus-mail-method-history nil)
(defvar gnus-server-alist nil
"List of available servers.")
+(defcustom gnus-cache-directory
+ (nnheader-concat gnus-directory "cache/")
+ "*The directory where cached articles will be stored."
+ :group 'gnus-cache
+ :type 'directory)
+
(defvar gnus-predefined-server-alist
`(("cache"
- (nnspool "cache"
- (nnspool-spool-directory "~/News/cache/")
- (nnspool-nov-directory "~/News/cache/")
- (nnspool-active-file "~/News/cache/active"))))
+ nnspool "cache"
+ (nnspool-spool-directory ,gnus-cache-directory)
+ (nnspool-nov-directory ,gnus-cache-directory)
+ (nnspool-active-file
+ ,(nnheader-concat gnus-cache-directory "active"))))
"List of predefined (convenience) servers.")
(defvar gnus-topic-indentation "") ;; Obsolete variable.
(defvar gnus-article-buffer "*Article*")
(defvar gnus-server-buffer "*Server*")
-(defvar gnus-buffer-list nil
- "Gnus buffers that should be killed on exit.")
-
(defvar gnus-slave nil
"Whether this Gnus is a slave or not.")
(cdr package)))))
'(("metamail" metamail-buffer)
("info" Info-goto-node)
- ("hexl" hexl-hex-string-to-integer)
("pp" pp pp-to-string pp-eval-expression)
+ ("qp" quoted-printable-decode-region quoted-printable-decode-string)
+ ("rfc2047" rfc2047-decode-region rfc2047-decode-string)
("ps-print" ps-print-preprint)
("mail-extr" mail-extract-address-components)
+ ("browse-url" browse-url)
("message" :interactive t
message-send-and-exit message-yank-original)
- ("nnmail" nnmail-split-fancy nnmail-article-group nnmail-date-to-time)
+ ("nnmail" nnmail-split-fancy nnmail-article-group)
("nnvirtual" nnvirtual-catchup-group nnvirtual-convert-headers)
- ("timezone" timezone-make-date-arpa-standard timezone-fix-time
- timezone-make-sortable-date timezone-make-time-string)
("rmailout" rmail-output)
("rmail" rmail-insert-rmail-file-header rmail-count-new-messages
- rmail-show-message)
+ rmail-show-message rmail-output-to-rmail-file)
("gnus-audio" :interactive t gnus-audio-play)
("gnus-xmas" gnus-xmas-splash)
("gnus-soup" :interactive t
gnus-uu-decode-binhex gnus-uu-decode-uu-view
gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
- gnus-uu-decode-binhex-view)
- ("gnus-uu" gnus-uu-delete-work-dir gnus-quote-arg-for-sh-or-csh)
+ gnus-uu-decode-binhex-view gnus-uu-unmark-thread
+ gnus-uu-mark-over)
+ ("gnus-uu" gnus-uu-delete-work-dir gnus-quote-arg-for-sh-or-csh
+ gnus-uu-unmark-thread)
("gnus-msg" (gnus-summary-send-map keymap)
gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
("gnus-msg" :interactive t
gnus-post-news gnus-summary-reply gnus-summary-reply-with-original
gnus-summary-mail-forward gnus-summary-mail-other-window
gnus-summary-resend-message gnus-summary-resend-bounced-mail
- gnus-bug)
+ gnus-summary-wide-reply gnus-summary-followup-to-mail
+ gnus-summary-followup-to-mail-with-original gnus-bug)
("gnus-picon" :interactive t gnus-article-display-picons
gnus-group-display-picons gnus-picons-article-display-x-face
gnus-picons-display-x-face)
("gnus-sum" gnus-summary-insert-line gnus-summary-read-group
gnus-list-of-unread-articles gnus-list-of-read-articles
gnus-offer-save-summaries gnus-make-thread-indent-array
- gnus-summary-exit gnus-update-read-articles)
+ gnus-summary-exit gnus-update-read-articles gnus-summary-last-subject
+ gnus-summary-skip-intangible gnus-summary-article-number
+ gnus-data-header gnus-data-find)
("gnus-group" gnus-group-insert-group-line gnus-group-quit
gnus-group-list-groups gnus-group-first-unread-group
gnus-group-set-mode-line gnus-group-set-info gnus-group-save-newsrc
gnus-group-setup-buffer gnus-group-get-new-news
- gnus-group-make-help-group gnus-group-update-group)
+ gnus-group-make-help-group gnus-group-update-group
+ gnus-clear-inboxes-moved gnus-group-iterate
+ gnus-group-group-name)
("gnus-bcklg" gnus-backlog-request-article gnus-backlog-enter-article
gnus-backlog-remove-article)
("gnus-art" gnus-article-read-summary-keys gnus-article-save
gnus-article-treat-overstrike gnus-article-word-wrap
gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
gnus-article-display-x-face gnus-article-de-quoted-unreadable
- gnus-article-mime-decode-quoted-printable gnus-article-hide-pgp
+ gnus-article-hide-pgp
gnus-article-hide-pem gnus-article-hide-signature
gnus-article-strip-leading-blank-lines gnus-article-date-local
gnus-article-date-original gnus-article-date-lapsed
gnus-start-date-timer gnus-stop-date-timer)
("gnus-int" gnus-request-type)
("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
- gnus-dribble-enter gnus-read-init-file)
+ gnus-dribble-enter gnus-read-init-file gnus-dribble-touch)
("gnus-dup" gnus-dup-suppress-articles gnus-dup-unsuppress-article
gnus-dup-enter-articles)
("gnus-range" gnus-copy-sequence)
gnus-async-halt-prefetch)
("gnus-agent" gnus-open-agent gnus-agent-get-function
gnus-agent-save-groups gnus-agent-save-active gnus-agent-method-p
- gnus-agent-get-undownloaded-list gnus-agent-fetch-session)
+ gnus-agent-get-undownloaded-list gnus-agent-fetch-session
+ gnus-summary-set-agent-mark gnus-agent-save-group-info)
("gnus-agent" :interactive t
gnus-unplugged gnus-agentize gnus-agent-batch)
("gnus-vm" :interactive t gnus-summary-save-in-vm
;;; gnus-sum.el thingies
-(defcustom gnus-summary-line-format "%U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
+(defcustom gnus-summary-line-format "%U%R%z%I%(%[%4L: %-20,20n%]%) %s\n"
"*The format specification of the lines in the summary buffer.
It works along the same lines as a normal formatting string,
"Set GROUP's active info."
`(gnus-sethash ,group ,active gnus-active-hashtb))
-(defun gnus-alive-p ()
- "Say whether Gnus is running or not."
- (and gnus-group-buffer
- (get-buffer gnus-group-buffer)
- (save-excursion
- (set-buffer gnus-group-buffer)
- (eq major-mode 'gnus-group-mode))))
-
;; Info access macros.
(defmacro gnus-info-group (info)
;;; Gnus Utility Functions
;;;
+
(defmacro gnus-string-or (&rest strings)
"Return the first element of STRINGS that is a non-blank string.
STRINGS will be evaluated in normal `or' order."
(setq strings nil)))
string))
-;; Add the current buffer to the list of buffers to be killed on exit.
-(defun gnus-add-current-to-buffer-list ()
- (or (memq (current-buffer) gnus-buffer-list)
- (push (current-buffer) gnus-buffer-list)))
-
(defun gnus-version (&optional arg)
"Version number of this version of Gnus.
If ARG, insert string at point."
(interactive "P")
- (let ((methods gnus-valid-select-methods)
- (mess gnus-version)
- meth)
- ;; Go through all the legal select methods and add their version
- ;; numbers to the total version string. Only the backends that are
- ;; currently in use will have their message numbers taken into
- ;; consideration.
- (while methods
- (setq meth (intern (concat (caar methods) "-version")))
- (and (boundp meth)
- (stringp (symbol-value meth))
- (setq mess (concat mess "; " (symbol-value meth))))
- (setq methods (cdr methods)))
- (if arg
- (insert (message mess))
- (message mess))))
+ (if arg
+ (insert (message gnus-version))
+ (message gnus-version)))
(defun gnus-continuum-version (version)
"Return VERSION as a floating point number."
(when (or (string-match "^\\([^ ]+\\)? ?Gnus v?\\([0-9.]+\\)$" version)
(string-match "^\\(.?\\)gnus-\\([0-9.]+\\)$" version))
- (let* ((alpha (and (match-beginning 1) (match-string 1 version)))
- (number (match-string 2 version))
- major minor least)
- (string-match "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
- (setq major (string-to-number (match-string 1 number)))
- (setq minor (string-to-number (match-string 2 number)))
- (setq least (if (match-beginning 3)
+ (let ((alpha (and (match-beginning 1) (match-string 1 version)))
+ (number (match-string 2 version))
+ major minor least)
+ (unless (string-match
+ "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
+ (error "Invalid version string: %s" version))
+ (setq major (string-to-number (match-string 1 number))
+ minor (string-to-number (match-string 2 number))
+ least (if (match-beginning 3)
(string-to-number (match-string 3 number))
0))
(string-to-number
(if (zerop major)
(format "%s00%02d%02d"
- (cond
- ((member alpha '("(ding)" "d")) "4.99")
- ((member alpha '("September" "s")) "5.01")
- ((member alpha '("Red" "r")) "5.03"))
+ (if (member alpha '("(ding)" "d"))
+ "4.99"
+ (+ 5 (* 0.02
+ (abs
+ (- (mm-char-int (aref (downcase alpha) 0))
+ (mm-char-int ?t))))
+ -0.01))
minor least)
(format "%d.%02d%02d" major minor least))))))
(setq prompt (match-string 1 string)))
(setq i (match-end 0))
;; We basically emulate just about everything that
- ;; `interactive' does, but adds the "g" and "G" specs.
+ ;; `interactive' does, but add the specs listed above.
(push
(cond
((= c ?a)
((= c ?g)
(gnus-group-group-name))
((= c ?A)
- (gnus-summary-article-number))
+ (gnus-summary-skip-intangible)
+ (or (get-text-property (point) 'gnus-number)
+ (gnus-summary-last-subject)))
((= c ?H)
- (gnus-summary-article-header))
+ (gnus-data-header (gnus-data-find (gnus-summary-article-number))))
(t
- (error "Not implemented spec")))
+ (error "Non-implemented spec")))
out)
(cond
((= c ?r)
"Return non-nil if GROUP (and ARTICLE) come from a news server."
(or (gnus-member-of-valid 'post group) ; Ordinary news group.
(and (gnus-member-of-valid 'post-mail group) ; Combined group.
- (eq (gnus-request-type group article) 'news))))
+ (if (or (null article)
+ (not (< article 0)))
+ (eq (gnus-request-type group article) 'news)
+ (if (not (vectorp article))
+ nil
+ ;; It's a real article.
+ (eq (gnus-request-type group (mail-header-id article))
+ 'news))))))
;; Returns a list of writable groups.
(defun gnus-writable-groups ()
(defun gnus-ephemeral-group-p (group)
"Say whether GROUP is ephemeral or not."
- (gnus-group-get-parameter group 'quit-config))
+ (gnus-group-get-parameter group 'quit-config t))
(defun gnus-group-quit-config (group)
"Return the quit-config of GROUP."
- (gnus-group-get-parameter group 'quit-config))
+ (gnus-group-get-parameter group 'quit-config t))
(defun gnus-kill-ephemeral-group (group)
"Remove ephemeral GROUP from relevant structures."
(gnus-server-to-method method))
((equal method gnus-select-method)
gnus-select-method)
- ((and (stringp (car method)) group)
+ ((and (stringp (car method))
+ group)
(gnus-server-extend-method group method))
- ((and method (not group)
+ ((and method
+ (not group)
(equal (cadr method) ""))
method)
(t
"Say whether the group is secondary or not."
(gnus-secondary-method-p (gnus-find-method-for-group group)))
-(defun gnus-group-find-parameter (group &optional symbol)
+(defun gnus-group-find-parameter (group &optional symbol allow-list)
"Return the group parameters for GROUP.
If SYMBOL, return the value of that symbol in the group parameters."
(save-excursion
(set-buffer gnus-group-buffer)
(let ((parameters (funcall gnus-group-get-parameter-function group)))
(if symbol
- (gnus-group-parameter-value parameters symbol)
+ (gnus-group-parameter-value parameters symbol allow-list)
parameters))))
-(defun gnus-group-get-parameter (group &optional symbol)
+(defun gnus-group-get-parameter (group &optional symbol allow-list)
"Return the group parameters for GROUP.
-If SYMBOL, return the value of that symbol in the group parameters."
+If SYMBOL, return the value of that symbol in the group parameters.
+Most functions should use `gnus-group-find-parameter', which
+also examines the topic parameters."
(let ((params (gnus-info-params (gnus-get-info group))))
(if symbol
- (gnus-group-parameter-value params symbol)
+ (gnus-group-parameter-value params symbol allow-list)
params)))
-(defun gnus-group-parameter-value (params symbol)
+(defun gnus-group-parameter-value (params symbol &optional allow-list)
"Return the value of SYMBOL in group PARAMS."
- (or (car (memq symbol params)) ; It's either a simple symbol
- (cdr (assq symbol params)))) ; or a cons.
+ ;; We only wish to return group parameters (dotted lists) and
+ ;; not local variables, which may have the same names.
+ ;; But first we handle single elements...
+ (or (car (memq symbol params))
+ ;; Handle alist.
+ (let (elem)
+ (catch 'found
+ (while (setq elem (pop params))
+ (when (and (consp elem)
+ (eq (car elem) symbol)
+ (or allow-list
+ (atom (cdr elem))))
+ (throw 'found (cdr elem))))))))
(defun gnus-group-add-parameter (group param)
"Add parameter PARAM to GROUP."
(when params
(setq params (delq name params))
(while (assq name params)
- (setq params (delq (assq name params) params)))
+ (gnus-pull name params))
(gnus-info-set-params info params))))))
(defun gnus-group-add-score (group &optional score)
"Collapse GROUP name LEVELS.
Select methods are stripped and any remote host name is stripped down to
just the host name."
- (let* ((name "") (foreign "") (depth -1) (skip 1)
+ (let* ((name "")
+ (foreign "")
+ (depth 0)
+ (skip 1)
(levels (or levels
(progn
(while (string-match "\\." group skip)
(defun gnus-read-method (prompt)
"Prompt the user for a method.
Allow completion over sensible values."
- (let ((method
- (completing-read
- prompt (append gnus-valid-select-methods gnus-predefined-server-alist
- gnus-server-alist)
- nil t nil 'gnus-method-history)))
+ (let* ((servers
+ (append gnus-valid-select-methods
+ gnus-predefined-server-alist
+ gnus-server-alist))
+ (method
+ (completing-read
+ prompt servers
+ nil t nil 'gnus-method-history)))
(cond
((equal method "")
(setq method gnus-select-method))
(assoc method gnus-valid-select-methods))
(read-string "Address: ")
"")))
- ((assoc method gnus-server-alist)
+ ((assoc method servers)
method)
(t
(list (intern method) "")))))
;;;###autoload
(defun gnus-slave-no-server (&optional arg)
- "Read network news as a slave, without connecting to local server"
+ "Read network news as a slave, without connecting to local server."
(interactive "P")
(gnus-no-server arg t))