+Tue Oct 29 20:42:07 1996 Lars Magne Ingebrigtsen <larsi@ylfing.ifi.uio.no>
+
+ * gnus-topic.el (gnus-topic-remove-topic): Fold properly.
+
+Tue Oct 29 19:45:25 1996 Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+
+ * message.el (message-generate-new-buffer-clone-locals): Bugged
+ out under XEmacs.
+
+Tue Oct 29 19:21:47 1996 David Moore <dmoore@ucsd.edu>
+
+ * gnus.el: Fixed autoloads.
+
+Tue Oct 29 17:21:42 1996 Lars Magne Ingebrigtsen <larsi@ylfing.ifi.uio.no>
+
+ * gnus-art.el (gnus-url-mailto): `message-goto-subject' takes no
+ args.
+
+Mon Oct 28 15:42:21 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.el: Autoload gnus-score-followup-thread.
+ (gnus-inhibit-startup-message): Doc fix.
+
+Sat Oct 26 15:48:28 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus-xmas.el (gnus-xmas-topic-menu-add): Add menu.
+
+ * gnus-topic.el (gnus-topic-kill-group): Enter into dribble.
+
+ * gnus-sum.el (gnus-summary-universal-argument): Bind
+ `gnus-newsgroup-process-marked' to nil before calling functions.
+
+Sat Oct 26 15:31:18 1996 David Moore <dmoore@ucsd.edu>
+
+ * nnmail.el (nnmail-activate): Faster version.
+
+Fri Oct 25 09:02:08 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * nnsoup.el (nnsoup-pack-replies): Error empty dirs.
+
+ * gnus-msg.el (gnus-summary-mail-forward): Allow prefix to forward
+ full headers.
+
+Thu Oct 24 07:20:30 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus-nocem.el (gnus-nocem-enter-article): Would enter unbound
+ symbols into hashtb.
+
+Thu Oct 24 07:12:23 1996 Michael R. Cook <mcook@cognex.com>
+
+ * nnmh.el (nnmh-active-number): Misplaced paren.
+
+Thu Oct 24 07:02:54 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus-group.el (gnus-group-list-groups): Clear inboxes.
+
+ * gnus-async.el (gnus-make-async-article-function): Use the
+ success param.
+
+ * nntp.el (nntp-after-change-function-callback): Pass along the
+ right success param.
+
+Wed Oct 23 18:33:15 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus-score.el (gnus-summary-increase-score): Spud.
+
+Wed Oct 23 07:55:42 1996 William Perry <wmperry@aventail.com>
+
+ * gnus-art.el (gnus-url-mailto): New function.
+
+Wed Oct 23 06:57:10 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * nnbabyl.el (nnbabyl-create-mbox): New function.
+ (nnbabyl-open-server): Create mbox.
+
+ * nnmbox.el (nnmbox-create-mbox): New function.
+
+Tue Oct 22 07:30:12 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * nnml.el (nnml-request-list): Always return t.
+
+Tue Oct 22 03:16:27 1996 Felix Lee <flee@teleport.com>
+
+ * gnus-score.el (gnus-score-adaptive): Use the right syntax
+ table.
+
+Tue Oct 22 03:08:30 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el (message-generate-headers): Rename Original-Sender as
+ well.
+ (message-send-news): Typo.
+ (message-send-news): Don't message.
+
+Tue Oct 22 03:06:49 1996 Felix Lee <flee@teleport.com>
+
+ * gnus-score.el (gnus-score-adaptive): gnus-score-adaptive will do
+ line scoring or word scoring, but not both.
+
+Tue Oct 22 02:48:08 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el (message-send-news): Use it.
+ (message-send-mail): Ditto.
+
+Tue Oct 22 02:40:14 1996 Joev Dubach <dubach1@husc.harvard.edu>
+
+ * message.el (message-generate-new-buffer-clone-locals): New
+ function.
+
+Tue Oct 22 01:19:47 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el: Removed `lisp-indent-hook' throughout all files.
+
+ * gnus.el (gnus-sethash): Fix edebug form spec.
+
+ * gnus-cache.el (gnus-cache-file-name): Translate file chars.
+
+Sun Oct 20 03:41:47 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * nntp.el (nntp-read-server-type): Fold case.
+
+Sat Oct 19 08:03:17 1996 Michael Ernst <mernst@cs.washington.edu>
+
+ * article.el (article-hide-headers): Do the right thing on
+ articles with no bodies.
+ (article-narrow-to-signature): Doc fix.
+
+Sat Oct 19 07:53:49 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * nnsoup.el (nnsoup-pack-replies): Refuse to pack when there is
+ nothing to pack.
+ (nnsoup-read-areas): Don't bug out on empty packets.
+
+ * gnus-soup.el (gnus-soup-pack-packet): Refuse to pack empty
+ packets.
+
+Sat Oct 19 07:43:33 1996 Kees de Bruin <kees_de_bruin@tasking.nl>
+
+ * gnus-sum.el (gnus-auto-center-summary): Fix.
+
+Sat Oct 19 07:32:27 1996 Marc Horowitz <marc@cygnus.com>
+
+ * gnus-topic.el (gnus-topic-remove-topic): Would clobber
+ duplicates.
+
+Sat Oct 19 07:01:14 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el (message-send-mail-hook): New hook.
+ (message-send-news-hook): Ditto.
+
+ * gnus-art.el (gnus-summary-write-to-file): New function.
+
+Sat Oct 19 06:56:34 1996 Kees de Bruin <kees_de_bruin@tasking.nl>
+
+ * gnus-sum.el (gnus-summary-save-article-mail-overwrite): New
+ command and keystroke.
+
+Thu Oct 17 06:25:55 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus-sum.el (gnus-article-sort-by-date): Use faster
+ implementation.
+
+ * gnus-util.el (gnus-string-get-time): New macro.
+
+ * message.el (message-check-news-syntax): Check more thorougly the
+ From header.
+ (message-check): New macro.
+
+Thu Oct 17 06:03:56 1996 Carsten Leonhardt <leo@arioch.tng.oche.de>
+
+ * gnus-ems.el (gnus-xemacs): Avoid clobbering functions.
+
+Thu Oct 17 05:34:15 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el (message-cite-function): Initialize from
+ mail-citation-hook.
+
+Thu Oct 17 02:45:47 1996 Lars Magne Ingebrigtsen <larsi@hrym.ifi.uio.no>
+
+ * gnus.el: Red Gnus v0.52 is released.
+
Wed Oct 16 21:01:41 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
* gnus-sum.el (gnus-summary-catchup): Return t.
;; Then treat the rest of the header lines.
(narrow-to-region
(point)
- (progn (search-forward "\n\n" nil t) (forward-line -1) (point)))
+ (if (search-forward "\n\n" nil t) ; if there's a body
+ (progn (forward-line -1) (point))
+ (point-max)))
;; Then we use the two regular expressions
;; `gnus-ignored-headers' and `gnus-visible-headers' to
;; select which header lines is to remain visible in the
(defvar mime::preview/content-list)
(defvar mime::preview-content-info/point-min)
(defun article-narrow-to-signature ()
- "Narrow to the signature."
+ "Narrow to the signature; return t if a signature is found, else nil."
(widen)
(when (and (boundp 'mime::preview/content-list)
mime::preview/content-list)
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
-;; Version: 0.993
+;; Version: 0.995
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
(require 'custom)
(require 'widget-edit)
+(require 'easymenu)
(define-widget-keywords :custom-show :custom-magic
:custom-state :custom-level :custom-form
(form (widget-get widget :custom-form))
(state (widget-get widget :custom-state))
(symbol (widget-get widget :value))
+ (options (get symbol 'custom-options))
(child-type (or (get symbol 'custom-type) 'sexp))
- (type (if (listp child-type)
- child-type
- (list child-type)))
+ (type (let ((tmp (if (listp child-type)
+ child-type
+ (list child-type))))
+ (when options
+ (widget-put tmp :options options))
+ tmp))
(conv (widget-convert type))
(value (if (boundp symbol)
(symbol-value symbol)
(widget-apply widget :notify widget event)
(widget-setup))))
+;;; The `hook' Widget.
+
+(define-widget 'hook 'list
+ "A emacs lisp hook"
+ :convert-widget 'custom-hook-convert-widget
+ :tag "Hook")
+
+(defun custom-hook-convert-widget (widget)
+ ;; Handle `:custom-options'.
+ (let* ((options (widget-get widget :options))
+ (other `(editable-list :inline t (function :format "%v")))
+ (args (if options
+ (list `(checklist :inline t
+ ,@(mapcar (lambda (entry)
+ `(function-item ,entry))
+ options))
+ other)
+ (list other))))
+ (widget-put widget :args args)
+ widget))
+
;;; The `custom-group' Widget.
(define-widget 'custom-group 'custom
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
-;; Version: 0.993
+;; Version: 0.995
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
(require 'widget)
-(define-widget-keywords :type :group)
+(define-widget-keywords :options :type :group)
;; These autoloads should be deleted when the file is added to Emacs
(autoload 'customize "custom-edit" nil t)
(color-instance-name
(specifier-instance
(face-background 'default))))
- (error nil))))
- (cond (bg-resource (intern (downcase bg-resource)))
- ((and color
- (< (apply '+ (custom-x-color-values color))
- (/ (apply '+ (custom-x-color-values "white")) 3)))
- 'dark)
- (t 'light))))
+ (error nil)))
+ (mode (cond (bg-resource (intern (downcase bg-resource)))
+ ((and color
+ (< (apply '+ (custom-x-color-values color))
+ (/ (apply '+ (custom-x-color-values "white"))
+ 3)))
+ 'dark)
+ (t 'light))))
+ (if (fboundp 'set-frame-property)
+ ;; `modify-frame-properties' is borken on XEmacs 19.14.
+ (set-frame-property (selected-frame) 'background-mode mode)
+ ;; `set-frame-property' is unimplemented in Emacs 19.34.
+ (modify-frame-parameters (selected-frame)
+ (cons (cons 'background-mode mode) params)))
+ mode))
;;; The `defcustom' Macro.
(setq args (cdr args))
(cond ((eq keyword :type)
(put symbol 'custom-type value))
+ ((eq keyword :options)
+ (put symbol 'custom-options
+ (append value (get symbol 'custom-options))))
((eq keyword :group)
(custom-add-to-group value symbol 'custom-variable))
(t
The following KEYWORD's are defined:
-:type VALUE should be a sexp widget.
+:type VALUE should be a widget type.
+:options VALUE should be a list of valid members of the widget type.
:group VALUE should be a customization group.
Add SYMBOL to that group.
(defun custom-declare-face (face spec doc &rest args)
"Like `defface', but FACE is evaluated as a normal argument."
(put face 'factory-face spec)
- (unless (facep face)
- ;; If the user has already created the face, respect that.
- (let ((value (or (get face 'saved-face) spec)))
- (custom-face-display-set face value)))
+ (when (fboundp 'facep)
+ (unless (facep face)
+ ;; If the user has already created the face, respect that.
+ (let ((value (or (get face 'saved-face) spec)))
+ (custom-face-display-set face value))))
(when doc
(put face 'face-documentation doc))
(while args
(defun custom-display-match-frame (display frame)
"Non-nil iff DISPLAY matches FRAME.
If FRAME is nil, the current FRAME is used."
- ;; This is a kludge to get started, we realle should use specifiers!
+ ;; This is a kludge to get started, we really should use specifiers!
(unless frame
(setq frame (selected-frame)))
(if (eq display t)
(options (cdr entry)))
(setq display (cdr display))
(cond ((eq req 'type)
- (setq match (if (fboundp 'device-type)
+ (let ((type (if (fboundp 'device-type)
(device-type frame)
- (memq window-system options))))
+ window-system)))
+ (setq match (memq type options))))
((eq req 'class)
(let ((class (if (fboundp 'device-class)
(device-class frame)
* gnus-summary-save-in-rmail (Rmail format)
* gnus-summary-save-in-mail (Unix mail format)
* gnus-summary-save-in-folder (MH folder)
-* gnus-summary-save-in-file (article format).
-* gnus-summary-save-in-vm (use VM's folder format)."
+* gnus-summary-save-in-file (article format)
+* gnus-summary-save-in-vm (use VM's folder format)
+* gnus-summary-write-to-file (article format -- overwrite)."
:group 'article
:type '(radio (function-item gnus-summary-save-in-rmail)
(function-item gnus-summary-save-in-mail)
(function-item gnus-summary-save-in-folder)
(function-item gnus-summary-save-in-file)
- (function-item gnus-summary-save-in-vm)))
+ (function-item gnus-summary-save-in-vm)
+ (function-item gnus-summary-write-to-file)))
(defcustom gnus-rmail-save-name 'gnus-plain-save-name
"A function generating a file name to save articles in Rmail format.
;; Remember the directory name to save articles.
(setq gnus-newsgroup-last-mail filename)))
-(defun gnus-summary-save-in-file (&optional filename)
+(defun gnus-summary-save-in-file (&optional filename overwrite)
"Append this article to file.
Optional argument FILENAME specifies file name.
Directory to save to is default to `gnus-article-save-directory'."
(save-excursion
(save-restriction
(widen)
+ (when (and overwrite
+ (file-exists-p filename))
+ (delete-file filename))
(gnus-output-to-file filename))))
;; Remember the directory name to save articles.
(setq gnus-newsgroup-last-file filename)))
-(defun gnus-summary-save-body-in-file (&optional filename)
+(defun gnus-summary-write-to-file (&optional filename)
"Append this article body to a file.
Optional argument FILENAME specifies file name.
The directory to save in defaults to `gnus-article-save-directory'."
(interactive)
- (gnus-set-global-variables)
- (let ((default-name
- (funcall gnus-file-save-name gnus-newsgroup-name
- gnus-current-headers gnus-newsgroup-last-file)))
- (setq filename (gnus-read-save-file-name
- "Save %s body in file:" default-name filename))
- (gnus-make-directory (file-name-directory filename))
- (gnus-eval-in-buffer-window gnus-original-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (when (search-forward "\n\n" nil t)
- (narrow-to-region (point) (point-max)))
- (gnus-output-to-file filename))))
- ;; Remember the directory name to save articles.
- (setq gnus-newsgroup-last-file filename)))
+ (gnus-summary-save-in-file nil t))
(defun gnus-summary-save-in-pipe (&optional command)
"Pipe this article to subprocess."
gnus-button-fetch-group 3)
("\\(<?\\(url: ?\\)?news:\\([^>\n\t ]*\\)>?\\)" 1 t
gnus-button-message-id 3)
- ("\\(<URL: *\\)?mailto: *\\([^> \n\t]+\\)>?" 0 t gnus-button-reply 2)
+ ("\\(<URL: *\\)?mailto: *\\([^> \n\t]+\\)>?" 0 t gnus-url-mailto 2)
;; This is how URLs _should_ be embedded in text...
("<URL: *\\([^\n\r>]*\\)>" 0 t gnus-button-url 1)
;; Next regexp stolen from highlight-headers.el.
(match-string 3 address)
"nntp"))))))
+(defun gnus-split-string (string pattern)
+ "Return a list of substrings of STRING which are separated by PATTERN."
+ (let (parts (start 0))
+ (while (string-match pattern string start)
+ (setq parts (cons (substring string start (match-beginning 0)) parts)
+ start (match-end 0)))
+ (nreverse (cons (substring string start) parts))))
+
+(defun gnus-url-parse-query-string (query &optional downcase)
+ (let (retval pairs cur key val)
+ (setq pairs (gnus-split-string query "&"))
+ (while pairs
+ (setq cur (car pairs)
+ pairs (cdr pairs))
+ (if (not (string-match "=" cur))
+ nil ; Grace
+ (setq key (gnus-url-unhex-string (substring cur 0 (match-beginning 0)))
+ val (gnus-url-unhex-string (substring cur (match-end 0) nil)))
+ (if downcase
+ (setq key (downcase key)))
+ (setq cur (assoc key retval))
+ (if cur
+ (setcdr cur (cons val (cdr cur)))
+ (setq retval (cons (list key val) retval)))))
+ retval))
+
+(defun gnus-url-unhex (x)
+ (if (> x ?9)
+ (if (>= x ?a)
+ (+ 10 (- x ?a))
+ (+ 10 (- x ?A)))
+ (- x ?0)))
+
+(defun gnus-url-unhex-string (str &optional allow-newlines)
+ "Remove %XXX embedded spaces, etc in a url.
+If optional second argument ALLOW-NEWLINES is non-nil, then allow the
+decoding of carriage returns and line feeds in the string, which is normally
+forbidden in URL encoding."
+ (setq str (or str ""))
+ (let ((tmp "")
+ (case-fold-search t))
+ (while (string-match "%[0-9a-f][0-9a-f]" str)
+ (let* ((start (match-beginning 0))
+ (ch1 (gnus-url-unhex (elt str (+ start 1))))
+ (code (+ (* 16 ch1)
+ (gnus-url-unhex (elt str (+ start 2))))))
+ (setq tmp (concat
+ tmp (substring str 0 start)
+ (cond
+ (allow-newlines
+ (char-to-string code))
+ ((or (= code ?\n) (= code ?\r))
+ " ")
+ (t (char-to-string code))))
+ str (substring str (match-end 0)))))
+ (setq tmp (concat tmp str))
+ tmp))
+
+(defun gnus-url-mailto (url)
+ ;; Send mail to someone
+ (if (not (string-match "mailto:/*\\(.*\\)" url))
+ (error "Malformed mailto link: %s" url))
+ (setq url (substring url (match-beginning 1) nil))
+ (let (to args source-url subject func)
+ (if (string-match (regexp-quote "?") url)
+ (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
+ args (gnus-url-parse-query-string
+ (substring url (match-end 0) nil) t))
+ (setq to (gnus-url-unhex-string url)))
+ (setq args (cons (list "to" to) args)
+ subject (cdr-safe (assoc "subject" args)))
+ (message-mail)
+ (while args
+ (setq func (intern-soft (concat "message-goto-" (downcase (caar args)))))
+ (if (fboundp func)
+ (funcall func)
+ (message-position-on-field (caar args)))
+ (insert (mapconcat 'identity (cdar args) ", "))
+ (setq args (cdr args)))
+ (if subject
+ (message-goto-body)
+ (message-goto-subject))))
+
(defun gnus-button-mailto (address)
;; Mail to ADDRESS.
(set-buffer (gnus-copy-article-buffer))
(gnus-async-release-semaphore 'gnus-async-article-semaphore)))
(put 'gnus-asynch-with-semaphore 'lisp-indent-function 0)
-(put 'gnus-asynch-with-semaphore 'lisp-indent-hook 0)
(put 'gnus-asynch-with-semaphore 'edebug-form-spec '(body))
;;;
"Return a callback function."
`(lambda (arg)
(save-excursion
- (gnus-async-set-buffer)
- (gnus-async-with-semaphore
- (push (list ',(intern (format "%s-%d" group article))
- ,mark (set-marker (make-marker)
- (point-max))
- ,group ,article)
- gnus-async-article-alist))
+ (when arg
+ (gnus-async-set-buffer)
+ (gnus-async-with-semaphore
+ (push (list ',(intern (format "%s-%d" group article))
+ ,mark (set-marker (make-marker) (point-max))
+ ,group ,article)
+ gnus-async-article-alist)))
(if (not (gnus-buffer-live-p ,summary))
(gnus-async-with-semaphore
(setq gnus-async-fetch-list nil))
(defun gnus-cache-file-name (group article)
(concat (file-name-as-directory gnus-cache-directory)
(file-name-as-directory
- (if (gnus-use-long-file-name 'not-cache)
- group
- (let ((group (nnheader-replace-chars-in-string group ?/ ?_)))
- ;; Translate the first colon into a slash.
- (when (string-match ":" group)
- (aset group (match-beginning 0) ?/))
- (nnheader-replace-chars-in-string group ?. ?/))))
+ (nnheader-translate-file-chars
+ (if (gnus-use-long-file-name 'not-cache)
+ group
+ (let ((group (nnheader-replace-chars-in-string group ?/ ?_)))
+ ;; Translate the first colon into a slash.
+ (when (string-match ":" group)
+ (aset group (match-beginning 0) ?/))
+ (nnheader-replace-chars-in-string group ?. ?/)))))
(if (stringp article) article (int-to-string article))))
(defun gnus-cache-update-article (group article)
(defun gnus-demon-scan-nocem ()
"Scan NoCeM groups for NoCeM messages."
- (gnus-nocem-scan-groups))
+ (save-window-excursion
+ (gnus-nocem-scan-groups)))
(defun gnus-demon-add-disconnection ()
"Add daemonic server disconnection to Gnus."
(gnus-demon-add-handler 'gnus-demon-close-connections nil 30))
(defun gnus-demon-close-connections ()
- (gnus-close-backends))
+ (save-window-excursion
+ (gnus-close-backends)))
(defun gnus-demon-add-scanmail ()
"Add daemonic scanning of mail from the mail backends."
(gnus-demon-add-handler 'gnus-demon-scan-mail 120 60))
(defun gnus-demon-scan-mail ()
- (let ((servers gnus-opened-servers)
- server)
- (while (setq server (car (pop servers)))
- (and (gnus-check-backend-function 'request-scan (car server))
- (or (gnus-server-opened server)
- (gnus-open-server server))
- (gnus-request-scan nil server)))))
+ (save-window-excursion
+ (let ((servers gnus-opened-servers)
+ server)
+ (while (setq server (car (pop servers)))
+ (and (gnus-check-backend-function 'request-scan (car server))
+ (or (gnus-server-opened server)
+ (gnus-open-server server))
+ (gnus-request-scan nil server))))))
(defun gnus-demon-add-rescan ()
"Add daemonic scanning of new articles from all backends."
(gnus-demon-add-handler 'gnus-demon-scan-news 120 60))
(defun gnus-demon-scan-news ()
- (when (gnus-alive-p)
- (save-excursion
- (set-buffer gnus-group-buffer)
- (gnus-group-get-new-news))))
+ (save-window-excursion
+ (when (gnus-alive-p)
+ (save-excursion
+ (set-buffer gnus-group-buffer)
+ (gnus-group-get-new-news)))))
(provide 'gnus-demon)
(eval-when-compile (require 'cl))
+;;; Function aliases later to be redefined for XEmacs usage.
+
(defvar gnus-xemacs (string-match "XEmacs\\|Lucid" emacs-version)
"Non-nil if running under XEmacs.")
"{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | xv -quit -"
"String or function to be executed to display an X-Face header.
If it is a string, the command will be executed in a sub-shell
-asynchronously. The compressed face will be piped to this command.")
-)
+asynchronously. The compressed face will be piped to this command."))
(cond
((string-match "XEmacs\\|Lucid" emacs-version)
gnus-group-misc-menu gnus-group-mode-map ""
'("Misc"
["Send a bug report" gnus-bug t]
+ ["Customize" gnus-group-customize t]
["Send a mail" gnus-group-mail t]
["Post an article..." gnus-group-post-news t]
["Check for new news" gnus-group-get-new-news t]
(gnus-group-default-level nil t)
gnus-group-default-list-level
gnus-level-subscribed))))
+ ;; Just do this here, for no particular good reason.
+ (gnus-clear-inboxes-moved)
(unless level
(setq level (car gnus-group-list-mode)
unread (cdr gnus-group-list-mode)))
(eval form))))))
did-kill)))
-(defun gnus-execute (field regexp form &optional backward ignore-marked)
+(defun gnus-execute (field regexp form &optional backward unread)
"If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
If FIELD is an empty string (or nil), entire article body is searched for.
If optional 1st argument BACKWARD is non-nil, do backward instead.
-If optional 2nd argument IGNORE-MARKED is non-nil, articles which are
+If optional 2nd argument UNREAD is non-nil, articles which are
marked as read or ticked are ignored."
(save-excursion
(let ((killed-no 0)
(setq article (gnus-summary-article-number)))
;; Find later articles.
(setq article
- (gnus-summary-search-forward
- ignore-marked nil backward)))
+ (gnus-summary-search-forward unread nil backward)))
(and (or (null gnus-newsgroup-kill-headers)
(memq article gnus-newsgroup-kill-headers))
(vectorp (setq header (gnus-summary-article-header article)))
'send))
(put 'gnus-setup-message 'lisp-indent-function 1)
-(put 'gnus-setup-message 'lisp-indent-hook 1)
(put 'gnus-setup-message 'edebug-form-spec '(form body))
;;; Post news commands of Gnus group mode and summary mode
(interactive "P")
(gnus-summary-reply (gnus-summary-work-articles n)))
-(defun gnus-summary-mail-forward (&optional post)
- "Forward the current message to another user."
+(defun gnus-summary-mail-forward (&optional full-headers post)
+ "Forward the current message to another user.
+If FULL-HEADERS (the prefix), include full headers when forwarding."
(interactive "P")
(gnus-set-global-variables)
(gnus-setup-message 'forward
(gnus-summary-select-article)
(set-buffer gnus-original-article-buffer)
- (message-forward post)))
+ (let ((message-included-forward-headers
+ (if full-headers "" message-included-forward-headers)))
+ (message-forward post))))
(defun gnus-summary-resend-message (address)
"Resend the current article to ADDRESS."
(set-buffer gnus-original-article-buffer)
(message-resend address)))
-(defun gnus-summary-post-forward ()
- "Forward the current article to a newsgroup."
- (interactive)
- (gnus-summary-mail-forward t))
+(defun gnus-summary-post-forward (&optional full-headers)
+ "Forward the current article to a newsgroup.
+If FULL-HEADERS (the prefix), include full headers when forwarding."
+ (interactive "P")
+ (gnus-summary-mail-forward full-headers t))
(defvar gnus-nastygram-message
"The following article was inappropriately posted to %s.\n\n"
(let ((b (search-forward "\n@@BEGIN NCM BODY\n" nil t))
(e (search-forward "\n@@END NCM BODY\n" nil t))
(buf (current-buffer))
- ncm id)
+ ncm id group)
(when (and b e)
(narrow-to-region b (1+ (match-beginning 0)))
(goto-char (point-min))
(while (search-forward "\t" nil t)
- (when (condition-case nil
- (boundp (let ((obarray gnus-active-hashtb)) (read buf)))
- (error nil))
- (beginning-of-line)
- (while (= (following-char) ?\t)
- (forward-line -1))
- (setq id (buffer-substring (point) (1- (search-forward "\t"))))
- (push id ncm)
- (gnus-sethash id t gnus-nocem-hashtb)
- (forward-line 1)
- (while (= (following-char) ?\t)
- (forward-line 1))))
+ (condition-case nil
+ (setq group (let ((obarray gnus-active-hashtb)) (read buf)))
+ (error nil))
+ (if (not (boundp group))
+ ;; Make sure all entries in the hashtb are bound.
+ (set group nil)
+ (when (gnus-gethash (symbol-name group) gnus-newsrc-hashtb)
+ ;; Valid group.
+ (beginning-of-line)
+ (while (= (following-char) ?\t)
+ (forward-line -1))
+ (setq id (buffer-substring (point) (1- (search-forward "\t"))))
+ (push id ncm)
+ (gnus-sethash id t gnus-nocem-hashtb)
+ (forward-line 1)
+ (while (= (following-char) ?\t)
+ (forward-line 1)))))
(when ncm
(setq gnus-nocem-touched-alist t)
(push (cons (let ((time (current-time))) (setcdr (cdr time) nil) time)
("followup" 2 gnus-score-followup)
("thread" 5 gnus-score-thread)))
-(eval-and-compile
- (autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap))
-
;;; Summary mode score maps.
(gnus-define-keys (gnus-summary-score-map "V" gnus-summary-mode-map)
(if (eq (nth 4 entry)
(nth 3 s))
s nil))
- char-to-type ))
+ char-to-type))
2)))
(gnus-score-kill-help-buffer)
(if mimic (message "%c %c %c" prefix hchar tchar pchar)
(message ""))
(unless (setq temporary (cadr (assq pchar char-to-perm)))
+ ;; Deal with der(r)ided superannuated paradigms.
+ (when (and (eq (1+ prefix) 77)
+ (eq (+ hchar 12) 109)
+ (eq tchar 114)
+ (eq (- pchar 4) 111))
+ (error "You rang?"))
(if mimic
(error "%c %c %c %c" prefix hchar tchar pchar)
(error ""))))
(nth 1 entry) ; Header
match ; Match
type ; Type
- (if (eq 's score) nil score) ; Score
- (if (eq 'perm temporary) ; Temp
+ (if (eq score 's) nil score) ; Score
+ (if (eq temporary 'perm) ; Temp
nil
temporary)
(not (nth 3 entry))) ; Prompt
(or gnus-newsgroup-adaptive-score-file
(gnus-score-file-name
gnus-newsgroup-name gnus-adaptive-file-suffix))))
- (cond
- ;; Perform ordinary line scoring.
- ((or (not (listp gnus-use-adaptive-scoring))
- (memq 'line gnus-use-adaptive-scoring))
+ ;; Perform ordinary line scoring.
+ (when (or (not (listp gnus-use-adaptive-scoring))
+ (memq 'line gnus-use-adaptive-scoring))
(save-excursion
(let* ((malist (gnus-copy-sequence gnus-adaptive-score-alist))
(alist malist)
(setq elem (cdr elem)))))
(setq data (cdr data))))))
- ;; Perform adaptive word scoring.
- ((memq 'word gnus-use-adaptive-scoring)
+ ;; Perform adaptive word scoring.
+ (when (and (listp gnus-use-adaptive-scoring)
+ (memq 'word gnus-use-adaptive-scoring))
(nnheader-temp-write nil
(let* ((hashtb (gnus-make-hashtable 1000))
(date (gnus-day-number (current-time-string)))
word d score val)
(unwind-protect
(progn
- (set-syntax-table syntab)
+ (set-syntax-table gnus-adaptive-word-syntax-table)
;; Go through all articles.
(while (setq d (pop data))
(when (and
(gnus-summary-score-entry
"subject" (symbol-name word) 'w (symbol-value word)
date nil t)))
- hashtb)))))))
+ hashtb))))))
(defun gnus-score-edit-done ()
(let ((bufnam (buffer-file-name (current-buffer)))
(setq message-cite-function 'sc-cite-original)
(autoload 'sc-cite-original "supercite"))
\f
-;;;### (autoloads (gnus-batch-score gnus-fetch-group gnus gnus-slave gnus-no-server gnus-update-format) "gnus" "lisp/gnus.el" (12473 2137))
+;;;### (autoloads (gnus gnus-slave gnus-no-server) "gnus" "lisp/gnus.el" (12473 2137))
;;; Generated autoloads from lisp/gnus.el
-(autoload 'gnus-update-format "gnus" "\
-Update the format specification near point." t nil)
-
(autoload 'gnus-slave-no-server "gnus" "\
Read network news as a slave without connecting to local server." t nil)
startup level. If ARG is non-nil and not a positive number, Gnus will
prompt the user for the name of an NNTP server to use." t nil)
-(autoload 'gnus-fetch-group "gnus" "\
+;;;***
+
+;;; These have moved out of gnus.el into other files.
+;;; FIX FIX FIX: should other things be in gnus-setup? or these not in it?
+(autoload 'gnus-update-format "gnus-spec" "\
+Update the format specification near point." t nil)
+
+(autoload 'gnus-fetch-group "gnus-group" "\
Start Gnus if necessary and enter GROUP.
Returns whether the fetching was successful or not." t nil)
(defalias 'gnus-batch-kill 'gnus-batch-score)
-(autoload 'gnus-batch-score "gnus" "\
+(autoload 'gnus-batch-score "gnus-kill" "\
Run batched scoring.
Usage: emacs -batch -l gnus -f gnus-batch-score <newsgroups> ...
Newsgroups is a list of strings in Bnews format. If you want to score
the comp hierarchy, you'd say \"comp.all\". If you would not like to
score the alt hierarchy, you'd say \"!alt.all\"." t nil)
-;;;***
-
(provide 'gnus-setup)
(run-hooks 'gnus-setup-load-hook)
"Make a SOUP packet from the SOUP areas."
(interactive)
(gnus-soup-read-areas)
+ (unless (file-exists-p gnus-soup-directory)
+ (message "No such directory: %s" gnus-soup-directory))
+ (when (null (directory-files gnus-soup-directory nil "\\.MSG$"))
+ (message "No files to pack."))
(gnus-soup-pack gnus-soup-directory gnus-soup-packer))
(defun gnus-group-brew-soup (n)
In particular, if `vertical' do only vertical recentering. If non-nil
and non-`vertical', do both horizontal and vertical recentering."
:group 'gnus-summary
- :type '(choice (const "none" nil)
+ :type '(choice (const :tag "none" nil)
(const vertical)
(sexp :menu-tag "both" t)))
(gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
"o" gnus-summary-save-article
"m" gnus-summary-save-article-mail
+ "F" gnus-summary-write-article-file
"r" gnus-summary-save-article-rmail
"f" gnus-summary-save-article-file
"b" gnus-summary-save-article-body-file
["Save in default format" gnus-summary-save-article t]
["Save in file" gnus-summary-save-article-file t]
["Save in Unix mail format" gnus-summary-save-article-mail t]
+ ["Write to file" gnus-summary-write-article-mail t]
["Save in MH folder" gnus-summary-save-article-folder t]
["Save in VM folder" gnus-summary-save-article-vm t]
["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
;; Saving hidden threads.
(put 'gnus-save-hidden-threads 'lisp-indent-function 0)
-(put 'gnus-save-hidden-threads 'lisp-indent-hook 0)
(put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
(defmacro gnus-save-hidden-threads (&rest forms)
(defsubst gnus-article-sort-by-date (h1 h2)
"Sort articles by root article date."
- (string-lessp
- (inline (gnus-sortable-date (mail-header-date h1)))
- (inline (gnus-sortable-date (mail-header-date h2)))))
+ (gnus-time-less
+ (gnus-date-get-time (mail-header-date h1))
+ (gnus-date-get-time (mail-header-date h2))))
(defun gnus-thread-sort-by-date (h1 h2)
"Sort threads by root article date."
(save-excursion
(while articles
(gnus-summary-goto-subject (setq article (pop articles)))
- (command-execute func)
+ (let (gnus-newsgroup-processable)
+ (command-execute func))
(gnus-summary-remove-process-mark article)))))
(gnus-summary-position-point))
(let ((gnus-default-article-saver 'gnus-summary-save-in-file))
(gnus-summary-save-article arg)))
+(defun gnus-summary-write-article-file (&optional arg)
+ "Write the current article to a file, deleting the previous file.
+If N is a positive number, save the N next articles.
+If N is a negative number, save the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+save those articles instead."
+ (interactive "P")
+ (gnus-set-global-variables)
+ (let ((gnus-default-article-saver 'gnus-summary-write-to-file))
+ (gnus-summary-save-article arg)))
+
(defun gnus-summary-save-article-body-file (&optional arg)
"Append the current article body to a file.
If N is a positive number, save the N next articles.
(while (and (zerop (forward-line 1))
(> (or (gnus-group-topic-level) (1+ level)) level)))
(delete-region beg (point))
- (setcar (cdadr (gnus-topic-find-topology topic))
- (if insert 'visible 'invisible))
+ (setcdr (cadr (gnus-topic-find-topology topic))
+ (if insert (list 'visible) (list 'invisible)))
(when hide
(setcdr (cdadr (gnus-topic-find-topology topic))
(list hide)))
(let ((topic (gnus-group-topic-name)))
(gnus-topic-remove-topic nil t)
(push (gnus-topic-find-topology topic nil nil gnus-topic-topology)
- gnus-topic-killed-topics))
+ gnus-topic-killed-topics)
+ (gnus-topic-enter-dribble))
(gnus-group-kill-group n discard)
(gnus-topic-update-topic)))
(gnus-topic-create-topic
(caar item) (gnus-topic-parent-topic previous) previous
item)
+ (gnus-topic-enter-dribble)
(gnus-topic-goto-topic (caar item)))
(let* ((prev (gnus-group-group-name))
(gnus-topic-inhibit-change-level t)
,@form))))
(put 'gnus-undo-register 'lisp-indent-function 0)
-(put 'gnus-undo-register 'lisp-indent-hook 0)
(put 'gnus-undo-register 'edebug-form-spec '(body))
(defun gnus-undo-register-1 (function)
(select-window ,tempvar)))))
(put 'gnus-eval-in-buffer-window 'lisp-indent-function 1)
-(put 'gnus-eval-in-buffer-window 'lisp-indent-hook 1)
(put 'gnus-eval-in-buffer-window 'edebug-form-spec '(form body))
(defmacro gnus-intern-safe (string hashtable)
`(gnus-define-keys-1 (quote ,keymap) (quote ,plist) t))
(put 'gnus-define-keys 'lisp-indent-function 1)
-(put 'gnus-define-keys 'lisp-indent-hook 1)
(put 'gnus-define-keys-safe 'lisp-indent-function 1)
-(put 'gnus-define-keys-safe 'lisp-indent-hook 1)
(put 'gnus-local-set-keys 'lisp-indent-function 1)
-(put 'gnus-local-set-keys 'lisp-indent-hook 1)
(defmacro gnus-define-keymap (keymap &rest plist)
"Define all keys in PLIST in KEYMAP."
`(gnus-define-keys-1 ,keymap (quote ,plist)))
(put 'gnus-define-keymap 'lisp-indent-function 1)
-(put 'gnus-define-keymap 'lisp-indent-hook 1)
(defun gnus-define-keys-1 (keymap plist &optional safe)
(when (null keymap)
timezone-months-assoc))
"???"))))))
-(defun gnus-time-iso8601 (time)
+(defmacro gnus-date-get-time (date)
+ "Convert DATE string to Emacs time.
+Cache the result as a text property stored in DATE."
+ ;; Either return the cached value...
+ `(let ((d ,date))
+ (or (get-text-property 0 'gnus-time d)
+ ;; or compute the value...
+ (let ((time (nnmail-date-to-time d)))
+ ;; and store it back in the string.
+ (put-text-property 0 1 'gnus-time time d)
+ time))))
+
+(defsubst gnus-time-iso8601 (time)
"Return a string of TIME in YYMMDDTHHMMSS format."
(format-time-string "%Y%m%dT%H%M%S" time))
(defun gnus-date-iso8601 (header)
"Convert the date field in HEADER to YYMMDDTHHMMSS"
(condition-case ()
- (gnus-time-iso8601 (nnmail-date-to-time (mail-header-date header)))
+ (gnus-time-iso8601 (gnus-date-get-time (mail-header-date header)))
(error "")))
(defun gnus-mode-string-quote (string)
- "Quote all \"%\" in STRING."
+ "Quote all \"%\"'s in STRING."
(save-excursion
(gnus-set-work-buffer)
(insert string)
(defmacro gnus-xmas-menu-add (type &rest menus)
`(gnus-xmas-menu-add-1 ',type ',menus))
(put 'gnus-xmas-menu-add 'lisp-indent-function 1)
-(put 'gnus-xmas-menu-add 'lisp-indent-hook 1)
(defun gnus-xmas-menu-add-1 (type menus)
(when (and menu-bar-mode
(defun gnus-xmas-group-menu-add ()
(gnus-xmas-menu-add group
- gnus-group-reading-menu gnus-group-group-menu gnus-group-misc-menu))
+ gnus-group-reading-menu gnus-group-group-menu gnus-group-misc-menu))
(defun gnus-xmas-summary-menu-add ()
(gnus-xmas-menu-add summary
- gnus-summary-misc-menu gnus-summary-kill-menu
- gnus-summary-article-menu gnus-summary-thread-menu
- gnus-summary-post-menu ))
+ gnus-summary-misc-menu gnus-summary-kill-menu
+ gnus-summary-article-menu gnus-summary-thread-menu
+ gnus-summary-post-menu ))
(defun gnus-xmas-article-menu-add ()
(gnus-xmas-menu-add article
- gnus-article-article-menu gnus-article-treatment-menu))
+ gnus-article-article-menu gnus-article-treatment-menu))
(defun gnus-xmas-score-menu-add ()
(gnus-xmas-menu-add score
- gnus-score-menu))
+ gnus-score-menu))
(defun gnus-xmas-pick-menu-add ()
(gnus-xmas-menu-add pick
- gnus-pick-menu))
+ gnus-pick-menu))
+
+(defun gnus-xmas-topic-menu-add ()
+ (gnus-xmas-menu-add topic
+ gnus-topic-menu))
(defun gnus-xmas-binary-menu-add ()
(gnus-xmas-menu-add binary
- gnus-binary-menu))
+ gnus-binary-menu))
(defun gnus-xmas-tree-menu-add ()
(gnus-xmas-menu-add tree
- gnus-tree-menu))
+ gnus-tree-menu))
(defun gnus-xmas-server-menu-add ()
(gnus-xmas-menu-add menu
- gnus-server-server-menu gnus-server-connections-menu))
+ gnus-server-server-menu gnus-server-connections-menu))
(defun gnus-xmas-browse-menu-add ()
(gnus-xmas-menu-add browse
- gnus-browse-menu))
+ gnus-browse-menu))
(defun gnus-xmas-grouplens-menu-add ()
(gnus-xmas-menu-add grouplens
- gnus-grouplens-menu))
+ gnus-grouplens-menu))
(defun gnus-xmas-read-event-char ()
"Get the next event."
(add-hook 'gnus-score-mode-hook 'gnus-xmas-score-menu-add)
(add-hook 'gnus-pick-mode-hook 'gnus-xmas-pick-menu-add)
+ (add-hook 'gnus-topic-mode-hook 'gnus-xmas-topic-menu-add)
(add-hook 'gnus-tree-mode-hook 'gnus-xmas-tree-menu-add)
(add-hook 'gnus-binary-mode-hook 'gnus-xmas-binary-menu-add)
(add-hook 'gnus-grouplens-mode-hook 'gnus-xmas-grouplens-menu-add)
"Score and kill file handling."
:group 'gnus )
-(defconst gnus-version-number "0.52"
+(defconst gnus-version-number "0.53"
"Version number for this version of Gnus.")
(defconst gnus-version (format "Red Gnus v%s" gnus-version-number)
"Version string for this version of Gnus.")
(defcustom gnus-inhibit-startup-message nil
- "*If non-nil, the startup message will not be displayed."
+ "*If non-nil, the startup message will not be displayed.
+This variable is used before `.gnus.el' is loaded, so it should
+be set in `.emacs' instead."
:group 'gnus-start
:type 'boolean)
(t
'ignore)))
+(defalias 'gnus-make-overlay 'make-overlay)
+(defalias 'gnus-overlay-put 'overlay-put)
+(defalias 'gnus-move-overlay 'move-overlay)
+(defalias 'gnus-overlay-end 'overlay-end)
+(defalias 'gnus-extent-detached-p 'ignore)
+(defalias 'gnus-extent-start-open 'ignore)
+(defalias 'gnus-set-text-properties 'set-text-properties)
+(defalias 'gnus-group-remove-excess-properties 'ignore)
+(defalias 'gnus-topic-remove-excess-properties 'ignore)
+(defalias 'gnus-appt-select-lowest-window 'appt-select-lowest-window)
+(defalias 'gnus-mail-strip-quoted-names 'mail-strip-quoted-names)
+(defalias 'gnus-make-local-hook 'make-local-hook)
+(defalias 'gnus-add-hook 'add-hook)
+(defalias 'gnus-character-to-event 'identity)
+(defalias 'gnus-add-text-properties 'add-text-properties)
+(defalias 'gnus-put-text-property 'put-text-property)
+(defalias 'gnus-mode-line-buffer-identification 'identity)
+
;; The XEmacs people think this is evil, so it must go.
(defun custom-face-lookup (&optional fg bg stipple bold italic underline)
"Lookup or create a face with specified attributes."
("hexl" hexl-hex-string-to-integer)
("pp" pp pp-to-string pp-eval-expression)
("mail-extr" mail-extract-address-components)
+ ("message" :interactive t
+ message-send-and-exit message-yank-original)
("nnmail" nnmail-split-fancy nnmail-article-group nnmail-date-to-time)
("nnvirtual" nnvirtual-catchup-group nnvirtual-convert-headers)
("timezone" timezone-make-date-arpa-standard timezone-fix-time
gnus-soup-send-replies gnus-soup-save-areas gnus-soup-pack-packet)
("nnsoup" nnsoup-pack-replies)
("score-mode" :interactive t gnus-score-mode)
- ("gnus-mh" gnus-mh-mail-setup gnus-summary-save-article-folder
+ ("gnus-mh" gnus-summary-save-article-folder
gnus-Folder-save-name gnus-folder-save-name)
("gnus-mh" :interactive t gnus-summary-save-in-folder)
("gnus-demon" gnus-demon-add-nocem gnus-demon-add-scanmail
gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
gnus-cache-enter-remove-article gnus-cached-article-p
gnus-cache-open gnus-cache-close gnus-cache-update-article)
- ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
- gnus-cache-remove-article gnus-summary-insert-cached-articles)
- ("gnus-score" :interactive t
- gnus-summary-increase-score gnus-summary-lower-score
- gnus-score-flush-cache gnus-score-close
- gnus-score-raise-same-subject-and-select
- gnus-score-raise-same-subject gnus-score-default
- gnus-score-raise-thread gnus-score-lower-same-subject-and-select
- gnus-score-lower-same-subject gnus-score-lower-thread
- gnus-possibly-score-headers gnus-summary-raise-score
- gnus-summary-set-score gnus-summary-current-score
- gnus-score-followup-article)
- ("gnus-score"
- (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
+ ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
+ gnus-cache-remove-article gnus-summary-insert-cached-articles)
+ ("gnus-score" :interactive t
+ gnus-summary-increase-score gnus-summary-set-score
+ gnus-summary-raise-thread gnus-summary-raise-same-subject
+ gnus-summary-raise-score gnus-summary-raise-same-subject-and-select
+ gnus-summary-lower-thread gnus-summary-lower-same-subject
+ gnus-summary-lower-score gnus-summary-lower-same-subject-and-select
+ gnus-summary-current-score gnus-score-default
+ gnus-score-flush-cache gnus-score-close
+ gnus-possibly-score-headers gnus-score-followup-article
+ gnus-score-followup-thread)
+ ("gnus-score"
+ (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
gnus-current-score-file-nondirectory gnus-score-adaptive
gnus-score-find-trace gnus-score-file-name)
("gnus-cus" :interactive t gnus-group-customize gnus-score-customize)
gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
gnus-uu-decode-binhex-view)
("gnus-msg" (gnus-summary-send-map keymap)
- gnus-mail-yank-original gnus-mail-send-and-exit
- gnus-article-mail gnus-new-mail gnus-mail-reply
- gnus-copy-article-buffer gnus-extended-version)
+ gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
("gnus-msg" :interactive t
gnus-group-post-news gnus-group-mail gnus-summary-post-news
gnus-summary-followup gnus-summary-followup-with-original
gnus-summary-cancel-article gnus-summary-supersede-article
- gnus-post-news gnus-inews-news
- gnus-summary-reply gnus-summary-reply-with-original
+ 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-bounced-mail
+ gnus-summary-resend-message gnus-summary-resend-bounced-mail
gnus-bug)
("gnus-picon" :interactive t gnus-article-display-picons
gnus-group-display-picons gnus-picons-article-display-x-face
("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p
gnus-grouplens-mode)
("smiley" :interactive t gnus-smiley-display)
- ("gnus" gnus-add-current-to-buffer-list gnus-add-shutdown)
("gnus-win" gnus-configure-windows)
("gnus-sum" gnus-summary-insert-line gnus-summary-read-group
gnus-list-of-unread-articles gnus-list-of-read-articles
gnus-backlog-remove-article)
("gnus-art" gnus-article-read-summary-keys gnus-article-save
gnus-article-prepare gnus-article-set-window-start
- gnus-article-show-all-headers gnus-article-next-page
- gnus-article-prev-page gnus-request-article-this-buffer
- gnus-article-mode gnus-article-setup-buffer gnus-narrow-to-page)
+ gnus-article-next-page gnus-article-prev-page
+ gnus-request-article-this-buffer gnus-article-mode
+ gnus-article-setup-buffer gnus-narrow-to-page)
("gnus-art" :interactive t
gnus-article-hide-headers gnus-article-hide-boring-headers
gnus-article-treat-overstrike gnus-article-word-wrap
("gnus-int" gnus-request-type)
("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
gnus-dribble-enter)
- ("gnus-dup" gnus-dup-suppress-articles gnus-dup-enter-articles)
+ ("gnus-dup" gnus-dup-suppress-articles gnus-dup-unsuppress-article
+ gnus-dup-enter-articles)
("gnus-range" gnus-copy-sequence)
- ("gnus-vm" gnus-vm-mail-setup)
("gnus-eform" gnus-edit-form)
("gnus-move" :interactive t
gnus-group-move-group-to-server gnus-change-server)
("gnus-logic" gnus-score-advanced)
- ("gnus-undo" gnus-undo-mode gnus-undo-register
- gnus-dup-unsuppress-article)
+ ("gnus-undo" gnus-undo-mode gnus-undo-register)
("gnus-async" gnus-async-request-fetched-article gnus-async-prefetch-next
gnus-async-prefetch-article gnus-async-prefetch-remove-group)
("article" article-decode-rfc1522)
(defvar gnus-group-mode-map (make-keymap))
(gnus-suppress-keymap gnus-group-mode-map)
-;;; Function aliases later to be redefined for XEmacs usage.
-
-(defalias 'gnus-make-overlay 'make-overlay)
-(defalias 'gnus-overlay-put 'overlay-put)
-(defalias 'gnus-move-overlay 'move-overlay)
-(defalias 'gnus-overlay-end 'overlay-end)
-(defalias 'gnus-extent-detached-p 'ignore)
-(defalias 'gnus-extent-start-open 'ignore)
-(defalias 'gnus-set-text-properties 'set-text-properties)
-(defalias 'gnus-group-remove-excess-properties 'ignore)
-(defalias 'gnus-topic-remove-excess-properties 'ignore)
-(defalias 'gnus-appt-select-lowest-window 'appt-select-lowest-window)
-(defalias 'gnus-mail-strip-quoted-names 'mail-strip-quoted-names)
-(defalias 'gnus-make-local-hook 'make-local-hook)
-(defalias 'gnus-add-hook 'add-hook)
-(defalias 'gnus-character-to-event 'identity)
-(defalias 'gnus-add-text-properties 'add-text-properties)
-(defalias 'gnus-put-text-property 'put-text-property)
-(defalias 'gnus-mode-line-buffer-identification 'identity)
-
\f
;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
(defmacro gnus-sethash (string value hashtable)
"Set hash value. Arguments are STRING, VALUE, and HASHTABLE."
`(set (intern ,string ,hashtable) ,value))
-(put 'nnheader-temp-write 'edebug-form-spec '(form form form))
+(put 'gnus-sethash 'edebug-form-spec '(form form form))
(defmacro gnus-group-unread (group)
"Get the currently computed number of unread articles in GROUP."
((< colon dot) colon)
((< dot colon) dot)))
":")
- group (substring group (+ 1 colon))
- )))
+ group (substring group (+ 1 colon)))))
(t
(let* ((colon (string-match ":" group)))
(setq foreign (concat (substring group 0 (+ 1 colon)))
group nil)))
name))
-
\f
;;;
;;; Kill file handling.
Used by `message-yank-original' via `message-yank-cite'.")
;;;###autoload
-(defvar message-cite-function 'message-cite-original
+(defvar message-cite-function
+ (if (and (boundp 'mail-citation-hook)
+ mail-citation-hook)
+ mail-citation-hook
+ 'message-cite-original)
"*Function for citing an original message.")
;;;###autoload
(defvar message-send-hook nil
"Hook run before sending messages.")
+(defvar message-send-mail-hook nil
+ "Hook run before sending mail messages.")
+
+(defvar message-send-news-hook nil
+ "Hook run before sending news messages.")
+
(defvar message-sent-hook nil
"Hook run after sending messages.")
(defun message-tokenize-header (header &optional separator)
"Split HEADER into a list of header elements.
\",\" is used as the separator."
- (let ((regexp (format "[%s]+" (or separator ",")))
- (beg 1)
- (first t)
- quoted elems paren)
- (save-excursion
- (message-set-work-buffer)
- (insert header)
- (goto-char (point-min))
- (while (not (eobp))
- (if first
- (setq first nil)
- (forward-char 1))
- (cond ((and (> (point) beg)
- (or (eobp)
- (and (looking-at regexp)
- (not quoted)
- (not paren))))
- (push (buffer-substring beg (point)) elems)
- (setq beg (match-end 0)))
- ((= (following-char) ?\")
- (setq quoted (not quoted)))
- ((and (= (following-char) ?\()
- (not quoted))
- (setq paren t))
- ((and (= (following-char) ?\))
- (not quoted))
- (setq paren nil))))
- (nreverse elems))))
+ (if (not header)
+ nil
+ (let ((regexp (format "[%s]+" (or separator ",")))
+ (beg 1)
+ (first t)
+ quoted elems paren)
+ (save-excursion
+ (message-set-work-buffer)
+ (insert header)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if first
+ (setq first nil)
+ (forward-char 1))
+ (cond ((and (> (point) beg)
+ (or (eobp)
+ (and (looking-at regexp)
+ (not quoted)
+ (not paren))))
+ (push (buffer-substring beg (point)) elems)
+ (setq beg (match-end 0)))
+ ((= (following-char) ?\")
+ (setq quoted (not quoted)))
+ ((and (= (following-char) ?\()
+ (not quoted))
+ (setq paren t))
+ ((and (= (following-char) ?\))
+ (not quoted))
+ (setq paren nil))))
+ (nreverse elems)))))
(defun message-fetch-field (header)
"The same as `mail-fetch-field', only remove all newlines."
"Insert a signature. See documentation for the `message-signature' variable."
(interactive (list 0))
(let* ((signature
- (cond ((and (null message-signature)
- (eq force 0))
- (save-excursion
- (goto-char (point-max))
- (not (re-search-backward
- message-signature-separator nil t))))
- ((and (null message-signature)
- force)
- t)
- ((message-functionp message-signature)
- (funcall message-signature))
- ((listp message-signature)
- (eval message-signature))
- (t message-signature)))
+ (cond
+ ((and (null message-signature)
+ (eq force 0))
+ (save-excursion
+ (goto-char (point-max))
+ (not (re-search-backward
+ message-signature-separator nil t))))
+ ((and (null message-signature)
+ force)
+ t)
+ ((message-functionp message-signature)
+ (funcall message-signature))
+ ((listp message-signature)
+ (eval message-signature))
+ (t message-signature)))
(signature
(cond ((stringp signature)
signature)
(defun message-send-mail (&optional arg)
(require 'mail-utils)
- (let ((tembuf (generate-new-buffer " message temp"))
+ (let ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
(case-fold-search nil)
(news (message-news-p))
(mailbuf (current-buffer)))
(replace-match "\n")
(backward-char 1)
(setq delimline (point-marker))
+ (run-hooks 'message-send-mail-hook)
;; Insert an extra newline if we need it to work around
;; Sun's bug that swallows newlines.
(goto-char (1+ delimline))
(re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n"))
(replace-match "\n")
+ (run-hooks 'message-send-mail-hook)
;; send the message
(case
(apply
;; should never happen
(t (error "qmail-inject reported unknown failure."))))
-
(defun message-send-mail-with-mh ()
"Send the prepared message buffer with mh."
(let ((mh-previous-window-config nil)
(concat "^" (symbol-name (car headers)) ": *") nil t)
(message-delete-line))
(pop headers)))
+ (run-hooks 'message-send-mail-hook)
;; Pass it on to mh.
(mh-send-letter)))
(defun message-send-news (&optional arg)
- (let ((tembuf (generate-new-buffer " *message temp*"))
+ (let ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
(case-fold-search nil)
(method (if (message-functionp message-post-method)
(funcall message-post-method arg)
(message-cleanup-headers)
(if (not (message-check-news-syntax))
(progn
- (message "Posting nor performed")
+ ;;(message "Posting not performed")
nil)
(unwind-protect
(save-excursion
(concat "^" (regexp-quote mail-header-separator) "\n"))
(replace-match "\n")
(backward-char 1))
+ (run-hooks 'message-send-news-hook)
(require (car method))
(funcall (intern (format "%s-open-server" (car method)))
(cadr method) (cddr method))
;;; Header generation & syntax checking.
;;;
+(defmacro message-check (type &rest forms)
+ "Eval FORMS if TYPE is to be checked."
+ `(or (message-check-element ,type)
+ (save-excursion
+ ,@forms)))
+
+(put 'message-check 'lisp-indent-function 1)
+(put 'message-check 'edebug-form-spec '(form body))
+
+(defun message-check-element (type)
+ "Returns non-nil if this type is not to be checked."
+ (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
+ t
+ (let ((able (assq type message-syntax-checks)))
+ (and (consp able)
+ (eq (cdr able) 'disabled)))))
+
(defun message-check-news-syntax ()
"Check the syntax of the message."
+ (save-excursion
+ (save-restriction
+ (widen)
+ (and
+ ;; We narrow to the headers and check them first.
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers)
+ (message-check-news-header-syntax)))
+ ;; Check the body.
+ (message-check-news-body-syntax)))))
+
+(defun message-check-news-header-syntax ()
(and
- ;; We narrow to the headers and check them first.
- (save-excursion
- (save-restriction
- (message-narrow-to-headers)
- (and
- ;; Check for commands in Subject.
- (or
- (message-check-element 'subject-cmsg)
+ ;; Check for commands in Subject.
+ (message-check 'subject-cmsg
+ (if (string-match "^cmsg " (message-fetch-field "subject"))
+ (y-or-n-p
+ "The control code \"cmsg\" is in the subject. Really post? ")
+ t))
+ ;; Check for multiple identical headers.
+ (message-check 'multiple-headers
+ (let (found)
+ (while (and (not found)
+ (re-search-forward "^[^ \t:]+: " nil t))
(save-excursion
- (if (string-match "^cmsg " (message-fetch-field "subject"))
- (y-or-n-p
- "The control code \"cmsg \" is in the subject. Really post? ")
- t)))
- ;; Check for multiple identical headers.
- (or (message-check-element 'multiple-headers)
- (save-excursion
- (let (found)
- (while (and (not found)
- (re-search-forward "^[^ \t:]+: " nil t))
- (save-excursion
- (or (re-search-forward
- (concat "^" (setq found
- (buffer-substring
- (match-beginning 0)
- (- (match-end 0) 2))))
- nil t)
- (setq found nil))))
- (if found
- (y-or-n-p
- (format "Multiple %s headers. Really post? " found))
- t))))
- ;; Check for Version and Sendsys.
- (or (message-check-element 'sendsys)
- (save-excursion
- (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
- (y-or-n-p
- (format "The article contains a %s command. Really post? "
- (buffer-substring (match-beginning 0)
- (1- (match-end 0)))))
- t)))
- ;; See whether we can shorten Followup-To.
- (or (message-check-element 'shorten-followup-to)
- (let ((newsgroups (message-fetch-field "newsgroups"))
- (followup-to (message-fetch-field "followup-to"))
- to)
- (when (and newsgroups (string-match "," newsgroups)
- (not followup-to)
- (not
- (zerop
- (length
- (setq to (completing-read
- "Followups to: (default all groups) "
- (mapcar (lambda (g) (list g))
- (cons "poster"
- (message-tokenize-header
- newsgroups)))))))))
- (goto-char (point-min))
- (insert "Followup-To: " to "\n"))
- t))
- ;; Check "Shoot me".
- (or (message-check-element 'shoot)
- (save-excursion
- (if (re-search-forward
- "Message-ID.*.i-have-a-misconfigured-system-so-shoot-me"
- nil t)
- (y-or-n-p
- "You appear to have a misconfigured system. Really post? ")
- t)))
- ;; Check for Approved.
- (or (message-check-element 'approved)
- (save-excursion
- (if (re-search-forward "^Approved:" nil t)
- (y-or-n-p
- "The article contains an Approved header. Really post? ")
- t)))
- ;; Check the Message-ID header.
- (or (message-check-element 'message-id)
- (save-excursion
- (let* ((case-fold-search t)
- (message-id (message-fetch-field "message-id")))
- (or (not message-id)
- (and (string-match "@" message-id)
- (string-match "@[^\\.]*\\." message-id))
- (y-or-n-p
- (format
- "The Message-ID looks strange: \"%s\". Really post? "
- message-id))))))
- ;; Check the Subject header.
- (or
- (message-check-element 'subject)
- (save-excursion
- (let* ((case-fold-search t)
- (subject (message-fetch-field "subject")))
- (or
- (and subject
- (not (string-match "\\`[ \t]*\\'" subject)))
- (progn
- (message
- "The subject field is empty or missing. Posting is denied.")
- nil)))))
- ;; Check the Newsgroups & Followup-To headers.
- (or
- (message-check-element 'existing-newsgroups)
- (let* ((case-fold-search t)
- (newsgroups (message-fetch-field "newsgroups"))
- (followup-to (message-fetch-field "followup-to"))
- (groups (message-tokenize-header
- (if followup-to
- (concat newsgroups "," followup-to)
- newsgroups)))
- (hashtb (and (boundp 'gnus-active-hashtb)
- gnus-active-hashtb))
- errors)
- (if (not hashtb)
- t
- (while groups
- (when (and (not (boundp (intern (car groups) hashtb)))
- (not (equal (car groups) "poster")))
- (push (car groups) errors))
- (pop groups))
- (if (not errors)
- t
- (y-or-n-p
- (format
- "Really post to %s unknown group%s: %s "
- (if (= (length errors) 1) "this" "these")
- (if (= (length errors) 1) "" "s")
- (mapconcat 'identity errors ", ")))))))
- ;; Check the Newsgroups & Followup-To headers for syntax errors.
- (or
- (message-check-element 'valid-newsgroups)
- (let ((case-fold-search t)
- (headers '("Newsgroups" "Followup-To"))
- header error)
- (while (and headers (not error))
- (when (setq header (mail-fetch-field (car headers)))
- (if (or
- (not
- (string-match
- "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
- header))
- (memq
- nil (mapcar
- (lambda (g)
- (not (string-match "\\.\\'\\|\\.\\." g)))
- (message-tokenize-header header ","))))
- (setq error t)))
- (unless error
- (pop headers)))
- (if (not error)
- t
- (y-or-n-p
- (format "The %s header looks odd: \"%s\". Really post? "
- (car headers) header)))))
- ;; Check the From header.
- (or
- (save-excursion
- (let* ((case-fold-search t)
- (from (message-fetch-field "from")))
- (cond
- ((not from)
- (message "There is no From line. Posting is denied.")
- nil)
- ((not (string-match "@[^\\.]*\\." from))
- (message
- "Denied posting -- the From looks strange: \"%s\"." from)
- nil)
- ((string-match "@[^@]*@" from)
- (message
- "Denied posting -- two \"@\"'s in the From header: %s." from)
- nil)
- ((string-match "(.*).*(.*)" from)
- (message
- "Denied posting -- the From header looks strange: \"%s\"."
- from)
- nil)
- (t t))))))))
- ;; Check for long lines.
- (or (message-check-element 'long-lines)
- (save-excursion
+ (or (re-search-forward
+ (concat "^" (setq found
+ (buffer-substring
+ (match-beginning 0) (- (match-end 0) 2))))
+ nil t)
+ (setq found nil))))
+ (if found
+ (y-or-n-p (format "Multiple %s headers. Really post? " found))
+ t)))
+ ;; Check for Version and Sendsys.
+ (message-check 'sendsys
+ (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
+ (y-or-n-p
+ (format "The article contains a %s command. Really post? "
+ (buffer-substring (match-beginning 0)
+ (1- (match-end 0)))))
+ t))
+ ;; See whether we can shorten Followup-To.
+ (message-check 'shorten-followup-to
+ (let ((newsgroups (message-fetch-field "newsgroups"))
+ (followup-to (message-fetch-field "followup-to"))
+ to)
+ (when (and newsgroups
+ (string-match "," newsgroups)
+ (not followup-to)
+ (not
+ (zerop
+ (length
+ (setq to (completing-read
+ "Followups to: (default all groups) "
+ (mapcar (lambda (g) (list g))
+ (cons "poster"
+ (message-tokenize-header
+ newsgroups)))))))))
(goto-char (point-min))
- (re-search-forward
- (concat "^" (regexp-quote mail-header-separator) "$"))
- (while (and
- (progn
- (end-of-line)
- (< (current-column) 80))
- (zerop (forward-line 1))))
- (or (bolp)
- (eobp)
- (y-or-n-p
- "You have lines longer than 79 characters. Really post? "))))
+ (insert "Followup-To: " to "\n"))
+ t))
+ ;; Check "Shoot me".
+ (message-check 'shoot
+ (if (re-search-forward
+ "Message-ID.*.i-have-a-misconfigured-system-so-shoot-me" nil t)
+ (y-or-n-p "You appear to have a misconfigured system. Really post? ")
+ t))
+ ;; Check for Approved.
+ (message-check 'approved
+ (if (re-search-forward "^Approved:" nil t)
+ (y-or-n-p "The article contains an Approved header. Really post? ")
+ t))
+ ;; Check the Message-ID header.
+ (message-check 'message-id
+ (let* ((case-fold-search t)
+ (message-id (message-fetch-field "message-id")))
+ (or (not message-id)
+ (and (string-match "@" message-id)
+ (string-match "@[^\\.]*\\." message-id))
+ (y-or-n-p
+ (format "The Message-ID looks strange: \"%s\". Really post? "
+ message-id)))))
+ ;; Check the Subject header.
+ (message-check 'subject
+ (let* ((case-fold-search t)
+ (subject (message-fetch-field "subject")))
+ (or
+ (and subject
+ (not (string-match "\\`[ \t]*\\'" subject)))
+ (ignore
+ (message
+ "The subject field is empty or missing. Posting is denied.")))))
+ ;; Check the Newsgroups & Followup-To headers.
+ (message-check 'existing-newsgroups
+ (let* ((case-fold-search t)
+ (newsgroups (message-fetch-field "newsgroups"))
+ (followup-to (message-fetch-field "followup-to"))
+ (groups (message-tokenize-header
+ (if followup-to
+ (concat newsgroups "," followup-to)
+ newsgroups)))
+ (hashtb (and (boundp 'gnus-active-hashtb)
+ gnus-active-hashtb))
+ errors)
+ (if (not hashtb)
+ t
+ (while groups
+ (when (and (not (boundp (intern (car groups) hashtb)))
+ (not (equal (car groups) "poster")))
+ (push (car groups) errors))
+ (pop groups))
+ (if (not errors)
+ t
+ (y-or-n-p
+ (format
+ "Really post to %s unknown group%s: %s "
+ (if (= (length errors) 1) "this" "these")
+ (if (= (length errors) 1) "" "s")
+ (mapconcat 'identity errors ", ")))))))
+ ;; Check the Newsgroups & Followup-To headers for syntax errors.
+ (message-check 'valid-newsgroups
+ (let ((case-fold-search t)
+ (headers '("Newsgroups" "Followup-To"))
+ header error)
+ (while (and headers (not error))
+ (when (setq header (mail-fetch-field (car headers)))
+ (if (or
+ (not
+ (string-match
+ "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
+ header))
+ (memq
+ nil (mapcar
+ (lambda (g)
+ (not (string-match "\\.\\'\\|\\.\\." g)))
+ (message-tokenize-header header ","))))
+ (setq error t)))
+ (unless error
+ (pop headers)))
+ (if (not error)
+ t
+ (y-or-n-p
+ (format "The %s header looks odd: \"%s\". Really post? "
+ (car headers) header)))))
+ ;; Check the From header.
+ (message-check 'from
+ (let* ((case-fold-search t)
+ (from (message-fetch-field "from"))
+ (ad (nth 1 (mail-extract-address-components from))))
+ (cond
+ ((not from)
+ (message "There is no From line. Posting is denied.")
+ nil)
+ ((or (not (string-match "@[^\\.]*\\." ad)) ;larsi@ifi
+ (string-match "\\.\\." ad) ;larsi@ifi..uio
+ (string-match "@\\." ad) ;larsi@.ifi.uio
+ (string-match "\\.$" ad) ;larsi@ifi.uio.
+ (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
+ (string-match "(.*).*(.*)" from)) ;(lars) (lars)
+ (message
+ "Denied posting -- the From looks strange: \"%s\"." from)
+ nil)
+ (t t))))))
+
+(defun message-check-news-body-syntax ()
+ (and
+ ;; Check for long lines.
+ (message-check 'long-lines
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$"))
+ (while (and
+ (progn
+ (end-of-line)
+ (< (current-column) 80))
+ (zerop (forward-line 1))))
+ (or (bolp)
+ (eobp)
+ (y-or-n-p
+ "You have lines longer than 79 characters. Really post? ")))
;; Check whether the article is empty.
- (or (message-check-element 'empty)
- (save-excursion
- (goto-char (point-min))
- (re-search-forward
- (concat "^" (regexp-quote mail-header-separator) "$"))
- (forward-line 1)
- (let ((b (point)))
- (goto-char (point-max))
- (re-search-backward message-signature-separator nil t)
- (beginning-of-line)
- (or (re-search-backward "[^ \n\t]" b t)
- (y-or-n-p "Empty article. Really post? ")))))
+ (message-check 'empty
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$"))
+ (forward-line 1)
+ (let ((b (point)))
+ (goto-char (point-max))
+ (re-search-backward message-signature-separator nil t)
+ (beginning-of-line)
+ (or (re-search-backward "[^ \n\t]" b t)
+ (y-or-n-p "Empty article. Really post? "))))
;; Check for control characters.
- (or (message-check-element 'control-chars)
- (save-excursion
- (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
- (y-or-n-p
- "The article contains control characters. Really post? ")
- t)))
+ (message-check 'control-chars
+ (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
+ (y-or-n-p
+ "The article contains control characters. Really post? ")
+ t))
;; Check excessive size.
- (or (message-check-element 'size)
- (if (> (buffer-size) 60000)
- (y-or-n-p
- (format "The article is %d octets long. Really post? "
- (buffer-size)))
- t))
+ (message-check 'size
+ (if (> (buffer-size) 60000)
+ (y-or-n-p
+ (format "The article is %d octets long. Really post? "
+ (buffer-size)))
+ t))
;; Check whether any new text has been added.
- (or (message-check-element 'new-text)
- (not message-checksum)
- (not (and (eq (message-checksum) (car message-checksum))
- (eq (buffer-size) (cdr message-checksum))))
- (y-or-n-p
- "It looks like no new text has been added. Really post? "))
+ (message-check 'new-text
+ (or
+ (not message-checksum)
+ (not (and (eq (message-checksum) (car message-checksum))
+ (eq (buffer-size) (cdr message-checksum))))
+ (y-or-n-p
+ "It looks like no new text has been added. Really post? ")))
;; Check the length of the signature.
- (or
- (message-check-element 'signature)
- (progn
- (goto-char (point-max))
- (if (or (not (re-search-backward message-signature-separator nil t))
- (search-forward message-forward-end-separator nil t))
- t
- (if (> (count-lines (point) (point-max)) 5)
- (y-or-n-p
- (format
- "Your .sig is %d lines; it should be max 4. Really post? "
- (1- (count-lines (point) (point-max)))))
- t))))))
-
-(defun message-check-element (type)
- "Returns non-nil if this type is not to be checked."
- (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
- t
- (let ((able (assq type message-syntax-checks)))
- (and (consp able)
- (eq (cdr able) 'disabled)))))
+ (message-check 'signature
+ (goto-char (point-max))
+ (if (or (not (re-search-backward message-signature-separator nil t))
+ (search-forward message-forward-end-separator nil t))
+ t
+ (if (> (count-lines (point) (point-max)) 5)
+ (y-or-n-p
+ (format
+ "Your .sig is %d lines; it should be max 4. Really post? "
+ (1- (count-lines (point) (point-max)))))
+ t)))))
(defun message-checksum ()
"Return a \"checksum\" for the current buffer."
(downcase secure-sender)))))
(goto-char (point-min))
;; Rename any old Sender headers to Original-Sender.
- (when (re-search-forward "^Sender:" nil t)
+ (when (re-search-forward "^\\(Original-\\)*Sender:" nil t)
(beginning-of-line)
(insert "Original-")
(beginning-of-line))
(list
(list list))))
+(defun message-generate-new-buffer-clone-locals (name &optional varstr)
+ "Create and return a buffer with a name based on NAME using generate-new-buffer.
+Then clone the local variables and values from the old buffer to the
+new one, cloning only the locals having a substring matching the
+regexp varstr."
+ (let ((oldlocals (buffer-local-variables)))
+ (save-excursion
+ (set-buffer (generate-new-buffer name))
+ (mapcar (lambda (dude)
+ (when (and (car dude)
+ (or (not varstr)
+ (string-match varstr (symbol-name (car dude)))))
+ (condition-case ()
+ (set (make-local-variable (car dude))
+ (cdr dude))
+ (error))))
+ oldlocals)
+ (current-buffer))))
+
(run-hooks 'message-load-hook)
(provide 'message)
"*Number of spaces to insert at the beginning of each cited line.
Used by `message-yank-original' via `message-yank-cite'.")
-(defvar message-cite-function (car mail-citation-hook)
- "*Function for citing an original message.")
-
(defvar message-signature mail-signature
"*String to be inserted at the end of the message buffer.
If t, the `message-signature-file' file will be inserted instead.
(deffoo nnbabyl-open-server (server &optional defs)
(nnoo-change-server 'nnbabyl server defs)
+ (nnbabyl-create-mbox)
(cond
((not (file-exists-p nnbabyl-mbox-file))
(nnbabyl-close-server)
(deffoo nnbabyl-request-list (&optional server)
(save-excursion
(nnmail-find-file nnbabyl-active-file)
- (setq nnbabyl-group-alist (nnmail-get-active))))
+ (setq nnbabyl-group-alist (nnmail-get-active))
+ t))
(deffoo nnbabyl-request-newgroups (date &optional server)
(nnbabyl-request-list server))
nnbabyl-group-alist))
(cdr active)))
-(defun nnbabyl-read-mbox ()
- (nnmail-activate 'nnbabyl)
+(defun nnbabyl-create-mbox ()
(unless (file-exists-p nnbabyl-mbox-file)
;; Create a new, empty RMAIL mbox file.
(save-excursion
(setq buffer-file-name nnbabyl-mbox-file)
(insert "BABYL OPTIONS:\n\n\^_")
(nnmail-write-region
- (point-min) (point-max) nnbabyl-mbox-file t 'nomesg)))
+ (point-min) (point-max) nnbabyl-mbox-file t 'nomesg))))
+
+(defun nnbabyl-read-mbox ()
+ (nnmail-activate 'nnbabyl)
+ (nnbabyl-create-mbox)
(if (and nnbabyl-mbox-buffer
(buffer-name nnbabyl-mbox-buffer)
(nnfolder-possibly-change-group nil server)
(save-excursion
(nnmail-find-file nnfolder-active-file)
- (setq nnfolder-group-alist (nnmail-get-active))))
+ (setq nnfolder-group-alist (nnmail-get-active))
+ t))
(deffoo nnfolder-request-newgroups (date &optional server)
(nnfolder-possibly-change-group nil server)
(kill-buffer ,temp-buffer)))))))
(put 'nnheader-temp-write 'lisp-indent-function 1)
-(put 'nnheader-temp-write 'lisp-indent-hook 1)
(put 'nnheader-temp-write 'edebug-form-spec '(form body))
(defvar jka-compr-compression-info-list)
;; If getting from mail spool directory,
;; use movemail to move rather than just renaming,
;; so as to interlock with the mailer.
- (unless (setq popmail (string-match "^po:" (file-name-nondirectory inbox)))
+ (unless (setq popmail (string-match
+ "^po:" (file-name-nondirectory inbox)))
(setq movemail t))
(when popmail
(setq inbox (file-name-nondirectory inbox)))
(if popmail
(progn
(setq nnmail-internal-password nnmail-pop-password)
- (when (and nnmail-pop-password-required (not nnmail-pop-password))
+ (when (and nnmail-pop-password-required
+ (not nnmail-pop-password))
(setq nnmail-internal-password
(nnmail-read-passwd
(format "Password for %s: "
'call-process
(append
(list
- (expand-file-name nnmail-movemail-program exec-directory)
+ (expand-file-name nnmail-movemail-program
+ exec-directory)
nil errors nil inbox tofile)
(when nnmail-internal-password
(list nnmail-internal-password))))))
;; already activated.
(defun nnmail-activate (backend &optional force)
(let (file timestamp file-time)
- (when (or (not (symbol-value (intern (format "%s-group-alist" backend))))
- force
- (and (setq file (condition-case ()
- (symbol-value (intern (format "%s-active-file"
- backend)))
- (error nil)))
- (setq file-time (nth 5 (file-attributes file)))
- (or (not
- (setq timestamp
- (condition-case ()
- (symbol-value (intern
- (format "%s-active-timestamp"
- backend)))
- (error 'none))))
- (not (consp timestamp))
- (equal timestamp '(0 0))
- (> (nth 0 file-time) (nth 0 timestamp))
- (and (= (nth 0 file-time) (nth 0 timestamp))
- (> (nth 1 file-time) (nth 1 timestamp))))))
- (save-excursion
- (or (eq timestamp 'none)
- (set (intern (format "%s-active-timestamp" backend))
- (current-time)))
- (funcall (intern (format "%s-request-list" backend)))
- (set (intern (format "%s-group-alist" backend))
- (nnmail-get-active))))
+ (if (or (not (symbol-value (intern (format "%s-group-alist" backend))))
+ force
+ (and (setq file (condition-case ()
+ (symbol-value (intern (format "%s-active-file"
+ backend)))
+ (error nil)))
+ (setq file-time (nth 5 (file-attributes file)))
+ (or (not
+ (setq timestamp
+ (condition-case ()
+ (symbol-value (intern
+ (format "%s-active-timestamp"
+ backend)))
+ (error 'none))))
+ (not (consp timestamp))
+ (equal timestamp '(0 0))
+ (> (nth 0 file-time) (nth 0 timestamp))
+ (and (= (nth 0 file-time) (nth 0 timestamp))
+ (> (nth 1 file-time) (nth 1 timestamp))))))
+ (save-excursion
+ (or (eq timestamp 'none)
+ (set (intern (format "%s-active-timestamp" backend))
+;;; dmoore@ucsd.edu 25.10.96
+;;; it's not always the case that current-time
+;;; does correspond to changes in the file's time. So just compare
+;;; the file's new time against its own previous time.
+;;; (current-time)
+ file-time
+ ))
+ (funcall (intern (format "%s-request-list" backend)))
+;;; dmoore@ucsd.edu 25.10.96
+;;; BACKEND-request-list already does this itself!
+;;; (set (intern (format "%s-group-alist" backend))
+;;; (nnmail-get-active))
+ ))
t))
(defun nnmail-message-id ()
(deffoo nnmbox-open-server (server &optional defs)
(nnoo-change-server 'nnmbox server defs)
+ (nnmbox-create-mbox)
(cond
((not (file-exists-p nnmbox-mbox-file))
(nnmbox-close-server)
(deffoo nnmbox-request-list (&optional server)
(save-excursion
(nnmail-find-file nnmbox-active-file)
- (setq nnmbox-group-alist (nnmail-get-active))))
+ (setq nnmbox-group-alist (nnmail-get-active))
+ t))
(deffoo nnmbox-request-newgroups (date &optional server)
(nnmbox-request-list server))
nnmbox-group-alist))
(cdr active)))
+(defun nnmbox-create-mbox ()
+ (when (not (file-exists-p nnmbox-mbox-file))
+ (nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg)))
+
(defun nnmbox-read-mbox ()
(nnmail-activate 'nnmbox)
- (when (not (file-exists-p nnmbox-mbox-file))
- (nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg))
+ (nnmbox-create-mbox)
(if (and nnmbox-mbox-buffer
(buffer-name nnmbox-mbox-buffer)
(save-excursion
(string-to-int f))
(directory-files
(nnmail-group-pathname group nnmh-directory)
- nil "^[0-9]+$")
- '>))))
+ nil "^[0-9]+$"))
+ '>)))
(when files
(setcdr active (car files)))))
(setcdr active (1+ (cdr active)))
(when (not (file-exists-p nnml-directory))
(condition-case ()
(make-directory nnml-directory t)
- (error t)))
+ (error)))
(cond
((not (file-exists-p nnml-directory))
(nnml-close-server)
(deffoo nnml-request-list (&optional server)
(save-excursion
(nnmail-find-file nnml-active-file)
- (setq nnml-group-alist (nnmail-get-active))))
+ (setq nnml-group-alist (nnmail-get-active))
+ t))
(deffoo nnml-request-newgroups (date &optional server)
(nnml-request-list server))
`(defvar ,var ,init))
(nnoo-define ',var ',map)))
(put 'defvoo 'lisp-indent-function 2)
-(put 'defvoo 'lisp-indent-hook 2)
(put 'defvoo 'edebug-form-spec '(var init &optional doc &rest map))
(defmacro deffoo (func args &rest forms)
(defun ,func ,args ,@forms)
(nnoo-register-function ',func)))
(put 'deffoo 'lisp-indent-function 2)
-(put 'deffoo 'lisp-indent-hook 2)
(put 'deffoo 'edebug-form-spec '(&define name lambda-list def-body))
(defun nnoo-register-function (func)
nil nil)
nnoo-definition-alist)))
(put 'nnoo-declare 'lisp-indent-function 1)
-(put 'nnoo-declare 'lisp-indent-hook 1)
(defun nnoo-parents (backend)
(nth 1 (assoc backend nnoo-definition-alist)))
(defmacro nnoo-import (backend &rest imports)
`(nnoo-import-1 ',backend ',imports))
(put 'nnoo-import 'lisp-indent-function 1)
-(put 'nnoo-import 'lisp-indent-hook 1)
(defun nnoo-import-1 (backend imports)
(let ((call-function
(defmacro nnoo-map-functions (backend &rest maps)
`(nnoo-map-functions-1 ',backend ',maps))
(put 'nnoo-map-functions 'lisp-indent-function 1)
-(put 'nnoo-map-functions 'lisp-indent-hook 1)
(defun nnoo-map-functions-1 (backend maps)
(let (m margs i)
prefix))
(defun nnsoup-read-areas ()
- (save-excursion
- (set-buffer nntp-server-buffer)
- (let ((areas (gnus-soup-parse-areas (concat nnsoup-tmp-directory "AREAS")))
- entry number area lnum cur-prefix file)
- ;; Go through all areas in the new AREAS file.
- (while (setq area (pop areas))
- ;; Change the name to the permanent name and move the files.
- (setq cur-prefix (nnsoup-next-prefix))
- (message "Incorporating file %s..." cur-prefix)
- (when (file-exists-p
- (setq file (concat nnsoup-tmp-directory
- (gnus-soup-area-prefix area) ".IDX")))
- (rename-file file (nnsoup-file cur-prefix)))
- (when (file-exists-p
- (setq file (concat nnsoup-tmp-directory
- (gnus-soup-area-prefix area) ".MSG")))
- (rename-file file (nnsoup-file cur-prefix t))
- (gnus-soup-set-area-prefix area cur-prefix)
- ;; Find the number of new articles in this area.
- (setq number (nnsoup-number-of-articles area))
- (if (not (setq entry (assoc (gnus-soup-area-name area)
- nnsoup-group-alist)))
- ;; If this is a new area (group), we just add this info to
- ;; the group alist.
- (push (list (gnus-soup-area-name area)
- (cons 1 number)
- (list (cons 1 number) area))
- nnsoup-group-alist)
- ;; There are already articles in this group, so we add this
- ;; info to the end of the entry.
- (nconc entry (list (list (cons (1+ (setq lnum (cdadr entry)))
- (+ lnum number))
- area)))
- (setcdr (cadr entry) (+ lnum number))))))
- (nnsoup-write-active-file t)
- (delete-file (concat nnsoup-tmp-directory "AREAS"))))
+ (when (file-exists-p (concat nnsoup-tmp-directory "AREAS"))
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (let ((areas (gnus-soup-parse-areas (concat nnsoup-tmp-directory "AREAS")))
+ entry number area lnum cur-prefix file)
+ ;; Go through all areas in the new AREAS file.
+ (while (setq area (pop areas))
+ ;; Change the name to the permanent name and move the files.
+ (setq cur-prefix (nnsoup-next-prefix))
+ (message "Incorporating file %s..." cur-prefix)
+ (when (file-exists-p
+ (setq file (concat nnsoup-tmp-directory
+ (gnus-soup-area-prefix area) ".IDX")))
+ (rename-file file (nnsoup-file cur-prefix)))
+ (when (file-exists-p
+ (setq file (concat nnsoup-tmp-directory
+ (gnus-soup-area-prefix area) ".MSG")))
+ (rename-file file (nnsoup-file cur-prefix t))
+ (gnus-soup-set-area-prefix area cur-prefix)
+ ;; Find the number of new articles in this area.
+ (setq number (nnsoup-number-of-articles area))
+ (if (not (setq entry (assoc (gnus-soup-area-name area)
+ nnsoup-group-alist)))
+ ;; If this is a new area (group), we just add this info to
+ ;; the group alist.
+ (push (list (gnus-soup-area-name area)
+ (cons 1 number)
+ (list (cons 1 number) area))
+ nnsoup-group-alist)
+ ;; There are already articles in this group, so we add this
+ ;; info to the end of the entry.
+ (nconc entry (list (list (cons (1+ (setq lnum (cdadr entry)))
+ (+ lnum number))
+ area)))
+ (setcdr (cadr entry) (+ lnum number))))))
+ (nnsoup-write-active-file t)
+ (delete-file (concat nnsoup-tmp-directory "AREAS")))))
(defun nnsoup-number-of-articles (area)
(save-excursion
(defun nnsoup-pack-replies ()
"Make an outbound package of SOUP replies."
(interactive)
+ (unless (file-exists-p nnsoup-replies-directory)
+ (message "No such directory: %s" nnsoup-replies-directory))
;; Write all data buffers.
(gnus-soup-save-areas)
;; Write the active file.
(nnsoup-write-active-file)
;; Write the REPLIES file.
(nnsoup-write-replies)
+ ;; Check whether there is anything here.
+ (when (null (directory-files nnsoup-replies-directory nil "\\.MSG$"))
+ (error "No files to pack."))
;; Pack all these files into a SOUP packet.
(gnus-soup-pack nnsoup-replies-directory nnsoup-packer))
;; Wait for the status string to arrive.
(setq nntp-server-type (buffer-string))
(let ((alist nntp-server-action-alist)
+ (case-fold-search t)
entry)
;; Run server-specific commands.
(while alist
(nntp-inside-change-function t))
(setq nntp-process-callback nil)
(save-excursion
- (funcall callback t))))))))
+ (funcall callback (buffer-name
+ (get-buffer nntp-process-to-buffer))))))))))
(defun nntp-retrieve-data (command address port buffer
&optional wait-for callback decode)
(defun nntp-decode-text (&optional cr-only)
"Decode the text in the current buffer."
(goto-char (point-min))
- (current-buffer)
+ ;; Remove \R's.
(while (search-forward "\r" nil t)
(delete-char -1))
(unless cr-only
+ ;; Remove trailing ".\n" end-of-transfer marker.
(goto-char (point-max))
(forward-line -1)
(when (looking-at ".\n")
(delete-char 2))
+ ;; Delete status line.
(goto-char (point-min))
(delete-region (point) (progn (forward-line 1) (point)))
+ ;; Remove "." -> ".." encoding.
(while (search-forward "\n.." nil t)
(delete-char -1))))
(require 'gnus-util)
(require 'w3)
(require 'url)
+(condition-case ()
+ (require 'w3-forms)
+ (error))
(nnoo-declare nnweb)
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: extensions
-;; Version: 0.993
+;; Version: 0.995
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
(require 'custom)
(error nil))
-(eval-and-compile
- (unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
- ;; We have the old custom-library, hack around it!
- (defmacro defgroup (&rest args) nil)
- (defmacro defcustom (&rest args) nil)
- (defmacro defface (&rest args) nil)
- (when (fboundp 'copy-face)
- (copy-face 'default 'widget-documentation-face)
- (copy-face 'bold 'widget-button-face)
- (copy-face 'italic 'widget-field-face))
- (defvar widget-mouse-face 'highlight)
- (defvar widget-menu-max-size 40)))
+(unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
+ ;; We have the old custom-library, hack around it!
+ (defmacro defgroup (&rest args) nil)
+ (defmacro defcustom (&rest args) nil)
+ (defmacro defface (&rest args) nil)
+ (when (fboundp 'copy-face)
+ (copy-face 'default 'widget-documentation-face)
+ (copy-face 'bold 'widget-button-face)
+ (copy-face 'italic 'widget-field-face))
+ (defvar widget-mouse-face 'highlight)
+ (defvar widget-menu-max-size 40))
;;; Compatibility.
(let ((face (widget-apply widget :button-face-get)))
(add-text-properties from to (list 'button widget
'mouse-face widget-mouse-face
+ 'start-open t
+ 'end-open t
'face face))))
(defun widget-specify-doc (widget from to)
(intern value)
value)))
-(define-widget 'function 'symbol
+(define-widget 'function 'sexp
;; Should complete on functions.
"A lisp function."
:tag "Function")
value))
:match (lambda (widget value) (numberp value)))
-(define-widget 'hook 'sexp
- "A emacs lisp hook"
- :tag "Hook")
-
(define-widget 'list 'group
"A lisp list."
:tag "List"
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, extensions, faces, hypermedia
-;; Version: 0.993
+;; Version: 0.995
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
+Mon Oct 28 15:50:08 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Startup Variables): Addition.
+
+Fri Oct 25 09:04:59 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Summary Mail Commands): Addition.
+
+Wed Oct 23 08:28:29 1996 Hrvoje Niksic <hniksic@srce.hr>
+
+ * gnus.texi (Fancy Mail Splitting): Removed trailing garbage.
+
+Tue Oct 22 07:36:02 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Converting Kill Files): New.
+
+Sat Oct 19 07:17:28 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Saving Articles): Addition.
+
+ * message.texi (Various Message Variables): Addition.
+
+Thu Oct 17 06:53:04 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Contributors): Added names.
+
Fri Oct 11 12:38:59 1996 Lars Magne Ingebrigtsen <larsi@ylfing.ifi.uio.no>
* gnus.texi (Adaptive Scoring): Addition.
\input texinfo.tex
@c %**start of header
-@setfilename custom.info
+@setfilename custom
@settitle The Customization Library
@iftex
@afourpaper
@end iftex
@c %**end of header
+@menu
+* Introduction::
+* User Commands::
+* The Customization Buffer::
+* Declaring Groups::
+* Declaring Variables::
+* Declaring Faces::
+* The Init File::
+* Wishlist::
+@end menu
+
@node Top, Introduction, (dir), (dir)
@comment node-name, next, previous, up
@top The Customization Library
-Version: 0.9
+Version: 0.995
@menu
* Introduction::
Create a customization buffer containing a single variable.
@item customize-face
-Create a customization buffer contaning a single face.
+Create a customization buffer containing a single face.
@item customize-apropos
Create a customization buffer containing all variables, faces, and
groups that match a user specified regular expression.
@end table
-@node The Customization Buffer, Declaring Groups, User Commands, Top
+@node The Customization Buffer, Declaring Groups, User Commands, Top
@comment node-name, next, previous, up
@section The Customization Buffer.
-Here should be a description of how to use a customization buffer.
-For now, try to press @kbd{C-h m} in the buffer, or read @ref{User
-Interface,,widget,The Widget Library}.
+The customization buffer allows the user to make temporary or permanent
+changes to how specific aspects of emacs works, by setting and editing
+user options.
-The interface will change, as it currently stinks. Here is some hints
-about how to use it though:
+The customization buffer contains three types of text:
-@itemize @bullet
-@item
-Groups and user option start on a new line, and look like this
-@t{@b{name}:}. If you move point above to the @t{@b{name}} and press
-@kbd{@key{RET}}, or move the mouse pointer above it and press
-@kbd{mouse-2}, you will be presented with a menu. I call this the
-@dfn{tag menu} below.
+@table @dfn
+@item informative text
+where the normal editing commands are disabled.
+
+@item editable fields
+where you can edit with the usual emacs commands. Editable fields are
+usually displayed with a grey background if your terminal supports
+colors, or an italic font otherwise.
+
+@item buttons
+which can be activated by either pressing the @kbd{@key{ret}} while
+point is located on the text, or pushing @kbd{mouse-2} while the mouse
+pointer is above the tex. Buttons are usually displayed in a bold
+font.
+@end table
-@item
-For groups and faces, you need to activate @samp{Toggle Hide} from the
-tag menu to be able to see the content.
+You can move to the next the next editable field or button by pressing
+@kbd{@key{tab}} or the previous with @kbd{M-@key{tab}}. Some buttons
+have a small helpful message about their purpose, which will be
+displayed when you move to it with the @key{tab} key.
-@item
-After editing a variable or face, you must activate @samp{Apply} for the
-setting to take effect, and @samp{Set Default} for marking the widget
-value as the new default value.
+The buffer is divided into three part, an introductory text, a list of
+customization options, and a line of customization buttons. Each part
+will be described in the following.
-@item
-After setting new default values with @samp{Set Default}, you must
-activate the @samp{Save} button in the bottom of the screen to save the
-new defaults. Otherwise the new defaults will be silently forgotten.
+@menu
+* The Introductory Text::
+* The Customization Options::
+* The Variable Options::
+* The Face Options::
+* The Group Options::
+* The State Button::
+* The Customization Buttons::
+@end menu
-@item
-Pushing @samp{Save} is a no-op unless you have activated @samp{Set Default}
-for some user option.
+@node The Introductory Text, The Customization Options, The Customization Buffer, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Introductory Text
-@item
-The @code{face} widget never attempts to display the current value of a
-face. Instead it allows you to specify how the face should be
-initialized. This is done with a list of @dfn{display} and
-@dfn{attributes} pairs, where the first display that matches a frame
-specify the attributes to use for that frame.
-
-A display can either match all frames, or only frames with a given
-@dfn{type}, @dfn{class}, and @dfn{background}. The checkbox before each
-of these display parameters determine whether the parameter will be
-checked. If the checkbox before @samp{Type} is unchecked, the display
-will match all types of frames. If it is checked, it will match the
-type of frames specified on the rest of the line.
-
-The attributes are specified next. Each attribute line begins with a
-checkbox, if that checkbox is unchecked the face will not affect that
-particular attribute on the screen, otherwise the face will force the
-the text to have the value for attribute specified after the attrbute
-name. This means that an attribute like @samp{bold} in effect have
-three states: If the first checkmark is unchecked, the face will not
-affect the boldness of the text. If the first checkmark is checked, but
-the second is unchecked, the text will be forced to be unbold. If both
-checkmarks are checked, the text will be forced to be bold.
-
-Think about this, and mail me a suggestion for how to make the face
-widget more intuitive.
-@end itemize
+The start of the buffer contains a short explanation of what it is, and
+how to get help. It will typically look like this:
+
+@example
+This is a customization buffer.
+Push RET or click mouse-2 on the word _help_ for more information.
+@end example
+
+Rather boring. It is mostly just informative text, but the word
+@samp{help} is a button that will bring up this document when
+activated.
+
+@node The Customization Options, The Variable Options, The Introductory Text, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Customization Options
+
+Each customization option looks similar to the following text:
+
+@example
+ *** custom-background-mode: default
+ [ ] [?] The brightness of the background.
+@end example
+
+The option contains the parts described below.
+
+@table @samp
+@item ***
+The Level Button. The customization options in the buffer are organized
+in a hierarchy, which is indicated by the number of stars in the level
+button. The top level options will be shown as @samp{*}. When they are
+expanded, the suboptions will be shown as @samp{**}. The example option
+is thus a subsuboption.
+
+Activating the level buttons will toggle between hiding and exposing the
+content of that option. The content can either be the value of the
+option, as in this example, or a list of suboptions.
+
+@item custom-background-mode
+This is the tag of the the option. The tag is a name of a variable, a
+face, or customization group. Activating the tag has an effect that
+depends on the exact type of the option. In this particular case,
+activating the tag will bring up a menu that will allow you to choose
+from the three possible values of the `custom-background-mode'
+variable.
+
+@item default
+After the tag, the options value is shown. Depending on its type, you
+may be able to edit the value directly. If an option should contain a
+file name, it is displayed in an editable field, i.e. you can edit it
+using the standard emacs editing commands.
+
+@item [ ]
+The state button. This look of this button will indicate the state of
+the option, e.g. whether it is currently hidden, or whether it has been
+modified or not. Activating the button will allow you to change the
+state, e.g. apply or reset the changes you have made. This is explained
+in detail in the following sections.
+
+@item [?]
+The documentation button. If the documentation is more than one line,
+this button will be present. Activating the button will toggle whether
+the complete documentation is shown, or only the first line.
+
+@item The brightness of the background.
+This is a documentation string explaining the purpose of this particular
+customization option.
+
+@end table
+
+@node The Variable Options, The Face Options, The Customization Options, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Variable Options
+
+The most common customization options are emacs lisp variables. The
+actual editing of these variables depend on what type values the
+variable is expected to contain. For example, a lisp variable whose
+value should be a string will typically be represented with an editable
+text field in the buffer, where you can change the string directly. If
+the value is a list, each item in the list will be presented in the
+buffer buffer on a separate line, with buttons to insert new items in
+the list, or delete existing items from the list. You may want to see
+@ref{User Interface,,, widget, The Widget Library}, where some examples
+of editing are discussed.
+
+You can either choose to edit the value directly, or edit the default
+value for that variable. The default value is a lisp expression that
+will be evaluated when you start emacs. The result of the evaluation
+will be used as the initial value for that variable. Editing the
+default value is for experts only, but if the current value of the
+variable is of a wrong type (i.e. a symbol where a string is expected),
+the `edit default' mode will always be selected.
+
+You can see what mode is currently selected by looking at the state
+button. If it uses parenthesises (like @samp{( )}) it is in `Edit
+default' mode, with square brackets (like @samp{[ ]}) it is normal edit
+mode. You can switch mode by activating the state button, and select
+either @samp{Edit} or @samp{Edit default} from the menu.
+
+You can change the state of the variable with the other menu items:
+
+@table @samp
+@item Apply
+When you have made your modifications in the buffer, you need to
+activate this item to make the modifications take effect. The
+modifications will be forgotten next time you run emacs.
+
+@item Set Default
+Unless you activate this item instead! This will mark the modification
+as permanent, i.e. the changes will be remembered in the next emacs
+session.
+
+@item Reset
+If you have made some modifications and not yet applied them, you can
+undo the modification by activating this item.
+
+@item Reset to Default
+Activating this item will reset the value of the variable to the last
+value you marked as permanent with `Set Default'.
+
+@item Reset to Factory Settings
+Activating this item will undo all modifications you have made, and
+reset the value to the initial value specified by the program itself.
+@end table
+
+By default, the value of large or complicated variables are hidden. You
+can show the value by clicking on the level button.
+
+@node The Face Options, The Group Options, The Variable Options, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Face Options
+
+A face is an object that controls the appearance of some buffer text.
+The face has a number of possible attributes, such as boldness,
+foreground color, and more. For each attribute you can specify whether
+this attribute is controlled by the face, and if so, what the value is.
+For example, if the attribute bold is not controlled by a face, using
+that face on some buffer text will not affect its boldness. If the bold
+attribute is controlled by the face, it can be turned either on or of.
+
+It is possible to specify that a face should have different attributes
+on different device types. For example, a face may make text red on a
+color device, and bold on a monochrome device.
+
+The way this is presented in the customization buffer is to have a list
+of display specifications, and for each display specification a list of
+face attributes. For each face attribute, there is a checkbox
+specifying whether this attribute has effect and what the value is.
+Here is an example:
+
+@example
+ *** custom-invalid-face: (sample)
+ [ ] Face used when the customize item is invalid.
+ [INS] [DEL] Display: [ ] Type: [ ] X [ ] TTY
+ [X] Class: [X] Color [ ] Grayscale [ ] Monochrome
+ [ ] Background: [ ] Light [ ] Dark
+ Attributes: [ ] Bold: off
+ [ ] Italic: off
+ [ ] Underline: off
+ [X] Foreground: yellow (sample)
+ [X] Background: red (sample)
+ [ ] Stipple:
+ [INS] [DEL] Display: all
+ Attributes: [X] Bold: on
+ [X] Italic: on
+ [X] Underline: on
+ [ ] Foreground: default (sample)
+ [ ] Background: default (sample)
+ [ ] Stipple:
+ [INS]
+@end example
+
+This has two display specifications. The first will match all color
+displays, independently on whether the device is X11 or a tty, and
+whether background color is dark or light. For devices matching this
+specification, @samp{custom-invalid-face} will force text to be
+displayed in yellow on red, but leave all other attributes alone.
+
+The second display will simply match everything. Since the list is
+prioritised, this means that it will match all non-color displays. For
+these, the face will not affect the foreground or background color, but
+force the font to be both bold, italic, and underline.
+
+You can add or delete display specifications by activating the
+@samp{[INS]} and @samp{[DEL]} buttons, and modify them by clicking on
+the check boxes. The first checkbox in each line in the display
+specification is special. It specify whether this particular property
+will even be relevant. By not checking the box in the first display, we
+match all device types, also device types other than X11 and tty, for
+example ms-windows, nextstep, and mac os.
+
+After modifying the face, you can activate the state button to make the
+changes take effect. The menu items in the state button menu is similar
+to the state menu items for variables described in the previous section.
+
+@node The Group Options, The State Button, The Face Options, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Group Options
+
+Since Emacs has approximately a zillion configuration options, they have
+been organized in groups. Each group can contain other groups, thus
+creating a customization hierarchy. The nesting of the customization
+within the visible part of this hierarchy is indicated by the number of
+stars in the level button.
+
+Since there is really no customization needed for the group itself, the
+menu items in the groups state button will affect all modified group
+members recursively. Thus, if you activate the @samp{Apply} menu item,
+all variables and faces that have been modified and belong to that group
+will be applied. For those members that themselves are groups, it will
+work as if you had activated the @samp{Apply} menu item on them as well.
+
+@node The State Button, The Customization Buttons, The Group Options, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The State Button
+
+The state button has two purposes. The first is to hold the state menu,
+as described in the previous sections. The second is to indicate the
+state of each customization item. This is done by the character inside
+the brackets. The following states have been defined, the first that
+applies to the current item will be used:
+
+@table @samp
+@item -
+The option is currently hidden. For group options that means the
+members are not shown, for variables and faces that the value is not
+shown. You cannot perform any of the state change operations on a
+hidden customization option.
+
+@item *
+The value if this option has been modified in the buffer, but not yet
+applied.
+
+@item +
+The current value of this option is different from the default value.
+
+@item !
+The default value of this option is different from the factory setting.
+
+@item @@
+The factory setting of this option is not known. This occurs when you
+try to customize variables or faces that have not been explicitly
+declared as customizable.
+
+@item SPC
+The factory setting is still in effect.
+
+@end table
+
+For non-hidden group options, the state shown is the most severe state
+of its members, where more severe means that it appears earlier in the
+list above (except hidden members, which are ignored).
+
+@node The Customization Buttons, , The State Button, The Customization Buffer
+@comment node-name, next, previous, up
+@subsection The Customization Buttons
+
+The last part of the customization buffer looks like this:
+
+@example
+[Apply] [Set Default] [Reset] [Save]
+@end example
+
+Activating the @samp{[Apply]}, @samp{[Set Default]}, or @samp{[Reset]}
+button will affect all modified customization items that are visible in
+the buffer.
+
+Activating the @samp{[Save]} button will ensure that all customization
+options who are marked as persistent with @samp{Set default} (either
+with the button at the end of the buffer, or with any of the state
+button menus), will actually be saved in your initialization file.
@node Declaring Groups, Declaring Variables, The Customization Buffer, Top
@comment node-name, next, previous, up
Use @code{defgroup} to declare new customization groups.
-@defun defgroup symbol members [keyword value]... doc
+@defun defgroup symbol members doc [keyword value]...
Declare @var{symbol} as a customization group containing @var{members}.
@var{symbol} does not need to be quoted.
+@var{doc} is the group documentation.
+
@var{members} should be an alist of the form ((@var{name}
@var{widget})...) where @var{name} is a symbol and @var{widget} is a
widget for editing that symbol. Useful widgets are
@code{custom-variable} for editing variables, @code{custom-face} for
editing faces, and @code{custom-group} for editing groups.@refill
-@var{doc} is the group documentation.
-
The following @var{keyword}'s are defined:
@table @code
Use @code{defcustom} to declare user editable variables.
-@defun defcustom symbol [keyword value]... doc
+@defun defcustom symbol value doc [keyword value]...
Declare @var{symbol} as a customizable variable that defaults to @var{value}.
Neither @var{symbol} nor @var{value} needs to be quoted.
If @var{symbol} is not already bound, initialize it to @var{value}.
@table @code
@item :type
-@var{value} should be a sexp widget.
+@var{value} should be a widget type.
+@item :options
+@var{value} should be a list of possible members of the specified type.
+For hooks, this is a list of function names.
@item :group
@var{value} should be a customization group.
Add @var{symbol} to that group.
@end table
-@xref{Sexp Types,,widget,The Widget Library}, for information about
+@xref{Sexp Types,,,widget,The Widget Library}, for information about
widgets to use together with the @code{:type} keyword.
@end defun
Faces are declared with @code{defface}.
-@defun defface FACE SPEC [KEYWORD VALUE]... DOC
+@defun defface face spec doc [keyword value]...
Declare @var{face} as a customizable face that defaults to @var{spec}.
@var{face} does not need to be quoted.
@itemize @bullet
@item
-The names of the menu items for the @code{custom-variable},
-@code{custom-face}, and @code{custom-group} tags should be rethought.
-Some of the actions may be better placed as buttons in the buffer.
-
-@item
-The menu items above should be grayed out when the information is
+The menu items should be grayed out when the information is
missing. I.e. if a variable doesn't have a factory setting, the user
should not be allowed to select the @samp{Factory} menu item.
We need @strong{much} better support for keyboard operations in the
customize buffer.
-@item
-There should be buttons that will apply, set, reset, etc. all the relevant
-widgets in a customize buffer.
-
-@item
-There should be a menu in the customize buffer.
-
-@item
-The group widget should allow you to apply, set, reset, etc. all the
-relevant members of the group.
-
@item
There should be a function to create a customize menu from a group.
Support real specifiers under XEmacs.
@item
-@code{customize-apropos} should only match user options that has either
-been declared with this library, or variables whose documentation start
-with @samp{*}. With an prefix argument, also match all variables that
-has a documentation string.
-
-@item
-If there is only one line of documentation, the @samp{Documentation}
-tag-menu items should go from `first line only' to `none' without going
-over `full'. I.e. it should have two states instead of three.
-
-@item
-@code{custom-face} should display the @code{face-documentation}
-property.
+Integrate with @file{w3} so you can customization buffers with much
+better formatting. I'm thinking about adding a <custom>name</custom>
+tag.
@item
-@code{custom-face}, @code{custom-variable}, and @code{custom-group}
-should be derived from a common @code{custom} widget.
+Try to keep track of whether it is necessary to save or not.
@item
-Integrate with @file{w3} so you can customization buffers with much
-better formatting. I'm thinking about adding a <custom>name</custom>
-tag.
+Offer to save if you exit emacs with unsaved customizations.
@end itemize
\input texinfo @c -*-texinfo-*-
@setfilename gnus
-@settitle Red Gnus 0.52 Manual
+@settitle Red Gnus 0.53 Manual
@synindex fn cp
@synindex vr cp
@synindex pg cp
@tex
@titlepage
-@title Red Gnus 0.52 Manual
+@title Red Gnus 0.53 Manual
@author by Lars Magne Ingebrigtsen
@page
@item gnus-inhibit-startup-message
@vindex gnus-inhibit-startup-message
If non-@code{nil}, the startup message won't be displayed. That way,
-your boss might not notice as easily that you are reading news instead of doing
-your job.
+your boss might not notice as easily that you are reading news instead
+of doing your job. Note that this variable is used before
+@file{.gnus.el} is loaded, so it should be set in @code{.emacs} instead.
@item gnus-no-groups-message
@vindex gnus-no-groups-message
Message displayed by Gnus when no groups are available.
+
+@item gnus-play-startup-jingle
+@vindex gnus-play-startup-jingle
+If non-@code{nil}, play the Gnus jingle at startup.
+
+@item gnus-startup-jingle
+@vindex gnus-startup-jingle
+Jingle to be played if the above variable is non-@code{nil}. The
+default is @samp{Tuxedomoon.Jingle4.au}.
+
@end table
@kindex S o m (Summary)
@findex gnus-summary-mail-forward
Forward the current article to some other person
-(@code{gnus-summary-mail-forward}).
+(@code{gnus-summary-mail-forward}). If given a prefix, include the full
+headers of the forwarded article.
@item S m
@itemx m
@kindex S o p (Summary)
@findex gnus-summary-post-forward
Forward the current article to a newsgroup
-(@code{gnus-summary-post-forward}).
+(@code{gnus-summary-post-forward}). If given a prefix, include the full
+headers of the forwarded article.
@item S O p
@kindex S O p (Summary)
Save the current article in plain file format
(@code{gnus-summary-save-article-file}).
+@item O F
+@kindex O F (Summary)
+@findex gnus-summary-write-article-file
+Write the current article in plain file format, overwriting any previous
+file contents (@code{gnus-summary-write-article-file}).
+
@item O b
@kindex O b (Summary)
@findex gnus-summary-save-article-body-file
;; People...
(any "larsi@@ifi\\.uio\\.no" "people.Lars Magne Ingebrigtsen"))
;; Unmatched mail goes to the catch all group.
- "misc.misc"))")
+ "misc.misc")
@end lisp
This variable has the format of a @dfn{split}. A split is a (possibly)
* Reverse Scoring:: That problem child of old is not problem.
* Global Score Files:: Earth-spanning, ear-splitting score files.
* Kill Files:: They are still here, but they can be ignored.
+* Converting Kill Files:: Translating kill files to score files.
* GroupLens:: Getting predictions on what you like to read.
* Advanced Scoring:: Using logical expressions to build score rules.
* Score Decays:: It can be useful to let scores wither away.
@end table
+@node Converting Kill Files
+@section Converting Kill Files
+@cindex kill files
+@cindex converting kill files
+
+If you have loads of old kill files, you may want to convert them into
+score files. If they are ``regular'', you can use
+the @file{gnus-kill-to-score.el} package; if not, you'll have to do it
+by hand.
+
+The kill to score conversion package isn't included in Gnus by default.
+You can fetch it from
+@file{http://www.ifi.uio.no/~larsi/ding-other/gnus-kill-to-score}.
+
+If your old kill files are very complex---if they contain more
+non-@code{gnus-kill} forms than not, you'll have to convert them by
+hand. Or just let them be as they are. Gnus will still use them as
+before.
+
+
@node GroupLens
@section GroupLens
@cindex GroupLens
On July 28th 1996 work on Red Gnus was begun.
+If you happen upon a version of Gnus that has a name that is prefixed --
+``(ding) Gnus'', ``September Gnus'', ``Red Gnus'', ``Mamey Sapote Gnus''
+-- don't panic. Don't let it know that you're frightened. Back away.
+Slowly. Whatever you do, don't run. Walk away, calmly, until you're
+out of its reach. Find a proper released version of Gnus and snuggle up
+to that instead.
+
@menu
* Why?:: What's the point of Gnus?
* Compatibility:: Just how compatible is Gnus with @sc{gnus}?
@item
Luis Fernandes---design and graphics.
+@item
+Erik Naggum---help, ideas, support, code and stuff.
+
@item
Wes Hardaker---@file{gnus-picon.el} and the manual section on
@dfn{picons} (@pxref{Picons}).
Marc Auslander,
Mark Borges,
Lance A. Brown,
+Kees de Bruin,
Martin Buchholz,
+Kevin Buhr,
Alastair Burt,
Joao Cachopo,
Massimo Campostrini,
-Michael Cook,
+Michael R. Cook,
Glenn Coombs,
Frank D. Cringle,
Geoffrey T. Dairiki,
Ulrik Dickow,
Dave Disser,
+Joev Dubach,
Paul Eggert,
Michael Ernst,
Luc Van Eycken,
Ishikawa Ichiro, @c Ishikawa
Francois Felix Ingrand,
Lee Iverson,
+Randell Jesup,
Fred Johansen,
Thor Kristoffersen,
Jens Lautenbacher,
+Carsten Leonhardt,
Christian Limpach,
+Tonny Madsen,
+Shlomo Mahlab,
Nat Makarevitch,
Timo Metzemakers,
Richard Mlynarik,
+David Moore,
Lantz Moore,
Morioka Tomohiko, @c Morioka
Hrvoje Niksic,
Andy Norman,
+Alexandre Oliva,
Ken Olstad,
Masaharu Onishi, @c Onishi
Hideki Ono, @c Ono
+William Perry,
+Stephen Peters,
Ulrich Pfeifer,
Colin Rafferty,
Bart Robinson,
@menu
* ding Gnus:: New things in Gnus 5.0/5.1, the first new Gnus.
* September Gnus:: The Thing Formally Known As Gnus 5.3/5.3.
-* Red Gnus:: The future.
+* Red Gnus:: The future---Gnus 5.4/5.5.
@end menu
These lists are, of course, just @emph{short} overviews of the
--- /dev/null
+\input texinfo @c -*-texinfo-*-
+
+@setfilename message
+@settitle Message Manual
+@synindex fn cp
+@synindex vr cp
+@synindex pg cp
+@iftex
+@finalout
+@end iftex
+@setchapternewpage odd
+
+@ifinfo
+
+This file documents Messa, the Emacs message composition mode.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@tex
+
+@titlepage
+@title Message Manual
+
+@author by Lars Magne Ingebrigtsen
+@page
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1996 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+
+@end titlepage
+@page
+
+@end tex
+
+@node Top
+@top Message
+
+All message composition (both mail and news) takes place in Message mode
+buffers.
+
+@menu
+* Interface:: Setting up message buffers.
+* Commands:: Commands you can execute in message mode buffers.
+* Variables:: Customizing the message buffers.
+* Index:: Variable, function and concept index.
+* Key Index:: List of Message mode keys.
+@end menu
+
+
+@node Interface
+@chapter Interface
+
+When a program (or a person) wants to respond to a message -- reply,
+follow up, forward, cancel -- the program (or person) should just put
+point in the buffer where the message is and call the required command.
+@code{Message} will then pop up a new @code{message} mode buffer with
+appropriate headers filled out, and the user can edit the message before
+sending it.
+
+@menu
+* New Mail Message:: Editing a brand new mail message.
+* New News Message:: Editing a brand new news message.
+* Reply:: Replying via mail.
+* Wide Reply:: Responding to all people via mail.
+* Followup:: Following up via news.
+* Canceling News:: Canceling a news article.
+* Superseding:: Superseding a message.
+* Forwarding:: Forwarding a message via news or mail.
+* Resending:: Resending a mail message.
+* Bouncing:: Bouncing a mail message.
+@end menu
+
+
+@node New Mail Message
+@section New Mail Message
+
+@findex message-mail
+The @code{message-mail} command pops up a new message buffer.
+
+Two optional parameters are accepted: The first will be used as the
+@code{To} header and the second as the @code{Subject} header. If these
+aren't present, those two headers will be empty.
+
+
+@node New News Message
+@section New News Message
+
+@findex message-news
+The @code{message-news} command pops up a new message buffer.
+
+This function accepts two optional parameters. The first will be used
+as the @code{Newsgroups} header and the second as the @code{Subject}
+header. If these aren't present, those two headers will be empty.
+
+
+@node Reply
+@section Reply
+
+@findex message-reply
+The @code{message-reply} function pops up a message buffer that's a
+reply to the message in the current buffer.
+
+@vindex message-reply-to-function
+Message uses the normal methods to determine where replies are to go,
+but you can change the behavior to suit your needs by fiddling with the
+@code{message-reply-to-function} variable.
+
+If you want the replies to go to the @code{Sender} instead of the
+@code{From}, you could do something like this:
+
+@lisp
+(setq message-reply-to-function
+ (lambda ()
+ (cond ((equal (mail-fetch-field "from") "somebody")
+ (mail-fetch-field "sender"))
+ (t
+ nil))))
+@end lisp
+
+This function will be called narrowed to the head of the article that is
+being replied to.
+
+As you can see, this function should return a string if it has an
+opinion as to what the To header should be. If it does not, it should
+just return @code{nil}, and the normal methods for determining the To
+header will be used.
+
+This function can also return a list. In that case, each list element
+should be a cons, where the car should be the name of an header
+(eg. @code{Cc}) and the cdr should be the header value
+(eg. @samp{larsi@@ifi.uio.no}). All these headers will be inserted into
+the head of the outgoing mail.
+
+
+@node Wide Reply
+@section Wide Reply
+
+@findex message-wide-reply
+The @code{message-wide-reply} pops up a message buffer that's a wide
+reply to the message in the current buffer. A @dfn{wide reply} is a
+reply that goes out to all people listed in the @code{To}, @code{From}
+and @code{Cc} headers.
+
+@vindex message-wide-reply-to-function
+Message uses the normal methods to determine where wide replies are to go,
+but you can change the behavior to suit your needs by fiddling with the
+@code{message-wide-reply-to-function}. It is used in the same way as
+@code{message-reply-to-function} (@pxref{Reply}).
+
+@findex rmail-dont-reply-to-names
+Addresses that matches the @code{rmail-dont-reply-to-names} regular
+expression will be removed from the @code{Cc} header.
+
+
+@node Followup
+@section Followup
+
+@findex message-followup
+The @code{message-followup} command pops up a message buffer that's a
+followup to the message in the current buffer.
+
+@vindex message-followup-to-function
+Message uses the normal methods to determine where followups are to go,
+but you can change the behavior to suit your needs by fiddling with the
+@code{message-followup-to-function}. It is used in the same way as
+@code{message-reply-to-function} (@pxref{Reply}).
+
+@vindex message-use-followup-to
+The @code{message-use-followup-to} variable says what to do about
+@code{Followup-To} headers. If it is @code{use}, always use the value.
+If it is @code{ask} (which is the default), ask whether to use the
+value. If it is @code{t}, use the value unless it is @samp{poster}. If
+it is @code{nil}, don't use the value.
+
+
+@node Canceling News
+@section Canceling News
+
+@findex message-cancel-news
+The @code{message-cancel-news} command cancels the article in the
+current buffer.
+
+
+@node Superseding
+@section Superseding
+
+@findex message-supersede
+The @code{message-supersede} command pops up a message buffer that will
+supersede the message in the current buffer.
+
+@vindex message-ignored-supersedes-headers
+Headers matching the @code{message-ignored-supersedes-headers} are
+removed before popping up the new message buffer. The default is
+@samp{^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|Return-Path:}.
+
+
+
+@node Forwarding
+@section Forwarding
+
+@findex message-forward
+The @code{message-forward} command pops up a message buffer to forward
+the message in the current buffer. If given a prefix, forward using
+news.
+
+@table @code
+@item message-forward-start-separator
+@vindex message-forward-start-separator
+Delimiter inserted before forwarded messages. The default is
+@samp{------- Start of forwarded message -------\n}.
+
+@vindex message-forward-end-separator
+@item message-forward-end-separator
+@vindex message-forward-end-separator
+Delimiter inserted after forwarded messages. The default is
+@samp{------- End of forwarded message -------\n}.
+
+@item message-signature-before-forwarded-message
+@vindex message-signature-before-forwarded-message
+If this variable is @code{t}, which it is by default, your personal
+signature will be inserted before the forwarded message. If not, the
+forwarded message will be inserted first in the new mail.
+
+@item message-included-forward-headers
+@vindex message-included-forward-headers
+Regexp matching header lines to be included in forwarded messages.
+
+@end table
+
+
+@node Resending
+@section Resending
+
+@findex message-resend
+The @code{message-resend} command will prompt the user for an address
+and resend the message in the current buffer to that address.
+
+@vindex message-ignored-resent-headers
+Headers the match the @code{message-ignored-resent-headers} regexp will
+be removed before sending the message. The default is
+@samp{^Return-receipt}.
+
+
+@node Bouncing
+@section Bouncing
+
+@findex message-bounce
+The @code{message-bounce} command will, if the current buffer contains a
+bounced mail message, pop up a message buffer stripped of the bounce
+information. A @dfn{bounced message} is typically a mail you've sent
+out that has been returned by some @code{mailer-daemon} as
+undeliverable.
+
+@vindex message-ignored-bounced-headers
+Headers that match the @code{message-ignored-bounced-headers} regexp
+will be removed before popping up the buffer. The default is
+@samp{^Received:}.
+
+
+@node Commands
+@chapter Commands
+
+@menu
+* Header Commands:: Commands for moving to headers.
+* Movement:: Moving around in message buffers.
+* Insertion:: Inserting things into message buffers.
+* Various Commands:: Various things.
+* Sending:: Actually sending the message.
+@end menu
+
+
+@node Header Commands
+@section Header Commands
+
+All these commands move to the header in question. If it doesn't exist,
+it will be inserted.
+
+@table @kbd
+
+@item C-c ?
+@kindex C-c ?
+@findex message-goto-to
+Describe the message mode.
+
+@item C-c C-f C-t
+@kindex C-c C-f C-t
+@findex message-goto-to
+Go to the @code{To} header (@code{message-goto-to}).
+
+@item C-c C-f C-b
+@kindex C-c C-f C-b
+@findex message-goto-bcc
+Go to the @code{Bcc} header (@code{message-goto-bcc}).
+
+@item C-c C-f C-f
+@kindex C-c C-f C-f
+@findex message-goto-fcc
+Go to the @code{Fcc} header (@code{message-goto-fcc}).
+
+@item C-c C-f C-c
+@kindex C-c C-f C-c
+@findex message-goto-cc
+Go to the @code{Cc} header (@code{message-goto-cc}).
+
+@item C-c C-f C-s
+@kindex C-c C-f C-s
+@findex message-goto-subject
+Go to the @code{Subject} header (@code{message-goto-subject}).
+
+@item C-c C-f C-r
+@kindex C-c C-f C-r
+@findex message-goto-reply-to
+Go to the @code{Reply-To} header (@code{message-goto-reply-to}).
+
+@item C-c C-f C-n
+@kindex C-c C-f C-n
+@findex message-goto-newsgroups
+Go to the @code{Newsgroups} header (@code{message-goto-newsgroups}).
+
+@item C-c C-f C-d
+@kindex C-c C-f C-d
+@findex message-goto-distribution
+Go to the @code{Distribution} header (@code{message-goto-distribution}).
+
+@item C-c C-f C-o
+@kindex C-c C-f C-o
+@findex message-goto-followup-to
+Go to the @code{Followup-To} header (@code{message-goto-followup-to}).
+
+@item C-c C-f C-k
+@kindex C-c C-f C-k
+@findex message-goto-keywords
+Go to the @code{Keywords} header (@code{message-goto-keywords}).
+
+@item C-c C-f C-u
+@kindex C-c C-f C-u
+@findex message-goto-summary
+Go to the @code{Summary} header (@code{message-goto-summary}).
+
+@end table
+
+
+@node Movement
+@section Movement
+
+@table @kbd
+@item C-c C-b
+@kindex C-c C-b
+@findex message-goto-body
+Move to the beginning of the body of the message
+(@code{message-goto-body}).
+
+@item C-c C-i
+@kindex C-c C-i
+@findex message-goto-signature
+Move to the signature of the message (@code{message-goto-signature}).
+
+@end table
+
+
+@node Insertion
+@section Insertion
+
+@table @kbd
+
+@item C-c C-y
+@kindex C-c C-y
+@findex message-yank-original
+Yank the message that's being replied to into the message buffer
+(@code{message-yank-original}).
+
+@item C-c C-q
+@kindex C-c C-q
+@findex message-fill-yanked-message
+Fill the yanked message (@code{message-fill-yanked-message}).
+
+@item C-c C-w
+@kindex C-c C-w
+@findex message-insert-signature
+Insert a signature at the end of the buffer
+(@code{message-insert-signature}).
+
+@end table
+
+@table @code
+@item message-ignored-cited-headers
+@vindex message-ignored-cited-headers
+All headers that match this regexp will be removed from yanked
+messages. The default is @samp{.}, which means that all headers will be
+removed.
+
+@item message-citation-line-function
+@vindex message-citation-line-function
+Function called to insert the citation line. The default is
+@code{message-insert-citation-line}.
+
+@item message-yank-prefix
+@vindex message-yank-prefix
+@cindex yanking
+@cindex quoting
+When you are replying to or following up an article, you normally want
+to quote the person you are answering. Inserting quoted text is done by
+@dfn{yanking}, and each quoted line you yank will have
+@code{message-yank-prefix} prepended to it. The default is @samp{> }.
+If it is @code{nil}, just indent the message.
+
+@item message-indentation-spaces
+@vindex message-indentation-spaces
+Number of spaces to indent yanked messages.
+
+@item message-cite-function
+@vindex message-cite-function
+@findex message-cite-original
+@findex sc-cite-original
+@cindex Supercite
+Function for citing an original message. The default is
+@code{message-cite-original}. You can also set it to
+@code{sc-cite-original} to use Supercite.
+
+@item message-indent-citation-function
+@vindex message-indent-citation-function
+Function for modifying a citation just inserted in the mail buffer.
+This can also be a list of functions. Each function can find the
+citation between @code{(point)} and @code{(mark t)}. And each function
+should leave point and mark around the citation text as modified.
+
+@item message-signature
+@vindex message-signature
+String to be inserted at the end of the message buffer. If @code{t}
+(which is the default), the @code{message-signature-file} file will be
+inserted instead. If a function, the result from the function will be
+used instead. If a form, the result from the form will be used instead.
+If this variable is @code{nil}, no signature will be inserted at all.
+
+@item message-signature-file
+@vindex message-signature-file
+File containing the signature to be inserted at the end of the buffer.
+The default is @samp{~/.signature}.
+
+@end table
+
+Note that RFC1036 says that a signature should be preceded by the three
+characters @samp{-- } on a line by themselves. This is to make it
+easier for the recipient to automatically recognize and process the
+signature. So don't remove those characters, even though you might feel
+that they ruin you beautiful design, like, totally.
+
+Also note that no signature should be more than four lines long.
+Including ASCII graphics is an efficient way to get everybody to believe
+that you are silly and have nothing important to say.
+
+
+
+@node Various Commands
+@section Various Commands
+
+@table @kbd
+
+@item C-c C-r
+@kindex C-c C-r
+@findex message-caesar-buffer-body
+Caesar rotate (aka. rot13) the current message
+(@code{message-caesar-buffer-body}). If narrowing is in effect, just
+rotate the visible portion of the buffer. A numerical prefix says how
+many places to rotate the text. The default is 13.
+
+@item C-c C-t
+@kindex C-c C-t
+@findex message-insert-to
+Insert a @code{To} header that contains the @code{Reply-To} or
+@code{From} header of the message you're following up
+(@code{message-insert-to}).
+
+@item C-c C-n
+@kindex C-c C-n
+@findex message-insert-newsgroups
+Insert a @code{Newsgroups} header that reflects the @code{Followup-To}
+or @code{Newsgroups} header of the article you're replying to
+(@code{message-insert-newsgroups}).
+
+@item C-c M-r
+@kindex C-c M-r
+@findex message-rename-buffer
+Rename the buffer (@code{message-rename-buffer}). If given a prefix,
+prompt for a new buffer name.
+
+@end table
+
+
+@node Sending
+@section Sending
+
+@table @kbd
+@item C-c C-c
+@kindex C-c C-c
+@findex message-send-and-exit
+Send the message and bury the current buffer
+(@code{message-send-and-exit}).
+
+@item C-c C-s
+@kindex C-c C-s
+@findex message-send
+Send the message (@code{message-send}).
+
+@item C-c C-d
+@kindex C-c C-d
+@findex message-dont-send
+Bury the message buffer and exit (@code{message-dont-send}).
+
+@item C-c C-k
+@kindex C-c C-k
+@findex message-kill-buffer
+Kill the message buffer and exit (@code{message-kill-buffer}).
+
+@end table
+
+
+@node Variables
+@chapter Variables
+
+@menu
+* Message Headers:: General message header stuff.
+* Mail Headers:: Customizing mail headers.
+* Mail Variables:: Other mail variables.
+* News Headers:: Customizing news headers.
+* News Variables:: Other news variables.
+* Various Message Variables:: Other message variables.
+* Sending Variables:: Variables for sending.
+* Message Buffers:: How Message names its buffers.
+* Message Actions:: Actions to be performed when exiting.
+@end menu
+
+
+@node Message Headers
+@section Message Headers
+
+Message is quite aggressive on the message generation front. It has
+to be -- it's a combined news and mail agent. To be able to send
+combined messages, it has to generate all headers itself to ensure that
+mail and news copies of messages look sufficiently similar.
+
+@table @code
+
+@item message-generate-headers-first
+@vindex message-generate-headers-first
+If non-@code{nil}, generate all headers before starting to compose the
+message.
+
+@item message-from-style
+@vindex message-from-style
+Specifies how @code{From} headers should look. There are four legal
+values:
+
+@table @code
+@item nil
+Just the address -- @samp{king@@grassland.com}.
+
+@item parens
+@samp{king@@grassland.com (Elvis Parsley)}.
+
+@item angles
+@samp{Elvis Parsley <king@@grassland.com>}.
+
+@item default
+Look like @code{angles} if that doesn't require quoting, and
+@code{parens} if it does. If even @code{parens} requires quoting, use
+@code{angles} anyway.
+
+@end table
+
+@item message-deletable-headers
+@vindex message-deletable-headers
+Headers in this list that were previously generated by Message will be
+deleted before posting. Let's say you post an article. Then you decide
+to post it again to some other group, you naughty boy, so you jump back
+to the @code{*post-buf*} buffer, edit the @code{Newsgroups} line, and
+ship it off again. By default, this variable makes sure that the old
+generated @code{Message-ID} is deleted, and a new one generated. If
+this isn't done, the entire empire would probably crumble, anarchy would
+prevail, and cats would start walking on two legs and rule the world.
+Allegedly.
+
+@item message-default-headers
+@vindex message-default-headers
+This string is inserted at the end of the headers in all message
+buffers.
+
+@end table
+
+
+@node Mail Headers
+@section Mail Headers
+
+@table @code
+@item message-required-mail-headers
+@vindex message-required-mail-headers
+See @pxref{News Headers} for the syntax of this variable. It is
+@code{(From Date Subject (optional . In-Reply-To) Message-ID Lines
+(optional . X-Mailer))} by default.
+
+@item message-ignored-mail-headers
+@vindex message-ignored-mail-headers
+Regexp of headers to be removed before mailing. The default is
+@samp{^Gcc:\\|^Fcc:}.
+
+@item message-default-mail-headers
+@vindex message-default-mail-headers
+This string is inserted at the end of the headers in all message
+buffers that are initialized as mail.
+
+@end table
+
+
+@node Mail Variables
+@section Mail Variables
+
+@table @code
+@item message-send-mail-function
+@vindex message-send-mail-function
+Function used to send the current buffer as mail. The default is
+@code{message-send-mail-with-sendmail}. If you prefer using MH
+instead, set this variable to @code{message-send-mail-with-mh}.
+
+@end table
+
+
+@node News Headers
+@section News Headers
+
+@vindex message-required-news-headers
+@code{message-required-news-headers} a list of header symbols. These
+headers will either be automatically generated, or, if that's
+impossible, they will be prompted for. The following symbols are legal:
+
+@table @code
+
+@item From
+@cindex From
+@findex user-full-name
+@findex user-mail-address
+This required header will be filled out with the result of the
+@code{message-make-from} function, which depends on the
+@code{message-from-style}, @code{user-full-name},
+@code{user-mail-address} variables.
+
+@item Subject
+@cindex Subject
+This required header will be prompted for if not present already.
+
+@item Newsgroups
+@cindex Newsgroups
+This required header says which newsgroups the article is to be posted
+to. If it isn't present already, it will be prompted for.
+
+@item Organization
+@cindex organization
+This optional header will be filled out depending on the
+@code{message-user-organization} variable.
+@code{message-user-organization-file} will be used if that variable is
+@code{t}.
+
+@item Lines
+@cindex Lines
+This optional header will be computed by Message.
+
+@item Message-ID
+@cindex Message-ID
+@vindex mail-host-address
+@findex system-name
+@cindex Sun
+This required header will be generated by Message. A unique ID will be
+created based on date, time, user name and system name. Message will
+use @code{mail-host-address} as the fully qualified domain name (FQDN)
+of the machine if that variable is define. If not, it will use
+@code{system-name}, which doesn't report a FQDN on some machines --
+notably Suns.
+
+@item X-Newsreader
+@cindex X-Newsreader
+This optional header will be filled out according to the
+@code{message-newsreader} local variable.
+
+@item X-Mailer
+This optional header will be filled out according to the
+@code{message-mailer} local variable, unless there already is an
+@code{X-Newsreader} header present.
+
+@item In-Reply-To
+This optional header is filled out using the @code{Date} and @code{From}
+header of the article being replied.
+
+@item Expires
+@cindex Expires
+This extremely optional header will be inserted according to the
+@code{message-expires} variable. It is highly deprecated and shouldn't
+be used unless you know what you're doing.
+
+@item Distribution
+@cindex Distribution
+This optional header is filled out according to the
+@code{message-distribution-function} variable. It is a deprecated and
+much misunderstood header.
+
+@item Path
+@cindex path
+This extremely optional header should probably not ever be used.
+However, some @emph{very} old servers require that this header is
+present. @code{message-user-path} further controls how this
+@code{Path} header is to look. If is is @code{nil}, the the server name
+as the leaf node. If is is a string, use the string. If it is neither
+a string nor @code{nil}, use the user name only. However, it is highly
+unlikely that you should need to fiddle with this variable at all.
+@end table
+
+@findex yow
+@cindex Mime-Version
+In addition, you can enter conses into this list. The car of this cons
+should be a symbol. This symbol's name is the name of the header, and
+the cdr can either be a string to be entered verbatim as the value of
+this header, or it can be a function to be called. This function should
+return a string to be inserted. For instance, if you want to insert
+@code{Mime-Version: 1.0}, you should enter @code{(Mime-Version . "1.0")}
+into the list. If you want to insert a funny quote, you could enter
+something like @code{(X-Yow . yow)} into the list. The function
+@code{yow} will then be called without any arguments.
+
+If the list contains a cons where the car of the cons is
+@code{optional}, the cdr of this cons will only be inserted if it is
+non-@code{nil}.
+
+Other variables for customizing outgoing news articles:
+
+@table @code
+
+@item message-syntax-checks
+@vindex message-syntax-checks
+If non-@code{nil}, message will attempt to check the legality of the
+headers, as well as some other stuff, before posting. You can control
+the granularity of the check by adding or removing elements from this
+list. Legal elements are:
+
+@table @code
+@item subject-cmsg
+Check the subject for commands.
+@item sender
+@cindex Sender
+Insert a new @code{Sender} header if the @code{From} header looks odd.
+@item multiple-headers
+Check for the existence of multiple equal headers.
+@item sendsys
+@cindex sendsys
+Check for the existence of version and sendsys commands.
+@item message-id
+Check whether the @code{Message-ID} looks ok.
+@item from
+Check whether the @code{From} header seems nice.
+@item long-lines
+@cindex long lines
+Check for too long lines.
+@item control-chars
+Check for illegal characters.
+@item size
+Check for excessive size.
+@item new-text
+Check whether there is any new text in the messages.
+@item signature
+Check the length of the signature.
+@item approved
+@cindex approved
+Check whether the article has an @code{Approved} header, which is
+something only moderators should include.
+@item empty
+Check whether the article is empty.
+@item empty-headers
+Check whether any of the headers are empty.
+@item existing-newsgroups
+Check whether the newsgroups mentioned in the Newsgroups and
+Followup-To headers exist.
+@item valid-newsgroups
+Check whether the @code{Newsgroups} and @code{Followup-to} headers
+are valid syntactically.
+@item shorten-followup-to
+Check whether to add a @code{Followup-to} header to shorten the number
+of groups to post to.
+@end table
+
+All these conditions are checked by default.
+
+@item message-ignored-news-headers
+@vindex message-ignored-news-headers
+Regexp of headers to be removed before posting. The default is
+@samp{^NNTP-Posting-Host:\\|^Xref:\\|^Bcc:\\|^Gcc:\\|^Fcc:}.
+
+@item message-default-news-headers
+@vindex message-default-news-headers
+This string is inserted at the end of the headers in all message
+buffers that are initialized as news.
+
+@end table
+
+
+@node News Variables
+@section News Variables
+
+@table @code
+@item message-send-news-function
+@vindex message-send-news-function
+Function used to send the current buffer as news. The default is
+@code{message-send-news}.
+
+@item message-post-method
+@vindex message-post-method
+Method used for posting a prepared news message.
+
+@end table
+
+
+@node Various Message Variables
+@section Various Message Variables
+
+@table @code
+@item message-signature-separator
+@vindex message-signature-separator
+Regexp matching the signature separator. It is @samp{^-- *$} by
+default.
+
+@item mail-header-separator
+@vindex mail-header-separator
+String used to separate the headers from the body. It is @samp{--text
+follows this line--} by default.
+
+@item message-directory
+@vindex message-directory
+Directory used by many mailey things. The default is @file{~/Mail/}.
+
+@item message-autosave-directory
+@vindex message-autosave-directory
+Directory where message buffers will be autosaved to.
+
+@item message-signature-setup-hook
+@vindex message-signature-setup-hook
+Hook run when initializing the message buffer. It is run after the
+headers have been inserted but before the signature has been inserted.
+
+@item message-setup-hook
+@vindex message-setup-hook
+Hook run as the last thing when the message buffer has been initialized.
+
+@item message-header-setup-hook
+@vindex message-header-setup-hook
+Hook called narrowed to the headers after initializing the headers.
+
+@item message-send-hook
+@vindex message-send-hook
+Hook run before sending messages.
+
+@item message-send-mail-hook
+@vindex message-send-mail-hook
+Hook run before sending mail messages.
+
+@item message-send-news-hook
+@vindex message-send-news-hook
+Hook run before sending news messages.
+
+@item message-sent-hook
+@vindex message-sent-hook
+Hook run after sending messages.
+
+@item message-mode-syntax-table
+@vindex message-mode-syntax-table
+Syntax table used in message mode buffers.
+
+@end table
+
+
+
+@node Sending Variables
+@section Sending Variables
+
+@table @code
+
+@item message-fcc-handler-function
+@vindex message-fcc-handler-function
+A function called to save outgoing articles. This function will be
+called with the name of the file to store the article in. The default
+function is @code{rmail-output} which saves in Unix mailbox format.
+
+@item message-courtesy-message
+@vindex message-courtesy-message
+When sending combined messages, this string is inserted at the start of
+the mailed copy. If the string contains the format spec @samp{%s}, the
+newsgroups the article has been posted to will be inserted there. If
+this variable is @code{nil}, no such courtesy message will be added.
+The default value is @samp{"The following message is a courtesy copy of
+an article\nthat has been posted to %s as well.\n\n"}.
+
+@end table
+
+
+@node Message Buffers
+@section Message Buffers
+
+Message will generate new buffers with unique buffer names when you
+request a message buffer. When you send the message, the buffer isn't
+normally killed off. It's name is changed and a certain number of old
+message buffers are kept alive.
+
+@table @code
+@item message-generate-new-buffers
+@vindex message-generate-new-buffers
+If non-@code{nil}, generate new buffers. The default is @code{t}. If
+this is a function, call that function with three parameters: The type,
+the to address and the group name. (Any of these may be @code{nil}.)
+The function should return the new buffer name.
+
+@item message-max-buffers
+@vindex message-max-buffers
+This variable says how many old message buffers to keep. If there are
+more message buffers than this, the oldest buffer will be killed. The
+default is 10. If this variable is @code{nil}, no old message buffers
+will ever be killed.
+
+@item message-send-rename-function
+@vindex message-send-rename-function
+After sending a message, the buffer is renamed from, for instance,
+@samp{*reply to Lars*} to @samp{*sent reply to Lars*}. If you don't
+like this, set this variable to a function that renames the buffer in a
+manner you like. If you don't want to rename the buffer at all, you can
+say:
+
+@lisp
+(setq message-send-rename-function 'ignore)
+@end lisp
+
+@item message-kill-buffer-on-exit
+@findex message-kill-buffer-on-exit
+If non-@code{nil}, kill the buffer immediately on exit.
+
+@end table
+
+
+@node Message Actions
+@section Message Actions
+
+When Message is being used from a news/mail reader, the reader is likely
+to want to perform some task after the message has been sent. Perhaps
+return to the previous window configuration or mark an article as
+replied.
+
+@vindex message-kill-actions
+@vindex message-postpone-actions
+@vindex message-exit-actions
+@vindex message-send-actions
+The user may exit from the message buffer in various ways. The most
+common is @kbd{C-c C-c}, which sends the message and exits. Other
+possibilities are @kbd{C-c C-s} which just sends the message, @kbd{C-c
+C-d} which postpones the message editing and buries the message buffer,
+and @kbd{C-c C-k} which kills the message buffer. Each of these actions
+have lists associated with them that contains actions to be executed:
+@code{message-send-actions}, @code{message-exit-actions},
+@code{message-postpone-actions}, and @code{message-kill-actions}.
+
+Message provides a function to interface with these lists:
+@code{message-add-action}. The first parameter is the action to be
+added, and the rest of the arguments are which lists to add this action
+to. Here's an example from Gnus:
+
+@lisp
+ (message-add-action
+ `(set-window-configuration ,(current-window-configuration))
+ 'exit 'postpone 'kill)
+@end lisp
+
+This restores the Gnus window configuration when the message buffer is
+killed, postponed or exited.
+
+An @dfn{action} can be either a normal function; or a list where the
+@code{car} is a function and the @code{cdr} is the list of arguments; or
+a form to be @code{eval}ed.
+
+@node Index
+@chapter Index
+@printindex cp
+
+@node Key Index
+@chapter Key Index
+@printindex ky
+
+@summarycontents
+@contents
+@bye
+
+@c End:
\input texinfo.tex
-@c $Id: widget.texi,v 1.1 1996/09/22 12:07:55 steve Exp $
+@c $Id: widget.texi,v 1.2 1996/10/30 19:27:41 steve Exp $
@c %**start of header
-@setfilename widget.info
+@setfilename widget
@settitle The Emacs Widget Library
@iftex
@afourpaper
@comment node-name, next, previous, up
@top The Emacs Widget Library
-Version: 0.9
+Version: 0.995
@menu
* Introduction::
@item link
Areas of text with an associated action. Intended for hypertext links
embedded in text.
-@item push
+@item push-button
Like link, but intended for stand-alone buttons.
-@item field
+@item editable-field
An editable text field. It can be either variable or fixed length.
-@item choice
+@item menu-choice
Allows the user to choose one of multiple options from a menu, each
option is itself a widget. Only the selected option will be visible in
the buffer.
-@item radio
+@item radio-button-choice
Allows the user to choose one of multiple options by pushing radio
buttons. The options are implemented as widgets. All options will be
visible in the buffer.
@item item
-A simple constant widget intended to be used in the @code{choice} and
-@code{radio} widgets.
+A simple constant widget intended to be used in the @code{menu-choice} and
+@code{radio-button-choice} widgets.
@item choice-item
An button item only intended for use in choices. When pushed, the user
will be asked to select another option from the choice widget.
A simple @samp{on}/@samp{off} switch.
@item checkbox
A checkbox (@samp{[ ]}/@samp{[X]}).
-@item repeat
+@item editable-list
Create an editable list. The user can insert or delete items in the
list. Each list item is itself a widget.
@end table
For example, capitalizing all text from the middle of one field to the
middle of another field is prohibited.
-Editing text fields are created by the @code{field} widget.
+Editing text fields are created by the @code{editable-field} widget.
The editing text fields are highlighted with the
@code{widget-field-face} face, making them easy to find.
@item The Option Field Tags.
When you activate one of these buttons, you will be asked to choose
between a number of different options. This is how you edit an option
-field. Option fields are created by the @code{choice} widget. In
+field. Option fields are created by the @code{menu-choice} widget. In
the example, @samp{@b{Choose}} is an option field tag.
@item The @samp{@b{[INS]}} and @samp{@b{[DEL]}} buttons.
Activating these will insert or delete elements from a editable list.
-The list is created by the @code{repeat} widget.
+The list is created by the @code{editable-list} widget.
@item Embedded Buttons.
The @samp{@b{_other work_}} is an example of an embedded
button. Embedded buttons are not associated with a fields, but can serve
Activating one of these will convert it to the other. This is useful
for implementing multiple-choice fields. You can create it wit
@item The @samp{@b{( )}} and @samp{@b{(*)}} buttons.
-Only one radio button in a @code{radio} widget can be selected at any
+Only one radio button in a @code{radio-button-choice} widget can be selected at any
time. When you push one of the unselected radio buttons, it will be
selected and the previous selected radio button will become unselected.
@item The @samp{@b{[Apply Form]}} @samp{@b{[Reset Form]}} buttons.
-These are explicit buttons made with the @code{push} widget. The main
+These are explicit buttons made with the @code{push-button} widget. The main
difference from the @code{link} widget is that the buttons are intended
to be displayed more like buttons in a GUI, once Emacs grows powerful
enough.
@lisp
(require 'widget)
+(eval-when-compile
+ (require 'widget-edit))
+
(defvar widget-example-repeat)
(defun widget-example ()
(let ((inhibit-read-only t))
(erase-buffer))
(widget-insert "Here is some documentation.\n\nName: ")
- (widget-create 'field
+ (widget-create 'editable-field
:size 13
"My Name")
- (widget-create 'choice
+ (widget-create 'menu-choice
:tag "Choose"
:value "This"
:help-echo "Choose me, please!"
(widget-value widget)))
'(item :tag "This option" :value "This")
'(choice-item "That option")
- '(field :menu-tag "No option" "Thus option"))
+ '(editable-field :menu-tag "No option" "Thus option"))
(widget-insert "Address: ")
- (widget-create 'field
+ (widget-create 'editable-field
"Some Place\nIn some City\nSome country.")
(widget-insert "\nSee also ")
(widget-create 'link
"other work")
(widget-insert " for more information.\n\nNumbers: count to three below\n")
(setq widget-example-repeat
- (widget-create 'repeat
+ (widget-create 'editable-list
:entry-format "%i %d %v"
:notify (lambda (widget &rest ignore)
(let ((old (widget-get widget
(widget-put widget ':example-length new)
(message "You can count to %d." new))))
:value '("One" "Eh, two?" "Five!")
- '(field :value "three")))
+ '(editable-field :value "three")))
(widget-insert "\n\nSelect multiple:\n\n")
(widget-create 'checkbox t)
(widget-insert " This\n")
:notify (lambda (&rest ignore) (message "Tickle"))
t)
(widget-insert " Thus\n\nSelect one:\n\n")
- (widget-create 'radio
+ (widget-create 'radio-button-choice
:value "One"
:notify (lambda (widget &rest ignore)
- (message "You selected %s" (widget-value widget)))
+ (message "You selected %s"
+ (widget-value widget)))
'(item "One") '(item "Anthor One.") '(item "A Final One."))
(widget-insert "\n")
- (widget-create 'push
+ (widget-create 'push-button
:notify (lambda (&rest ignore)
(if (= (length (widget-value widget-example-repeat))
3)
(error "Three was the count!")))
"Apply Form")
(widget-insert " ")
- (widget-create 'push
+ (widget-create 'push-button
:notify (lambda (&rest ignore)
(widget-example))
"Reset Form")
@item %d
Insert the string specified by @code{:doc} here.
+@item %h
+Like @samp{%d}, with the following modifications: If the documentation
+string is more than one line, it will add a button which will toggle
+between showing only the first line, and showing the full text.
+Furthermore, if there is no @code{:doc} property in the widget, it will
+instead examine the @code{:documentation-property} property. If it is a
+lambda expression, it will be called with the widget's value as an
+argument, and the result will be used as the documentation text.
+
@item %t
Insert the string specified by @code{:tag} here, or the @code{princ}
representation of the value if there is no tag.
Message displayed whenever you move to the widget with either
@code{widget-forward} or @code{widget-backward}.
+@item :indent
+An integer indicating the absolute number of spaces to indent children
+of this widget.
+
+@item :offset
+An integer indicating how many extra spaces to add to the widget's
+grandchildren compared to this widget.
+
+@item :extra-offset
+An integer indicating how many extra spaces to add to the widget's
+children compared to this widget.
+
@item :notify
A function called each time the widget or a nested widget is changed.
The function is called with two or three arguments. The first argument
@item :menu-tag
Tag used in the menu when the widget is used as an option in a
-@code{choice} widget.
+@code{menu-choice} widget.
@item :menu-tag-get
Function used for finding the tag when the widget is used as an option
-in a @code{choice} widget. By default, the tag used will be either the
+in a @code{menu-choice} widget. By default, the tag used will be either the
@code{:menu-tag} or @code{:tag} property if present, or the @code{princ}
representation of the @code{:value} property if not.
@code{:error} property to a string explaining the error.
@item :parent
-The parent of a nested widget (e.g. a @code{choice} item or an element of a
-@code{repeat} widget).
+The parent of a nested widget (e.g. a @code{menu-choice} item or an element of a
+@code{editable-list} widget).
@end table
@menu
* link::
-* push::
-* field::
+* push-button::
+* editable-field::
* text::
-* choice::
-* radio::
+* menu-choice::
+* radio-button-choice::
* item::
* choice-item::
* toggle::
* checkbox::
* checklist::
-* repeat::
+* editable-list::
@end menu
-@node link, push, Basic Types, Basic Types
+@node link, push-button, Basic Types, Basic Types
@comment node-name, next, previous, up
@subsection The @code{link} Widget
property. The value should be a string, which will be inserted in the
buffer.
-@node push, field, link, Basic Types
+@node push-button, editable-field, link, Basic Types
@comment node-name, next, previous, up
-@subsection The @code{push} Widget
+@subsection The @code{push-button} Widget
Syntax:
@example
-TYPE ::= (push [KEYWORD ARGUMENT]... [ VALUE ])
+TYPE ::= (push-button [KEYWORD ARGUMENT]... [ VALUE ])
@end example
The @var{value}, if present, is used to initialize the @code{:value}
property. The value should be a string, which will be inserted in the
buffer.
-@node field, text, push, Basic Types
+@node editable-field, text, push-button, Basic Types
@comment node-name, next, previous, up
-@subsection The @code{field} Widget
+@subsection The @code{editable-field} Widget
Syntax:
@example
-TYPE ::= (field [KEYWORD ARGUMENT]... [ VALUE ])
+TYPE ::= (editable-field [KEYWORD ARGUMENT]... [ VALUE ])
@end example
The @var{value}, if present, is used to initialize the @code{:value}
@item :keymap
Keymap used in the editable field. @code{widget-keymap} will allow you
-to use normal editing commands, even if these has been supressed in the
+to use normal editing commands, even if these has been suppressed in the
current buffer.
+@item :hide-front-space
+@itemx :hide-rear-space
+In order to keep track of the editable field, emacs places an invisible
+space character in front of the field, and for fixed sized fields also
+in the rear end of the field. For fields that extent to the end of the
+line, the terminating linefeed serves that purpose instead.
+
+Emacs will try to make the spaces intangible when it is safe to do so.
+Intangible means that the cursor motion commands will skip over the
+character as if it didn't exist. This is safe to do when the text
+preceding or following the widget cannot possible change during the
+lifetime of the @code{editable-field} widget. The preferred way to tell
+Emacs this, is to add text to the @code{:format} property around the
+value. For example @code{:format "Tag: %v "}.
+
+You can overwrite the internal safety check by setting the
+@code{:hide-front-space} or @code{:hide-rear-space} properties to
+non-nil. This is not recommended. For example, @emph{all} text that
+belongs to a widget (i.e. is created from its @code{:format} string) will
+change whenever the widget changes its value.
+
@end table
-@node text, choice, field, Basic Types
+@node text, menu-choice, editable-field, Basic Types
@comment node-name, next, previous, up
@subsection The @code{text} Widget
-This is just like @code{field}, but intended for multiline text
+This is just like @code{editable-field}, but intended for multiline text
fields.
-@node choice, radio, text, Basic Types
+@node menu-choice, radio-button-choice, text, Basic Types
@comment node-name, next, previous, up
-@subsection The @code{choice} Widget
+@subsection The @code{menu-choice} Widget
Syntax:
@example
-TYPE ::= (choice [KEYWORD ARGUMENT]... TYPE ... )
+TYPE ::= (menu-choice [KEYWORD ARGUMENT]... TYPE ... )
@end example
The @var{type} arguments represents each possible choice. The widgets
Widget type used as a fallback when the value does not match any of the
specified @var{type} arguments.
+@item :case-fold
+Set this to nil if you don't want to ignore case when prompting for a
+choice through the minibuffer.
+
@item :children
A list whose car is the widget representing the currently chosen type in
the buffer.
The list of types.
@end table
-@node radio, item, choice, Basic Types
+@node radio-button-choice, item, menu-choice, Basic Types
@comment node-name, next, previous, up
-@subsection The @code{radio} Widget
+@subsection The @code{radio-button-choice} Widget
Syntax:
@example
-TYPE ::= (radio [KEYWORD ARGUMENT]... TYPE ... )
+TYPE ::= (radio-button-choice [KEYWORD ARGUMENT]... TYPE ... )
@end example
The @var{type} arguments represents each possible choice. The widgets
The list of types.
@end table
-You can add extra radio button items to a radio widget after it has been
-created with the function `widget-radio-add-item'.
+You can add extra radio button items to a @code{radio-button-choice}
+widget after it has been created with the function
+@code{widget-radio-add-item}.
@defun widget-radio-add-item widget type
-Add to radio widget @var{widget} a new radio button item of type @var{type}.
+Add to @code{radio-button-choice} widget @var{widget} a new radio button item of type
+@var{type}.
@end defun
-Please note that such items added after the radio widget has been
-created will @strong{not} be properly destructed when you call
-@code{widget-delete}.
+Please note that such items added after the @code{radio-button-choice}
+widget has been created will @strong{not} be properly destructed when
+you call @code{widget-delete}.
-@node item, choice-item, radio, Basic Types
+@node item, choice-item, radio-button-choice, Basic Types
@comment node-name, next, previous, up
@subsection The @code{item} Widget
TYPE ::= (checkbox [KEYWORD ARGUMENT]...)
@end example
-@node checklist, repeat, checkbox, Basic Types
+@node checklist, editable-list, checkbox, Basic Types
@comment node-name, next, previous, up
@subsection The @code{checklist} Widget
The list of types.
@end table
-@node repeat, , checklist, Basic Types
+@node editable-list, , checklist, Basic Types
@comment node-name, next, previous, up
-@subsection The @code{repeat} Widget
+@subsection The @code{editable-list} Widget
Syntax:
@example
-TYPE ::= ([KEYWORD ARGUMENT]... TYPE)
+TYPE ::= (editable-list [KEYWORD ARGUMENT]... TYPE)
@end example
The value is a list, where each member represent one widget of type
The following extra properties are recognized.
@table @code
-@item :indent
-Number of spaces inserted before each member of the list, except for the
-first.
-
@item :entry-format
This string will be inserted for each entry in the list.
The following @samp{%} escapes are available:
field.
The @code{sexp} widget takes the same keyword arguments as the
-@code{field} widget.
+@code{editable-field} widget.
@end deffn
@node atoms, composite, generic, Sexp Types
property and must be an expression of the same type as the widget.
I.e. the string widget can only be initialized with a string.
-All the atom widgets take the same keyword arguments as the @code{field}
+All the atom widgets take the same keyword arguments as the @code{editable-field}
widget.
@deffn Widget string
Allows you to edit a number in an editable field.
@end deffn
+@deffn Widget boolean
+Allows you to edit a boolean. In lisp this means a variable which is
+either nil meaning false, or non-nil meaning true.
+@end deffn
+
+
@node composite, , atoms, Sexp Types
@comment node-name, next, previous, up
@subsection Composite Sexp Widgets.
@deffn Widget cons
The value of a @code{cons} widget is a cons-cell where the car is the
value of the first component and the cdr is the value of the second
-coponent. There must be exactly two components.
+component. There must be exactly two components.
@end deffn
@deffn Widget lisp
-The value of a @code{cons} widget is a list containing the value of
+The value of a @code{lisp} widget is a list containing the value of
each of its component.
@end deffn
@deffn Widget vector
-The value of a @code{cons} widget is a vector containing the value of
+The value of a @code{vector} widget is a vector containing the value of
each of its component.
@end deffn
The above suffice for specifying fixed size lists and vectors. To get
variable length lists and vectors, you can use a @code{choice},
-@code{radio}, @code{checklist} or @code{repeat} widget together with the
-@code{:inline} keyword. If any component of a composite widget has the
-@code{:inline} keyword set, its value must be a list which will then be
-spliced into the composite. For example, to specify a list whose first
-element must be a file name, and whose remaining arguments should either
-by the symbol @code{t} or two files, you can use the following widget
-specification:
+@code{set} or @code{repeat} widgets together with the @code{:inline}
+keywords. If any component of a composite widget has the @code{:inline}
+keyword set, its value must be a list which will then be spliced into
+the composite. For example, to specify a list whose first element must
+be a file name, and whose remaining arguments should either by the
+symbol @code{t} or two files, you can use the following widget
+specification:
@example
(list file
hard to implement so instead of confuse you more by trying to explain it
here, I'll just suggest you meditate over it for a while.
+@deffn Widget choice
+Allows you to edit a sexp which may have one of fixed set of types. It
+is currently implemented with the @code{choice-menu} basic widget, and
+has a similar syntax.
+@end deffn
+
+@deffn Widget set
+Allows you to specify a type which must be a list whose elements all
+belong to given set. The elements of the list is not significant. This
+is implemented on top of the @code{checklist} basic widget, and has a
+similar syntax.
+@end deffn
+
+@deffn Widget repeat
+Allows you to specify a variable length list whose members are all of
+the same type. Implemented on top of the `editable-list' basic widget,
+and has a similar syntax.
+@end deffn
+
@node Widget Properties, Defining New Widgets, Sexp Types, Top
@comment node-name, next, previous, up
@section Properties
Function to handle unknown @samp{%} escapes in the format string. It
will be called with the widget and the escape character as arguments.
You can set this to allow your widget to handle non-standard escapes.
+
+You should end up calling @code{widget-default-format-handler} to handle
+unknown escape sequences, which will handle the @samp{%h} and any future
+escape sequences, as well as give an error for unknown escapes.
@end table
If you want to define a new widget from scratch, use the @code{default}
@deffn Widget default [ keyword argument ]
Widget used as a base for other widgets.
-It provides most of the functionality that is refered to as ``by
+It provides most of the functionality that is referred to as ``by
default'' in this text.
@end deffn
I.e. real radio buttons and checkmarks instead of their @sc{ascii}
equivalents.
-@item
-There should be a way to probe a widget to see if the user has modified
-it.
-
-@item
-The support for indentation of component widgets should be finished.
-
@item
There should be support for browsing the widget documentation.
@item
There should be a way to specify that @key{RET} in a field will call the
@code{:activate} function. This should be used by widgets such as
-@code{file} and @code{symbol} prompt with completion. This way, we
-could also get rid of the default tag for the @code{file} widget.
+@code{file} and @code{symbol} prompt with completion.
@item
-The @code{choice} tag should be prettier, something like the abbreviated
+The @code{menu-choice} tag should be prettier, something like the abbreviated
menus in Open Look.
@item
specific to the first widget where I used them.
@item
-Unchecked items in a @code{radio} or @code{checklist} should be grayed
-out, and the subwidgets should somehow become inactive. This could
-perhaps be implemented by binding @code{widget-inactive} to t when inserting
-the grayed out subwidget, and let the widget-specify functions check
-that variable.
+Unchecked items in a @code{radio-button-choice} or @code{checklist}
+should be grayed out, and the subwidgets should somehow become inactive.
+This could perhaps be implemented by binding @code{widget-inactive} to t
+when inserting the grayed out subwidget, and let the widget-specify
+functions check that variable.
@end itemize