+++ /dev/null
-1998-01-08 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * lisp/smtpmail.el (smtpmail-via-smtp): Bind
- `coding-system-for-read' by `smtpmail-coding-system' to avoid
- dead-locking in Emacs 20.
-
- * lisp/gnus.el: gnus.el (gnus-version-number): Update to version
- 6.0.2.
-
-1998-01-07 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * lisp/nnmail.el, lisp/message.el: Sync with Quassia Gnus v0.22.
-
- * lisp/gnus.el: Delete autoload setting for `metamail-buffer'.
-
- * lisp/gnus.el, lisp/gnus-sum.el: Sync with Quassia Gnus v0.22.
-
- * lisp/gnus-msg.el: Abolish function
- `gnus-inews-insert-mime-headers'.
-
- * lisp/gnus-msg.el, lisp/gnus-draft.el, lisp/gnus-art.el: Sync
- with Quassia Gnus v0.22.
-
- * lisp/smtpmail.el (smtpmail-coding-system): New variable; abolish
- `smtpmail-code-conv-from'.
- (smtpmail-via-smtp): Guard `coding-system-for-write' by
- `smtpmail-coding-system'.
-
- * lisp/smtpmail.el: Imported from Emacs 20.2.
-
- * lisp/pop3.el (pop3-movemail-file-coding-system): Change default
- value to `binary'.
- (pop3-open-server): Guard `coding-system-for-read' by `binary'.
-
-1998-01-06 Shuhei Kobayashi <shuhei-k@jaist.ac.jp>
-
- * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/nnoo.el,
- lisp/nnml.el, lisp/message.el, lisp/gnus.el, lisp/gnus-sum.el,
- lisp/gnus-start.el, lisp/gnus-ems.el, lisp/gnus-draft.el,
- lisp/gnus-agent.el, lisp/ChangeLog: Importing qgnus-0.22
-
- * texi/message.texi, texi/gnus.texi, lisp/gnus.el, lisp/ChangeLog:
- Importing qgnus-0.21
-
- * texi/message.texi, texi/gnus.texi, texi/ChangeLog,
- lisp/nnvirtual.el, lisp/nnsoup.el, lisp/nnoo.el, lisp/nnmh.el,
- lisp/nnmail.el, lisp/nndraft.el, lisp/gnus.el, lisp/gnus-xmas.el,
- lisp/gnus-sum.el, lisp/gnus-start.el, lisp/gnus-score.el,
- lisp/gnus-msg.el, lisp/gnus-group.el, lisp/gnus-draft.el,
- lisp/gnus-art.el, lisp/ChangeLog: Importing qgnus-0.20
-
- * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/pop3.el,
- lisp/nntp.el, lisp/nnml.el, lisp/nnmail.el, lisp/nndoc.el,
- lisp/message.el, lisp/gnus.el, lisp/gnus-uu.el,
- lisp/gnus-topic.el, lisp/gnus-sum.el, lisp/gnus-start.el,
- lisp/gnus-score.el, lisp/gnus-group.el, lisp/gnus-cache.el,
- lisp/gnus-agent.el, lisp/ChangeLog: Importing qgnus-0.19
-
-1997-12-27 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * lisp/gnus.el (gnus-version-number): Update to version 6.0.1.
-
- * lisp/message.el (message-resend): Enclose `message-setup' with
- `(let (message-setup-hook) ...)' to avoid to `turn-on-mime-edit';
- must setup `message-encoding-buffer' and `message-edit-buffer' for
- `message-send-mail'.
-
-1997-12-08 Shuhei Kobayashi <shuhei-k@jaist.ac.jp>
-
- * lisp/pop3.el, lisp/message.el, lisp/gnus.el, lisp/gnus-sum.el,
- lisp/gnus-art.el, lisp/ChangeLog: Synch'ed up to qgnus-0.18.
-
- * texi/message.texi, texi/gnus.texi, texi/ChangeLog,
- lisp/smiley.el, lisp/pop3.el, lisp/nnweb.el, lisp/nntp.el,
- lisp/nnml.el, lisp/nnmail.el, lisp/nnheader.el, lisp/nndraft.el,
- lisp/message.el, lisp/lpath.el, lisp/gnus.el, lisp/gnus-util.el,
- lisp/gnus-sum.el, lisp/gnus-start.el, lisp/gnus-picon.el,
- lisp/gnus-nocem.el, lisp/gnus-mh.el, lisp/gnus-group.el,
- lisp/gnus-ems.el, lisp/gnus-cite.el, lisp/gnus-art.el,
- lisp/gnus-agent.el, lisp/dgnushack.el, lisp/ChangeLog: Importing
- qgnus-0.18
-
-1997-11-29 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * README.semi: New file.
-
- * lisp/gnus.el (gnus-version): Rename to "Semi-gnus".
-
-1997-11-28 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * lisp/gnus-draft.el (gnus-draft-decoding-function): New variable.
- (gnus-draft-setup): Use `gnus-draft-decoding-function'.
-
-1997-11-27 MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
- * lisp/nnmail.el, lisp/nnheader.el, lisp/message.el, lisp/gnus.el,
- lisp/gnus-sum.el, lisp/gnus-msg.el, lisp/gnus-art.el: sync with
- qgnus-0.17.
-
- * texi/message.texi, texi/gnus.texi, lisp/smiley.el, lisp/nnoo.el,
- lisp/nnml.el, lisp/nnmail.el, lisp/nnheader.el,
- lisp/messagexmas.el, lisp/message.el, lisp/gnus.el,
- lisp/gnus-xmas.el, lisp/gnus-util.el, lisp/gnus-sum.el,
- lisp/gnus-start.el, lisp/gnus-spec.el, lisp/gnus-score.el,
- lisp/gnus-picon.el, lisp/gnus-move.el, lisp/gnus-msg.el,
- lisp/gnus-kill.el, lisp/gnus-group.el, lisp/gnus-draft.el,
- lisp/gnus-demon.el, lisp/gnus-cite.el, lisp/gnus-art.el,
- lisp/ChangeLog: Quassia Gnus v0.17.
-
- * lisp/gnus-i18n.el: New file.
-
- * lisp/nnmail.el (nnmail-file-coding-system): Use `raw-text' in
- default.
-
- * lisp/nnheader.el (nnheader-file-coding-system): Use `raw-text'
- in default.
-
- * lisp/message.el (message-encode-function): New variable.
- (message-forward-start-separator): Modify for mime-edit.
- (message-forward-end-separator): Modify for mime-edit.
- (message-setup-hook): Use `(message-maybe-setup-default-charset
- turn-on-mime-edit)' in default.
- (message-header-hook): Use `(eword-encode-header)' in default.
-
- (message-send): Use local variable `message-encoding-buffer',
- `message-edit-buffer' and `message-mime-mode' as public variables;
- use `message-encode-function'.
- (message-send-mail): Use `message-encoding-buffer' to get contents
- of body; abolish `message-encode-mail-hook'; use
- `mime-edit-maybe-split-and-send'; use `message-edit-buffer' to
- refer original editing buffer.
- (message-send-news): Use `message-encoding-buffer' to get contents
- of body; abolish `message-encode-news-hook'; use
- `mime-edit-maybe-split-and-send'; use `message-edit-buffer' to
- refer original editing buffer.
- (message-check-news-syntax): Call `message-check-news-body-syntax'
- in `mime-edit-buffer'.
- (message-do-fcc): Use `message-encoding-buffer' to get contents;
- run `message-header-hook'.
- (message-cancel-news): Use `std11-extract-address-components'
- instead of `mail-extract-address-components'; bind
- `message-encoding-buffer' and `message-edit-buffer'.
-
- (message-maybe-setup-default-charset): New function.
- (message-maybe-encode): New function.
- (message-mime-insert-article): New function.
- Add setting for mime-view.
-
- * lisp/gnus.el (gnus-version-number): for version number for Open
- gnus.
- (gnus-version): Modify for Open gnus.
-
- * lisp/gnus-sum.el: Autoload gnus-i18n.
-
- (gnus-show-mime): `t' in default.
- (gnus-structured-field-decoder): Use
- `eword-decode-structured-field-body' in default.
- (gnus-unstructured-field-decoder): Use
- `eword-decode-unstructured-field-body' in default.
-
- (gnus-parse-headers-hook): Use
- `(gnus-set-summary-default-charset)' in default.
-
- (gnus-summary-mode-map): Add binding for
- `gnus-summary-scroll-down' and
- `gnus-summary-preview-mime-message'.
-
- (gnus-summary-preview-mime-message): New function.
- (gnus-mime-partial-preview-function): New function.
- Add setting for mime-view.
-
- * lisp/gnus-msg.el (gnus-summary-cancel-article): Display
- `gnus-article-buffer' instead ofb `gnus-original-article-buffer'.
- (gnus-extended-version): Don't return version of emacsen.
- (gnus-inews-do-gcc): Refer `message-encoding-buffer'.
-
- * lisp/gnus-art.el (gnus-show-mime-method): Use
- `gnus-article-preview-mime-message' instead of `metamail-buffer'
- in default.
- (gnus-decode-encoded-word-method): Use
- `gnus-article-decode-encoded-word' instead of
- `gnus-article-de-quoted-unreadable' in default.
-
- Abolish `gnus-hack-decode-rfc1522', `gnus-decode-rfc1522',
- `article-decode-rfc1522', `article-de-quoted-unreadable',
- `article-mime-decode-quoted-printable-buffer' and
- `article-mime-decode-quoted-printable'.
- (gnus-article-decode-rfc1522): New implementation (use
- `eword-decode-header').
-
- (gnus-article-preview-mime-message): New function.
- (gnus-article-decode-encoded-word): New function.
- (gnus-content-header-filter): New function.
- (mime-view-quitting-method-for-gnus): New function.
- Add setting for mime-view.
-
- * lisp/message.el: Abolish `message-max-size' because it is not
- used.
-
- * lisp/message.el: sync with qgnus-0.16.
-
- * texi/Makefile, texi/message.texi, texi/gnus.texi, lisp/nnweb.el,
- lisp/nnmh.el, lisp/nnheader.el, lisp/nnfolder.el, lisp/message.el,
- lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el,
- lisp/gnus-sum.el, lisp/gnus-srvr.el, lisp/gnus-picon.el,
- lisp/gnus-group.el, lisp/gnus-cite.el, lisp/gnus-art.el: Quassia
- Gnus v0.16.
-
- * lisp/nnmh.el (nnmh-request-list-1): fix maybe.
-
- * lisp/message.el (message-do-fcc): Guard
- `coding-system-for-write' by `raw-text'; run
- `message-before-do-fcc-hook'.
-
- * lisp/gnus-msg.el (gnus-inews-do-gcc): Guard
- `coding-system-for-write' by `raw-text'; run
- `gnus-before-do-gcc-hook'.
-
- * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/nntp.el,
- lisp/nnoo.el, lisp/nnml.el, lisp/nndraft.el, lisp/nnbabyl.el,
- lisp/message.el, lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el,
- lisp/gnus-util.el, lisp/gnus-sum.el, lisp/gnus-start.el,
- lisp/gnus-spec.el, lisp/gnus-soup.el, lisp/gnus-score.el,
- lisp/gnus-msg.el, lisp/gnus-gl.el, lisp/gnus-ems.el,
- lisp/gnus-draft.el, lisp/gnus-cache.el, lisp/gnus-audio.el,
- lisp/gnus-art.el, lisp/gnus-agent.el, lisp/ChangeLog: Quassia Gnus
- v0.15.
-
- * lisp/message.el, lisp/ChangeLog: sync with qgnus-0.14.
-
- * texi/Makefile, texi/gnus.texi: Quassia Gnus v0.14.
-
- * texi/dir: New file.
-
- * texi/dir, lisp/pop3.el, lisp/nntp.el, lisp/nnml.el,
- lisp/nnmail.el, lisp/nnfolder.el, lisp/message.el, lisp/lpath.el,
- lisp/gnus.el, lisp/gnus-win.el, lisp/gnus-util.el,
- lisp/gnus-topic.el, lisp/gnus-sum.el, lisp/gnus-start.el,
- lisp/gnus-score.el, lisp/gnus-msg.el, lisp/gnus-mh.el,
- lisp/gnus-cus.el, lisp/gnus-art.el, lisp/gnus-agent.el,
- lisp/ChangeLog: Quassia Gnus v0.14.
-
- * lisp/message.el, lisp/ChangeLog: sync with qgnus-0.13.
-
- * texi/gnus.texi, texi/ChangeLog, lisp/pop3.el, lisp/nnweb.el,
- lisp/nnmail.el: Quassia Gnus v0.13.
-
- * lisp/nnlistserv.el: New file.
-
- * lisp/nnlistserv.el, lisp/message.el, lisp/md5.el, lisp/lpath.el,
- lisp/gnus.el, lisp/gnus-topic.el, lisp/gnus-sum.el,
- lisp/gnus-score.el, lisp/gnus-picon.el, lisp/gnus-msg.el,
- lisp/gnus-group.el, lisp/gnus-art.el, lisp/gnus-agent.el,
- lisp/dgnushack.el, lisp/ChangeLog, GNUS-NEWS: Quassia Gnus v0.13.
-
- * lisp/message.el: sync with qgnus-0.12.
-
- * texi/message.texi, texi/gnus.texi, texi/gnus-faq.texi,
- texi/ChangeLog, lisp/nntp.el, lisp/nnmh.el, lisp/nnmail.el,
- lisp/nndraft.el, lisp/messcompat.el, lisp/message.el,
- lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el,
- lisp/gnus-sum.el, lisp/gnus-score.el, lisp/gnus-salt.el,
- lisp/gnus-msg.el, lisp/gnus-int.el, lisp/gnus-group.el,
- lisp/gnus-demon.el, lisp/gnus-cache.el, lisp/gnus-art.el,
- lisp/gnus-agent.el, lisp/ChangeLog, GNUS-NEWS: Quassia Gnus v0.12.
-
- * lisp/message.el (message-send-news-function): Use
- `message-send-news-with-gnus' in default.
- (message-send-via-news): Use `message-send-news' instead of
- `message-send-news-function'.
- (message-send-mail): Don't avoid text properties; run
- `message-encode-mail-hook'.
- (message-send-news): Don't avoid text properties; run
- `message-encode-news-hook'; use `message-send-news-function'.
- (message-send-news-with-gnus): New function.
- (message-cancel-news): Use `message-send-news' instead of
- `message-send-news-function'.
+++ /dev/null
-EMACS=emacs
-XEMACS=xemacs
-
-all: lick info
-
-lick:
- cd lisp; $(MAKE) EMACS=$(EMACS) all
-
-# Rule for Lars and nobody else.
-some:
- cd lisp; $(MAKE) EMACS=$(EMACS) some
-l:
- cd lisp; $(MAKE) EMACS=$(EMACS) clever
-
-info:
- cd texi; $(MAKE) EMACS=$(EMACS) all
-
-clean:
- rm -f */*.orig */*.rej *.orig *.rej
-
-xsome:
- cd lisp; $(MAKE) EMACS=$(XEMACS) some
-
-elclean:
- rm lisp/*.elc
-
-x:
- make EMACS=xemacs
-
-distclean:
- make clean
- rm -r *~
- for i in lisp texi; do (cd $$i; make distclean); done
-
-osome:
- make EMACS=emacs-19.34 some
+++ /dev/null
-SHELL = /bin/sh
-EMACS=emacs
-FLAGS=-batch -q -no-site-file -l ./dgnushack.el
-
-total:
- rm -f *.elc ; $(EMACS) $(FLAGS) -f dgnushack-compile
-
-all:
- rm -f *.elc ; $(EMACS) $(FLAGS) -f dgnushack-compile
-
-clever:
- $(EMACS) $(FLAGS) -f dgnushack-compile
-
-some:
- $(EMACS) $(FLAGS) -f dgnushack-compile
-
-tags:
- etags *.el
-
-separately:
- rm -f *.elc ; for i in *.el; do $(EMACS) $(FLAGS) -f batch-byte-compile $$i; done
-
-pot:
- xpot -drgnus -r`cat ./version` *.el > rgnus.pot
-
-gnus-load.el:
- echo ";;; gnus-load.el --- automatically extracted custom dependencies" > gnus-load.el
- echo ";;" >> gnus-load.el
- echo ";;; Code:" >> gnus-load.el
- echo >> gnus-load.el
- $(EMACS) $(FLAGS) -l ./dgnushack.el -l cus-edit.el *.el \
- -f custom-make-dependencies >> gnus-load.el
- echo >> gnus-load.el
- echo "(provide 'gnus-load)" >> gnus-load.el
- echo >> gnus-load.el
- echo ";;; gnus-load.el ends here" >> gnus-load.el
-
-distclean:
- rm -f *.orig *.rej *.elc *~
-
+++ /dev/null
-;;; date.el --- Date and time handling functions
-;; Copyright (C) 1998 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Masanobu Umeda <umerin@mse.kyutech.ac.jp>
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'timezone)
-
-(defun parse-time-string (date)
- "Convert DATE into time."
- (decode-time
- (condition-case ()
- (let* ((d1 (timezone-parse-date date))
- (t1 (timezone-parse-time (aref d1 3))))
- (apply 'encode-time
- (mapcar (lambda (el)
- (and el (string-to-number el)))
- (list
- (aref t1 2) (aref t1 1) (aref t1 0)
- (aref d1 2) (aref d1 1) (aref d1 0)
- (number-to-string
- (* 60 (timezone-zone-to-minute (aref d1 4))))))))
- ;; If we get an error, then we just return a 0 time.
- (error (list 0 0)))))
-
-(defun date-to-time (date)
- "Convert DATE into time."
- (apply 'encode-time (parse-time-string date)))
-
-(defun time-less-p (t1 t2)
- "Say whether time T1 is less than time T2."
- (or (< (car t1) (car t2))
- (and (= (car t1) (car t2))
- (< (nth 1 t1) (nth 1 t2)))))
-
-(defun days-to-time (days)
- "Convert DAYS into time."
- (let* ((seconds (* 1.0 days 60 60 24))
- (rest (expt 2 16))
- (ms (condition-case nil (floor (/ seconds rest))
- (range-error (expt 2 16)))))
- (list ms (condition-case nil (round (- seconds (* ms rest)))
- (range-error (expt 2 16))))))
-
-(defun time-since (time)
- "Return the time since TIME, which is either an internal time or a date."
- (when (stringp time)
- ;; Convert date strings to internal time.
- (setq time (date-to-time time)))
- (let* ((current (current-time))
- (rest (when (< (nth 1 current) (nth 1 time))
- (expt 2 16))))
- (list (- (+ (car current) (if rest -1 0)) (car time))
- (- (+ (or rest 0) (nth 1 current)) (nth 1 time)))))
-
-(defun subtract-time (t1 t2)
- "Subtract two internal times."
- (let ((borrow (< (cadr t1) (cadr t2))))
- (list (- (car t1) (car t2) (if borrow 1 0))
- (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
-
-(defun date-to-day (date)
- "Return the number of days between year 1 and DATE."
- (time-to-day (date-to-time date)))
-
-(defun days-between (date1 date2)
- "Return the number of days between DATE1 and DATE2."
- (- (date-to-day date1) (date-to-day date2)))
-
-(defun date-leap-year-p (year)
- "Return t if YEAR is a leap year."
- (or (and (zerop (% year 4))
- (not (zerop (% year 100))))
- (zerop (% year 400))))
-
-(defun time-to-day-in-year (time)
- "Return the day number within the year of the date month/day/year."
- (let* ((tim (decode-time time))
- (month (nth 4 tim))
- (day (nth 3 tim))
- (year (nth 5 tim))
- (day-of-year (+ day (* 31 (1- month)))))
- (when (> month 2)
- (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10)))
- (when (date-leap-year-p year)
- (setq day-of-year (1+ day-of-year))))
- day-of-year))
-
-(defun time-to-day (time)
- "The number of days between the Gregorian date 0001-12-31bce and TIME.
-The Gregorian date Sunday, December 31, 1bce is imaginary."
- (let* ((tim (decode-time time))
- (month (nth 4 tim))
- (day (nth 3 tim))
- (year (nth 5 tim)))
- (+ (time-to-day-in-year time) ; Days this year
- (* 365 (1- year)) ; + Days in prior years
- (/ (1- year) 4) ; + Julian leap years
- (- (/ (1- year) 100)) ; - century years
- (/ (1- year) 400)))) ; + Gregorian leap years
-
-(provide 'date)
-
-;;; date.el ends here
+++ /dev/null
-;;; mailcap.el --- Functions for displaying MIME parts
-;; Copyright (C) 1998 Free Software Foundation, Inc.
-
-;; Author: William M. Perry <wmperry@aventail.com>
-;; Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news, mail
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;; Code:
-
-(eval-and-compile
- (require 'cl))
-(require 'mail-parse)
-
-(defvar mailcap-parse-args-syntax-table
- (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
- (modify-syntax-entry ?' "\"" table)
- (modify-syntax-entry ?` "\"" table)
- (modify-syntax-entry ?{ "(" table)
- (modify-syntax-entry ?} ")" table)
- table)
- "A syntax table for parsing sgml attributes.")
-
-(defvar mailcap-mime-data
- '(("application"
- ("x-x509-ca-cert"
- (viewer . ssl-view-site-cert)
- (test . (fboundp 'ssl-view-site-cert))
- (type . "application/x-x509-ca-cert"))
- ("x-x509-user-cert"
- (viewer . ssl-view-user-cert)
- (test . (fboundp 'ssl-view-user-cert))
- (type . "application/x-x509-user-cert"))
- ("octet-stream"
- (viewer . mailcap-save-binary-file)
- (type ."application/octet-stream"))
- ("dvi"
- (viewer . "open %s")
- (type . "application/dvi")
- (test . (eq (mm-device-type) 'ns)))
- ("dvi"
- (viewer . "xdvi %s")
- (test . (eq (mm-device-type) 'x))
- ("needsx11")
- (type . "application/dvi"))
- ("dvi"
- (viewer . "dvitty %s")
- (test . (not (getenv "DISPLAY")))
- (type . "application/dvi"))
- ("emacs-lisp"
- (viewer . mailcap-maybe-eval)
- (type . "application/emacs-lisp"))
- ("x-tar"
- (viewer . mailcap-save-binary-file)
- (type . "application/x-tar"))
- ("x-latex"
- (viewer . tex-mode)
- (test . (fboundp 'tex-mode))
- (type . "application/x-latex"))
- ("x-tex"
- (viewer . tex-mode)
- (test . (fboundp 'tex-mode))
- (type . "application/x-tex"))
- ("latex"
- (viewer . tex-mode)
- (test . (fboundp 'tex-mode))
- (type . "application/latex"))
- ("tex"
- (viewer . tex-mode)
- (test . (fboundp 'tex-mode))
- (type . "application/tex"))
- ("texinfo"
- (viewer . texinfo-mode)
- (test . (fboundp 'texinfo-mode))
- (type . "application/tex"))
- ("zip"
- (viewer . mailcap-save-binary-file)
- (type . "application/zip")
- ("copiousoutput"))
- ("pdf"
- (viewer . "acroread %s")
- (type . "application/pdf"))
- ("postscript"
- (viewer . "open %s")
- (type . "application/postscript")
- (test . (eq (mm-device-type) 'ns)))
- ("postscript"
- (viewer . "ghostview %s")
- (type . "application/postscript")
- (test . (eq (mm-device-type) 'x))
- ("needsx11"))
- ("postscript"
- (viewer . "ps2ascii %s")
- (type . "application/postscript")
- (test . (not (getenv "DISPLAY")))
- ("copiousoutput")))
- ("audio"
- ("x-mpeg"
- (viewer . "maplay %s")
- (type . "audio/x-mpeg"))
- (".*"
- (viewer . mailcap-save-binary-file)
- (test . (or (featurep 'nas-sound)
- (featurep 'native-sound)))
- (type . "audio/*"))
- (".*"
- (viewer . "showaudio")
- (type . "audio/*")))
- ("message"
- ("rfc-*822"
- (viewer . gnus-article-prepare-display)
- (test . (and (featurep 'gnus)
- (gnus-alive-p)))
- (type . "message/rfc-822"))
- ("rfc-*822"
- (viewer . vm-mode)
- (test . (fboundp 'vm-mode))
- (type . "message/rfc-822"))
- ("rfc-*822"
- (viewer . w3-mode)
- (test . (fboundp 'w3-mode))
- (type . "message/rfc-822"))
- ("rfc-*822"
- (viewer . view-mode)
- (test . (fboundp 'view-mode))
- (type . "message/rfc-822"))
- ("rfc-*822"
- (viewer . fundamental-mode)
- (type . "message/rfc-822")))
- ("image"
- ("x-xwd"
- (viewer . "xwud -in %s")
- (type . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- (test . (eq (mm-device-type) 'x))
- ("needsx11"))
- ("x11-dump"
- (viewer . "xwud -in %s")
- (type . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- (test . (eq (mm-device-type) 'x))
- ("needsx11"))
- ("windowdump"
- (viewer . "xwud -in %s")
- (type . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- (test . (eq (mm-device-type) 'x))
- ("needsx11"))
- (".*"
- (viewer . "aopen %s")
- (type . "image/*")
- (test . (eq (mm-device-type) 'ns)))
- (".*"
- (viewer . "xv -perfect %s")
- (type . "image/*")
- (test . (eq (mm-device-type) 'x))
- ("needsx11")))
- ("text"
- ("plain"
- (viewer . w3-mode)
- (test . (fboundp 'w3-mode))
- (type . "text/plain"))
- ("plain"
- (viewer . view-mode)
- (test . (fboundp 'view-mode))
- (type . "text/plain"))
- ("plain"
- (viewer . fundamental-mode)
- (type . "text/plain"))
- ("enriched"
- (viewer . enriched-decode-region)
- (test . (fboundp 'enriched-decode))
- (type . "text/enriched"))
- ("html"
- (viewer . mm-w3-prepare-buffer)
- (test . (fboundp 'w3-prepare-buffer))
- (type . "text/html")))
- ("video"
- ("mpeg"
- (viewer . "mpeg_play %s")
- (type . "video/mpeg")
- (test . (eq (mm-device-type) 'x))
- ("needsx11")))
- ("x-world"
- ("x-vrml"
- (viewer . "webspace -remote %s -URL %u")
- (type . "x-world/x-vrml")
- ("description"
- "VRML document")))
- ("archive"
- ("tar"
- (viewer . tar-mode)
- (type . "archive/tar")
- (test . (fboundp 'tar-mode)))))
- "The mailcap structure is an assoc list of assoc lists.
-1st assoc list is keyed on the major content-type
-2nd assoc list is keyed on the minor content-type (which can be a regexp)
-
-Which looks like:
------------------
- ((\"application\"
- (\"postscript\" . <info>))
- (\"text\"
- (\"plain\" . <info>)))
-
-Where <info> is another assoc list of the various information
-related to the mailcap RFC. This is keyed on the lowercase
-attribute name (viewer, test, etc). This looks like:
- ((viewer . viewerinfo)
- (test . testinfo)
- (xxxx . \"string\"))
-
-Where viewerinfo specifies how the content-type is viewed. Can be
-a string, in which case it is run through a shell, with
-appropriate parameters, or a symbol, in which case the symbol is
-funcall'd, with the buffer as an argument.
-
-testinfo is a list of strings, or nil. If nil, it means the
-viewer specified is always valid. If it is a list of strings,
-these are used to determine whether a viewer passes the 'test' or
-not.")
-
-(defvar mailcap-download-directory nil
- "*Where downloaded files should go by default.")
-
-(defvar mailcap-temporary-directory (or (getenv "TMPDIR") "/tmp")
- "*Where temporary files go.")
-
-;;;
-;;; Utility functions
-;;;
-
-(defun mailcap-generate-unique-filename (&optional fmt)
- "Generate a unique filename in mailcap-temporary-directory"
- (if (not fmt)
- (let ((base (format "mailcap-tmp.%d" (user-real-uid)))
- (fname "")
- (x 0))
- (setq fname (format "%s%d" base x))
- (while (file-exists-p
- (expand-file-name fname mailcap-temporary-directory))
- (setq x (1+ x)
- fname (concat base (int-to-string x))))
- (expand-file-name fname mailcap-temporary-directory))
- (let ((base (concat "mm" (int-to-string (user-real-uid))))
- (fname "")
- (x 0))
- (setq fname (format fmt (concat base (int-to-string x))))
- (while (file-exists-p
- (expand-file-name fname mailcap-temporary-directory))
- (setq x (1+ x)
- fname (format fmt (concat base (int-to-string x)))))
- (expand-file-name fname mailcap-temporary-directory))))
-
-(defun mailcap-save-binary-file ()
- (goto-char (point-min))
- (unwind-protect
- (let ((file (read-file-name
- "Filename to save as: "
- (or mailcap-download-directory "~/")))
- (require-final-newline nil))
- (write-region (point-min) (point-max) file))
- (kill-buffer (current-buffer))))
-
-(defun mailcap-maybe-eval ()
- "Maybe evaluate a buffer of emacs lisp code"
- (if (yes-or-no-p "This is emacs-lisp code, evaluate it? ")
- (eval-buffer (current-buffer))
- (emacs-lisp-mode)))
-
-;;;
-;;; The mailcap parser
-;;;
-
-(defun mailcap-replace-regexp (regexp to-string)
- ;; Quiet replace-regexp.
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (replace-match to-string t nil)))
-
-(defvar mailcap-parsed-p nil)
-
-(defun mailcap-parse-mailcaps (&optional path force)
- "Parse out all the mailcaps specified in a unix-style path string PATH.
-If FORCE, re-parse even if already parsed."
- (interactive (list nil t))
- (when (or (not mailcap-parsed-p)
- force)
- (cond
- (path nil)
- ((getenv "MAILCAPS") (setq path (getenv "MAILCAPS")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
- (setq path (mapconcat 'expand-file-name '("~/mail.cap" "~/etc/mail.cap")
- ";")))
- (t (setq path (mapconcat 'expand-file-name
- '("~/.mailcap"
- "/etc/mailcap:/usr/etc/mailcap"
- "/usr/local/etc/mailcap") ":"))))
- (let ((fnames (reverse
- (split-string
- path (if (memq system-type
- '(ms-dos ms-windows windows-nt))
- ";"
- ":"))))
- fname)
- (while fnames
- (setq fname (car fnames))
- (if (and (file-exists-p fname) (file-readable-p fname)
- (file-regular-p fname))
- (mailcap-parse-mailcap (car fnames)))
- (setq fnames (cdr fnames))))
- (setq mailcap-parsed-p t)))
-
-(defun mailcap-parse-mailcap (fname)
- ;; Parse out the mailcap file specified by FNAME
- (let (major ; The major mime type (image/audio/etc)
- minor ; The minor mime type (gif, basic, etc)
- save-pos ; Misc saved positions used in parsing
- viewer ; How to view this mime type
- info ; Misc info about this mime type
- )
- (with-temp-buffer
- (insert-file-contents fname)
- (set-syntax-table mailcap-parse-args-syntax-table)
- (mailcap-replace-regexp "#.*" "") ; Remove all comments
- (mailcap-replace-regexp "\n+" "\n") ; And blank lines
- (mailcap-replace-regexp "\\\\[ \t\n]+" " ") ; And collapse spaces
- (mailcap-replace-regexp (concat (regexp-quote "\\") "[ \t]*\n") "")
- (goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n")
- (setq save-pos (point)
- info nil)
- (skip-chars-forward "^/;")
- (downcase-region save-pos (point))
- (setq major (buffer-substring save-pos (point)))
- (skip-chars-forward "/ \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^;")
- (downcase-region save-pos (point))
- (setq minor
- (cond
- ((eq ?* (or (char-after save-pos) 0)) ".*")
- ((= (point) save-pos) ".*")
- (t (buffer-substring save-pos (point)))))
- (skip-chars-forward "; \t\n")
- ;;; Got the major/minor chunks, now for the viewers/etc
- ;;; The first item _must_ be a viewer, according to the
- ;;; RFC for mailcap files (#1343)
- (skip-chars-forward "; \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^;\n")
- (if (eq (or (char-after save-pos) 0) ?')
- (setq viewer (progn
- (narrow-to-region (1+ save-pos) (point))
- (goto-char (point-min))
- (prog1
- (read (current-buffer))
- (goto-char (point-max))
- (widen))))
- (setq viewer (buffer-substring save-pos (point))))
- (setq save-pos (point))
- (end-of-line)
- (setq info (nconc (list (cons 'viewer viewer)
- (cons 'type (concat major "/"
- (if (string= minor ".*")
- "*" minor))))
- (mailcap-parse-mailcap-extras save-pos (point))))
- (mailcap-mailcap-entry-passes-test info)
- (mailcap-add-mailcap-entry major minor info)))))
-
-(defun mailcap-parse-mailcap-extras (st nd)
- ;; Grab all the extra stuff from a mailcap entry
- (let (
- name ; From name=
- value ; its value
- results ; Assoc list of results
- name-pos ; Start of XXXX= position
- val-pos ; Start of value position
- done ; Found end of \'d ;s?
- )
- (save-restriction
- (narrow-to-region st nd)
- (goto-char (point-min))
- (skip-chars-forward " \n\t;")
- (while (not (eobp))
- (setq done nil)
- (skip-chars-forward " \";\n\t")
- (setq name-pos (point))
- (skip-chars-forward "^ \n\t=")
- (downcase-region name-pos (point))
- (setq name (buffer-substring name-pos (point)))
- (skip-chars-forward " \t\n")
- (if (not (eq (char-after (point)) ?=)) ; There is no value
- (setq value nil)
- (skip-chars-forward " \t\n=")
- (setq val-pos (point))
- (if (memq (char-after val-pos) '(?\" ?'))
- (progn
- (setq val-pos (1+ val-pos))
- (condition-case nil
- (progn
- (forward-sexp 1)
- (backward-char 1))
- (error (goto-char (point-max)))))
- (while (not done)
- (skip-chars-forward "^;")
- (if (eq (char-after (1- (point))) ?\\ )
- (progn
- (subst-char-in-region (1- (point)) (point) ?\\ ? )
- (skip-chars-forward ";"))
- (setq done t))))
- (setq value (buffer-substring val-pos (point))))
- (setq results (cons (cons name value) results)))
- results)))
-
-(defun mailcap-mailcap-entry-passes-test (info)
- ;; Return t iff a mailcap entry passes its test clause or no test
- ;; clause is present.
- (let (status ; Call-process-regions return value
- (test (assq 'test info)) ; The test clause
- )
- (setq status (and test (split-string (cdr test) " ")))
- (if (and (or (assoc "needsterm" info)
- (assoc "needsx11" info))
- (not (getenv "DISPLAY")))
- (setq status nil)
- (cond
- ((and (equal (nth 0 status) "test")
- (equal (nth 1 status) "-n")
- (or (equal (nth 2 status) "$DISPLAY")
- (equal (nth 2 status) "\"$DISPLAY\"")))
- (setq status (if (getenv "DISPLAY") t nil)))
- ((and (equal (nth 0 status) "test")
- (equal (nth 1 status) "-z")
- (or (equal (nth 2 status) "$DISPLAY")
- (equal (nth 2 status) "\"$DISPLAY\"")))
- (setq status (if (getenv "DISPLAY") nil t)))
- (test nil)
- (t nil)))
- (and test (listp test) (setcdr test status))))
-
-;;;
-;;; The action routines.
-;;;
-
-(defun mailcap-possible-viewers (major minor)
- ;; Return a list of possible viewers from MAJOR for minor type MINOR
- (let ((exact '())
- (wildcard '()))
- (while major
- (cond
- ((equal (car (car major)) minor)
- (setq exact (cons (cdr (car major)) exact)))
- ((and minor (string-match (car (car major)) minor))
- (setq wildcard (cons (cdr (car major)) wildcard))))
- (setq major (cdr major)))
- (nconc (nreverse exact) (nreverse wildcard))))
-
-(defun mailcap-unescape-mime-test (test type-info)
- (let (save-pos save-chr subst)
- (cond
- ((symbolp test) test)
- ((and (listp test) (symbolp (car test))) test)
- ((or (stringp test)
- (and (listp test) (stringp (car test))
- (setq test (mapconcat 'identity test " "))))
- (with-temp-buffer
- (insert test)
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward "^%")
- (if (/= (- (point)
- (progn (skip-chars-backward "\\\\")
- (point)))
- 0) ; It is an escaped %
- (progn
- (delete-char 1)
- (skip-chars-forward "%."))
- (setq save-pos (point))
- (skip-chars-forward "%")
- (setq save-chr (char-after (point)))
- (cond
- ((null save-chr) nil)
- ((= save-chr ?t)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert (or (cdr (assq 'type type-info)) "\"\"")))
- ((= save-chr ?M)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?n)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?F)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?{)
- (forward-char 1)
- (skip-chars-forward "^}")
- (downcase-region (+ 2 save-pos) (point))
- (setq subst (buffer-substring (+ 2 save-pos) (point)))
- (delete-region save-pos (1+ (point)))
- (insert (or (cdr (assoc subst type-info)) "\"\"")))
- (t nil))))
- (buffer-string)))
- (t (error "Bad value to mailcap-unescape-mime-test. %s" test)))))
-
-(defvar mailcap-viewer-test-cache nil)
-
-(defun mailcap-viewer-passes-test (viewer-info type-info)
- ;; Return non-nil iff the viewer specified by VIEWER-INFO passes its
- ;; test clause (if any).
- (let* ((test-info (assq 'test viewer-info))
- (test (cdr test-info))
- (otest test)
- (viewer (cdr (assoc 'viewer viewer-info)))
- (default-directory (expand-file-name "~/"))
- status parsed-test cache result)
- (if (setq cache (assoc test mailcap-viewer-test-cache))
- (cadr cache)
- (setq
- result
- (cond
- ((not test-info) t) ; No test clause
- ((not test) nil) ; Already failed test
- ((eq test t) t) ; Already passed test
- ((and (symbolp test) ; Lisp function as test
- (fboundp test))
- (funcall test type-info))
- ((and (symbolp test) ; Lisp variable as test
- (boundp test))
- (symbol-value test))
- ((and (listp test) ; List to be eval'd
- (symbolp (car test)))
- (eval test))
- (t
- (setq test (mailcap-unescape-mime-test test type-info)
- test (list shell-file-name nil nil nil
- shell-command-switch test)
- status (apply 'call-process test))
- (= 0 status))))
- (push (list otest result) mailcap-viewer-test-cache)
- result)))
-
-(defun mailcap-add-mailcap-entry (major minor info)
- (let ((old-major (assoc major mailcap-mime-data)))
- (if (null old-major) ; New major area
- (setq mailcap-mime-data
- (cons (cons major (list (cons minor info)))
- mailcap-mime-data))
- (let ((cur-minor (assoc minor old-major)))
- (cond
- ((or (null cur-minor) ; New minor area, or
- (assq 'test info)) ; Has a test, insert at beginning
- (setcdr old-major (cons (cons minor info) (cdr old-major))))
- ((and (not (assq 'test info)) ; No test info, replace completely
- (not (assq 'test cur-minor)))
- (setcdr cur-minor info))
- (t
- (setcdr old-major (cons (cons minor info) (cdr old-major)))))))))
-
-;;;
-;;; The main whabbo
-;;;
-
-(defun mailcap-viewer-lessp (x y)
- ;; Return t iff viewer X is more desirable than viewer Y
- (let ((x-wild (string-match "[*?]" (or (cdr-safe (assq 'type x)) "")))
- (y-wild (string-match "[*?]" (or (cdr-safe (assq 'type y)) "")))
- (x-lisp (not (stringp (or (cdr-safe (assq 'viewer x)) ""))))
- (y-lisp (not (stringp (or (cdr-safe (assq 'viewer y)) "")))))
- (cond
- ((and x-lisp (not y-lisp))
- t)
- ((and (not y-lisp) x-wild (not y-wild))
- t)
- ((and (not x-wild) y-wild)
- t)
- (t nil))))
-
-(defun mailcap-mime-info (string &optional request)
- "Get the MIME viewer command for STRING, return nil if none found.
-Expects a complete content-type header line as its argument.
-
-Second argument REQUEST specifies what information to return. If it is
-nil or the empty string, the viewer (second field of the mailcap
-entry) will be returned. If it is a string, then the mailcap field
-corresponding to that string will be returned (print, description,
-whatever). If a number, then all the information for this specific
-viewer is returned. If `all', then all possible viewers for
-this type is returned."
- (let (
- major ; Major encoding (text, etc)
- minor ; Minor encoding (html, etc)
- info ; Other info
- save-pos ; Misc. position during parse
- major-info ; (assoc major mailcap-mime-data)
- minor-info ; (assoc minor major-info)
- test ; current test proc.
- viewers ; Possible viewers
- passed ; Viewers that passed the test
- viewer ; The one and only viewer
- ctl)
- (save-excursion
- (setq ctl (mail-header-parse-content-type (or string "text/plain")))
- (setq major (split-string (car ctl) "/"))
- (setq minor (cadr major)
- major (car major))
- (when (setq major-info (cdr (assoc major mailcap-mime-data)))
- (when (setq viewers (mailcap-possible-viewers major-info minor))
- (setq info (mapcar (lambda (a) (cons (symbol-name (car a))
- (cdr a)))
- (cdr ctl)))
- (while viewers
- (if (mailcap-viewer-passes-test (car viewers) info)
- (setq passed (cons (car viewers) passed)))
- (setq viewers (cdr viewers)))
- (setq passed (sort (nreverse passed) 'mailcap-viewer-lessp))
- (setq viewer (car passed))))
- (when (and (stringp (cdr (assq 'viewer viewer)))
- passed)
- (setq viewer (car passed)))
- (cond
- ((and (null viewer) (not (equal major "default")) request)
- (mailcap-mime-info "default" request))
- ((or (null request) (equal request ""))
- (mailcap-unescape-mime-test (cdr (assq 'viewer viewer)) info))
- ((stringp request)
- (if (or (eq request 'test) (eq request 'viewer))
- (mailcap-unescape-mime-test
- (cdr-safe (assoc request viewer)) info)))
- ((eq request 'all)
- passed)
- (t
- ;; MUST make a copy *sigh*, else we modify mailcap-mime-data
- (setq viewer (copy-tree viewer))
- (let ((view (assq 'viewer viewer))
- (test (assq 'test viewer)))
- (if view (setcdr view (mailcap-unescape-mime-test (cdr view) info)))
- (if test (setcdr test (mailcap-unescape-mime-test (cdr test) info))))
- viewer)))))
-
-;;;
-;;; Experimental MIME-types parsing
-;;;
-
-(defvar mailcap-mime-extensions
- '(("" . "text/plain")
- (".abs" . "audio/x-mpeg")
- (".aif" . "audio/aiff")
- (".aifc" . "audio/aiff")
- (".aiff" . "audio/aiff")
- (".ano" . "application/x-annotator")
- (".au" . "audio/ulaw")
- (".avi" . "video/x-msvideo")
- (".bcpio" . "application/x-bcpio")
- (".bin" . "application/octet-stream")
- (".cdf" . "application/x-netcdr")
- (".cpio" . "application/x-cpio")
- (".csh" . "application/x-csh")
- (".dvi" . "application/x-dvi")
- (".el" . "application/emacs-lisp")
- (".eps" . "application/postscript")
- (".etx" . "text/x-setext")
- (".exe" . "application/octet-stream")
- (".fax" . "image/x-fax")
- (".gif" . "image/gif")
- (".hdf" . "application/x-hdf")
- (".hqx" . "application/mac-binhex40")
- (".htm" . "text/html")
- (".html" . "text/html")
- (".icon" . "image/x-icon")
- (".ief" . "image/ief")
- (".jpg" . "image/jpeg")
- (".macp" . "image/x-macpaint")
- (".man" . "application/x-troff-man")
- (".me" . "application/x-troff-me")
- (".mif" . "application/mif")
- (".mov" . "video/quicktime")
- (".movie" . "video/x-sgi-movie")
- (".mp2" . "audio/x-mpeg")
- (".mp3" . "audio/x-mpeg")
- (".mp2a" . "audio/x-mpeg2")
- (".mpa" . "audio/x-mpeg")
- (".mpa2" . "audio/x-mpeg2")
- (".mpe" . "video/mpeg")
- (".mpeg" . "video/mpeg")
- (".mpega" . "audio/x-mpeg")
- (".mpegv" . "video/mpeg")
- (".mpg" . "video/mpeg")
- (".mpv" . "video/mpeg")
- (".ms" . "application/x-troff-ms")
- (".nc" . "application/x-netcdf")
- (".nc" . "application/x-netcdf")
- (".oda" . "application/oda")
- (".pbm" . "image/x-portable-bitmap")
- (".pdf" . "application/pdf")
- (".pgm" . "image/portable-graymap")
- (".pict" . "image/pict")
- (".png" . "image/png")
- (".pnm" . "image/x-portable-anymap")
- (".ppm" . "image/portable-pixmap")
- (".ps" . "application/postscript")
- (".qt" . "video/quicktime")
- (".ras" . "image/x-raster")
- (".rgb" . "image/x-rgb")
- (".rtf" . "application/rtf")
- (".rtx" . "text/richtext")
- (".sh" . "application/x-sh")
- (".sit" . "application/x-stuffit")
- (".snd" . "audio/basic")
- (".src" . "application/x-wais-source")
- (".tar" . "archive/tar")
- (".tcl" . "application/x-tcl")
- (".tcl" . "application/x-tcl")
- (".tex" . "application/x-tex")
- (".texi" . "application/texinfo")
- (".tga" . "image/x-targa")
- (".tif" . "image/tiff")
- (".tiff" . "image/tiff")
- (".tr" . "application/x-troff")
- (".troff" . "application/x-troff")
- (".tsv" . "text/tab-separated-values")
- (".txt" . "text/plain")
- (".vbs" . "video/mpeg")
- (".vox" . "audio/basic")
- (".vrml" . "x-world/x-vrml")
- (".wav" . "audio/x-wav")
- (".wrl" . "x-world/x-vrml")
- (".xbm" . "image/xbm")
- (".xpm" . "image/xpm")
- (".xwd" . "image/windowdump")
- (".zip" . "application/zip")
- (".ai" . "application/postscript")
- (".jpe" . "image/jpeg")
- (".jpeg" . "image/jpeg"))
- "An assoc list of file extensions and corresponding MIME content-types.")
-
-(defun mailcap-parse-mimetypes (&optional path)
- ;; Parse out all the mimetypes specified in a unix-style path string PATH
- (cond
- (path nil)
- ((getenv "MIMETYPES") (setq path (getenv "MIMETYPES")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
- (setq path (mapconcat 'expand-file-name
- '("~/mime.typ" "~/etc/mime.typ") ";")))
- (t (setq path (mapconcat 'expand-file-name
- '("~/.mime-types"
- "/etc/mime-types:/usr/etc/mime-types"
- "/usr/local/etc/mime-types"
- "/usr/local/www/conf/mime-types") ":"))))
- (let ((fnames (reverse
- (split-string path
- (if (memq system-type
- '(ms-dos ms-windows windows-nt))
- ";" ":"))))
- fname)
- (while fnames
- (setq fname (car fnames))
- (if (and (file-exists-p fname) (file-readable-p fname))
- (mailcap-parse-mimetype-file (car fnames)))
- (setq fnames (cdr fnames)))))
-
-(defun mailcap-parse-mimetype-file (fname)
- ;; Parse out a mime-types file
- (let (type ; The MIME type for this line
- extns ; The extensions for this line
- save-pos ; Misc. saved buffer positions
- )
- (with-temp-buffer
- (insert-file-contents fname)
- (mailcap-replace-regexp "#.*" "")
- (mailcap-replace-regexp "\n+" "\n")
- (mailcap-replace-regexp "[ \t]+$" "")
- (goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^ \t")
- (downcase-region save-pos (point))
- (setq type (buffer-substring save-pos (point)))
- (while (not (eolp))
- (skip-chars-forward " \t")
- (setq save-pos (point))
- (skip-chars-forward "^ \t\n")
- (setq extns (cons (buffer-substring save-pos (point)) extns)))
- (while extns
- (setq mailcap-mime-extensions
- (cons
- (cons (if (= (string-to-char (car extns)) ?.)
- (car extns)
- (concat "." (car extns))) type)
- mailcap-mime-extensions)
- extns (cdr extns)))))))
-
-(defun mailcap-extension-to-mime (extn)
- "Return the MIME content type of the file extensions EXTN."
- (if (and (stringp extn)
- (not (eq (string-to-char extn) ?.)))
- (setq extn (concat "." extn)))
- (cdr (assoc (downcase extn) mailcap-mime-extensions)))
-
-(defvar mailcap-binary-suffixes
- (if (memq system-type '(ms-dos windows-nt))
- '(".exe" ".com" ".bat" ".cmd" ".btm" "")
- '("")))
-
-(defun mailcap-command-p (command)
- "Say whether COMMAND is in the exec path.
-The path of COMMAND will be returned iff COMMAND is a command."
- (let ((path (if (file-name-absolute-p command) '(nil) exec-path))
- file dir)
- (catch 'found
- (while (setq dir (pop path))
- (let ((suffixes mailcap-binary-suffixes))
- (while suffixes
- (when (and (file-executable-p
- (setq file (expand-file-name
- (concat command (pop suffixes))
- dir)))
- (not (file-directory-p file)))
- (throw 'found file))))))))
-
-(provide 'mailcap)
-
-;;; mailcap.el ends here
+++ /dev/null
-;;; mm.el,v --- Mailcap parsing routines, and MIME handling
-;; Author: wmperry
-;; Created: 1996/05/28 02:46:51
-;; Version: 1.96
-;; Keywords: mail, news, hypermedia
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Copyright (c) 1994, 1995, 1996 by William M. Perry <wmperry@cs.indiana.edu>
-;;; Copyright (c) 1996 - 1998 Free Software Foundation, Inc.
-;;;
-;;; This file is not part of GNU Emacs, but the same permissions apply.
-;;;
-;;; GNU Emacs is free software; you can redistribute it and/or modify
-;;; it under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 2, or (at your option)
-;;; any later version.
-;;;
-;;; GNU Emacs is distributed in the hope that it will be useful,
-;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with GNU Emacs; see the file COPYING. If not, write to the
-;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;;; Boston, MA 02111-1307, USA.
-;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Generalized mailcap parsing and access routines
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
-;;; Data structures
-;;; ---------------
-;;; The mailcap structure is an assoc list of assoc lists.
-;;; 1st assoc list is keyed on the major content-type
-;;; 2nd assoc list is keyed on the minor content-type (which can be a regexp)
-;;;
-;;; Which looks like:
-;;; -----------------
-;;; (
-;;; ("application"
-;;; ("postscript" . <info>)
-;;; )
-;;; ("text"
-;;; ("plain" . <info>)
-;;; )
-;;; )
-;;;
-;;; Where <info> is another assoc list of the various information
-;;; related to the mailcap RFC. This is keyed on the lowercase
-;;; attribute name (viewer, test, etc). This looks like:
-;;; (("viewer" . viewerinfo)
-;;; ("test" . testinfo)
-;;; ("xxxx" . "string")
-;;; )
-;;;
-;;; Where viewerinfo specifies how the content-type is viewed. Can be
-;;; a string, in which case it is run through a shell, with
-;;; appropriate parameters, or a symbol, in which case the symbol is
-;;; funcall'd, with the buffer as an argument.
-;;;
-;;; testinfo is a list of strings, or nil. If nil, it means the
-;;; viewer specified is always valid. If it is a list of strings,
-;;; these are used to determine whether a viewer passes the 'test' or
-;;; not.
-;;;
-;;; The main interface to this code is:
-;;;
-;;; To set everything up:
-;;;
-;;; (mm-parse-mailcaps [path])
-;;;
-;;; Where PATH is a unix-style path specification (: separated list
-;;; of strings). If PATH is nil, the environment variable MAILCAPS
-;;; will be consulted. If there is no environment variable, then a
-;;; default list of paths is used.
-;;;
-;;; To retrieve the information:
-;;; (mm-mime-info st [nd] [request])
-;;;
-;;; Where st and nd are positions in a buffer that contain the
-;;; content-type header information of a mail/news/whatever message.
-;;; st can optionally be a string that contains the content-type
-;;; information.
-;;;
-;;; Third argument REQUEST specifies what information to return. If
-;;; it is nil or the empty string, the viewer (second field of the
-;;; mailcap entry) will be returned. If it is a string, then the
-;;; mailcap field corresponding to that string will be returned
-;;; (print, description, whatever). If a number, then all the
-;;; information for this specific viewer is returned.
-;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Variables, etc
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(eval-and-compile
- (require 'cl)
-;LMI was here
- ;;(require 'devices)
- )
-
-(defconst mm-version (let ((x "1.96"))
- (if (string-match "Revision: \\([^ \t\n]+\\)" x)
- (substring x (match-beginning 1) (match-end 1))
- x))
- "Version # of MM package")
-
-(defvar mm-parse-args-syntax-table
- (copy-syntax-table emacs-lisp-mode-syntax-table)
- "A syntax table for parsing sgml attributes.")
-
-(modify-syntax-entry ?' "\"" mm-parse-args-syntax-table)
-(modify-syntax-entry ?` "\"" mm-parse-args-syntax-table)
-(modify-syntax-entry ?{ "(" mm-parse-args-syntax-table)
-(modify-syntax-entry ?} ")" mm-parse-args-syntax-table)
-
-(defvar mm-mime-data
- '(
- ("multipart" . (
- ("alternative". (("viewer" . mm-multipart-viewer)
- ("type" . "multipart/alternative")))
- ("mixed" . (("viewer" . mm-multipart-viewer)
- ("type" . "multipart/mixed")))
- (".*" . (("viewer" . mm-save-binary-file)
- ("type" . "multipart/*")))
- )
- )
- ("application" . (
- ("x-x509-ca-cert" . (("viewer" . ssl-view-site-cert)
- ("test" . (fboundp 'ssl-view-site-cert))
- ("type" . "application/x-x509-ca-cert")))
- ("x-x509-user-cert" . (("viewer" . ssl-view-user-cert)
- ("test" . (fboundp 'ssl-view-user-cert))
- ("type" . "application/x-x509-user-cert")))
- ("octet-stream" . (("viewer" . mm-save-binary-file)
- ("type" ."application/octet-stream")))
- ("dvi" . (("viewer" . "open %s")
- ("type" . "application/dvi")
- ("test" . (eq (device-type) 'ns))))
- ("dvi" . (("viewer" . "xdvi %s")
- ("test" . (eq (device-type) 'x))
- ("needsx11")
- ("type" . "application/dvi")))
- ("dvi" . (("viewer" . "dvitty %s")
- ("test" . (not (getenv "DISPLAY")))
- ("type" . "application/dvi")))
- ("emacs-lisp" . (("viewer" . mm-maybe-eval)
- ("type" . "application/emacs-lisp")))
-; ("x-tar" . (("viewer" . tar-mode)
-; ("test" . (fboundp 'tar-mode))
-; ("type" . "application/x-tar")))
- ("x-tar" . (("viewer" . mm-save-binary-file)
- ("type" . "application/x-tar")))
- ("x-latex" . (("viewer" . tex-mode)
- ("test" . (fboundp 'tex-mode))
- ("type" . "application/x-latex")))
- ("x-tex" . (("viewer" . tex-mode)
- ("test" . (fboundp 'tex-mode))
- ("type" . "application/x-tex")))
- ("latex" . (("viewer" . tex-mode)
- ("test" . (fboundp 'tex-mode))
- ("type" . "application/latex")))
- ("tex" . (("viewer" . tex-mode)
- ("test" . (fboundp 'tex-mode))
- ("type" . "application/tex")))
- ("texinfo" . (("viewer" . texinfo-mode)
- ("test" . (fboundp 'texinfo-mode))
- ("type" . "application/tex")))
- ("zip" . (("viewer" . mm-save-binary-file)
- ("type" . "application/zip")
- ("copiousoutput")))
- ("pdf" . (("viewer" . "acroread %s")
- ("type" . "application/pdf")))
- ("postscript" . (("viewer" . "open %s")
- ("type" . "application/postscript")
- ("test" . (eq (device-type) 'ns))))
- ("postscript" . (("viewer" . "ghostview %s")
- ("type" . "application/postscript")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- ("postscript" . (("viewer" . "ps2ascii %s")
- ("type" . "application/postscript")
- ("test" . (not (getenv "DISPLAY")))
- ("copiousoutput")))
- ))
- ("audio" . (
- ("x-mpeg" . (("viewer" . "maplay %s")
- ("type" . "audio/x-mpeg")))
- (".*" . (("viewer" . mm-play-sound-file)
- ("test" . (or (featurep 'nas-sound)
- (featurep 'native-sound)))
- ("type" . "audio/*")))
- (".*" . (("viewer" . "showaudio")
- ("type" . "audio/*")))
- ))
- ("message" . (
- ("rfc-*822" . (("viewer" . vm-mode)
- ("test" . (fboundp 'vm-mode))
- ("type" . "message/rfc-822")))
- ("rfc-*822" . (("viewer" . w3-mode)
- ("test" . (fboundp 'w3-mode))
- ("type" . "message/rfc-822")))
- ("rfc-*822" . (("viewer" . view-mode)
- ("test" . (fboundp 'view-mode))
- ("type" . "message/rfc-822")))
- ("rfc-*822" . (("viewer" . fundamental-mode)
- ("type" . "message/rfc-822")))
- ))
- ("image" . (
- ("x-xwd" . (("viewer" . "xwud -in %s")
- ("type" . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- ("x11-dump" . (("viewer" . "xwud -in %s")
- ("type" . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- ("windowdump" . (("viewer" . "xwud -in %s")
- ("type" . "image/x-xwd")
- ("compose" . "xwd -frame > %s")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- (".*" . (("viewer" . "open %s")
- ("type" . "image/*")
- ("test" . (eq (device-type) 'ns))))
- (".*" . (("viewer" . "xv -perfect %s")
- ("type" . "image/*")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- ))
- ("text" . (
- ("plain" . (("viewer" . w3-mode)
- ("test" . (fboundp 'w3-mode))
- ("type" . "text/plain")))
- ("plain" . (("viewer" . view-mode)
- ("test" . (fboundp 'view-mode))
- ("type" . "text/plain")))
- ("plain" . (("viewer" . fundamental-mode)
- ("type" . "text/plain")))
- ("enriched" . (("viewer" . enriched-decode-region)
- ("test" . (fboundp
- 'enriched-decode-region))
- ("type" . "text/enriched")))
- ("html" . (("viewer" . w3-prepare-buffer)
- ("test" . (fboundp 'w3-prepare-buffer))
- ("type" . "text/html")))
- ))
- ("video" . (
- ("mpeg" . (("viewer" . "mpeg_play %s")
- ("type" . "video/mpeg")
- ("test" . (eq (device-type) 'x))
- ("needsx11")))
- ))
- ("x-world" . (
- ("x-vrml" . (("viewer" . "webspace -remote %s -URL %u")
- ("type" . "x-world/x-vrml")
- ("description"
- "VRML document")))))
- ("archive" . (
- ("tar" . (("viewer" . tar-mode)
- ("type" . "archive/tar")
- ("test" . (fboundp 'tar-mode))))
- ))
- )
- "*The mailcap structure is an assoc list of assoc lists.
-1st assoc list is keyed on the major content-type
-2nd assoc list is keyed on the minor content-type (which can be a regexp)
-
-Which looks like:
------------------
-(
- (\"application\"
- (\"postscript\" . <info>)
- )
- (\"text\"
- (\"plain\" . <info>)
- )
-)
-
-Where <info> is another assoc list of the various information
-related to the mailcap RFC. This is keyed on the lowercase
-attribute name (viewer, test, etc). This looks like:
-((\"viewer\" . viewerinfo)
- (\"test\" . testinfo)
- (\"xxxx\" . \"string\")
-)
-
-Where viewerinfo specifies how the content-type is viewed. Can be
-a string, in which case it is run through a shell, with
-appropriate parameters, or a symbol, in which case the symbol is
-funcall'd, with the buffer as an argument.
-
-testinfo is a list of strings, or nil. If nil, it means the
-viewer specified is always valid. If it is a list of strings,
-these are used to determine whether a viewer passes the 'test' or
-not.")
-
-(defvar mm-content-transfer-encodings
- '(("base64" . base64-decode-region)
- ("7bit" . ignore)
- ("8bit" . ignore)
- ("binary" . ignore)
- ("x-compress" . ("uncompress" "-c"))
- ("x-gzip" . ("gzip" "-dc"))
- ("compress" . ("uncompress" "-c"))
- ("gzip" . ("gzip" "-dc"))
- ("x-hqx" . ("mcvert" "-P" "-s" "-S"))
- ("quoted-printable" . mm-decode-quoted-printable)
- )
- "*An assoc list of content-transfer-encodings and how to decode them.")
-
-(defvar mm-download-directory nil
- "*Where downloaded files should go by default.")
-
-(defvar mm-temporary-directory (or (getenv "TMPDIR") "/tmp")
- "*Where temporary files go.")
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; A few things from w3 and url, just in case this is used without them
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defun mm-generate-unique-filename (&optional fmt)
- "Generate a unique filename in mm-temporary-directory"
- (if (not fmt)
- (let ((base (format "mm-tmp.%d" (user-real-uid)))
- (fname "")
- (x 0))
- (setq fname (format "%s%d" base x))
- (while (file-exists-p
- (expand-file-name fname mm-temporary-directory))
- (setq x (1+ x)
- fname (concat base (int-to-string x))))
- (expand-file-name fname mm-temporary-directory))
- (let ((base (concat "mm" (int-to-string (user-real-uid))))
- (fname "")
- (x 0))
- (setq fname (format fmt (concat base (int-to-string x))))
- (while (file-exists-p
- (expand-file-name fname mm-temporary-directory))
- (setq x (1+ x)
- fname (format fmt (concat base (int-to-string x)))))
- (expand-file-name fname mm-temporary-directory))))
-
-(if (and (fboundp 'copy-tree)
- (subrp (symbol-function 'copy-tree)))
- (fset 'mm-copy-tree 'copy-tree)
- (defun mm-copy-tree (tree)
- (if (consp tree)
- (cons (mm-copy-tree (car tree))
- (mm-copy-tree (cdr tree)))
- (if (vectorp tree)
- (let* ((new (copy-sequence tree))
- (i (1- (length new))))
- (while (>= i 0)
- (aset new i (mm-copy-tree (aref new i)))
- (setq i (1- i)))
- new)
- tree))))
-
-;LMI was here
-;(require 'mule-sysdp)
-
-(if (not (fboundp 'w3-save-binary-file))
- (defun mm-save-binary-file ()
- ;; Ok, this is truly fucked. In XEmacs, if you use the mouse to select
- ;; a URL that gets saved via this function, read-file-name will pop up a
- ;; dialog box for file selection. For some reason which buffer we are in
- ;; gets royally screwed (even with save-excursions and the whole nine
- ;; yards). SO, we just keep the old buffer name around and away we go.
- (let ((old-buff (current-buffer))
- (file (read-file-name "Filename to save as: "
- (or mm-download-directory "~/")
- (file-name-nondirectory (url-view-url t))
- nil
- (file-name-nondirectory (url-view-url t))))
- (require-final-newline nil))
- (set-buffer old-buff)
- (mule-write-region-no-coding-system (point-min) (point-max) file)
- (kill-buffer (current-buffer))))
- (fset 'mm-save-binary-file 'w3-save-binary-file))
-
-(defun mm-maybe-eval ()
- "Maybe evaluate a buffer of emacs lisp code"
- (if (yes-or-no-p "This is emacs-lisp code, evaluate it? ")
- (eval-buffer (current-buffer))
- (emacs-lisp-mode)))
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; The mailcap parser
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-viewer-unescape (format &optional filename url)
- (save-excursion
- (set-buffer (get-buffer-create " *mm-parse*"))
- (erase-buffer)
- (insert format)
- (goto-char (point-min))
- (while (re-search-forward "%\\(.\\)" nil t)
- (let ((escape (aref (match-string 1) 0)))
- (replace-match "" t t)
- (case escape
- (?% (insert "%"))
- (?s (insert (or filename "\"\"")))
- (?u (insert (or url "\"\""))))))
- (buffer-string)))
-
-(defun mm-in-assoc (elt list)
- ;; Check to see if ELT matches any of the regexps in the car elements of LIST
- (let (rslt)
- (while (and list (not rslt))
- (and (car (car list))
- (string-match (car (car list)) elt)
- (setq rslt (car list)))
- (setq list (cdr list)))
- rslt))
-
-(defun mm-replace-regexp (regexp to-string)
- ;; Quiet replace-regexp.
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (replace-match to-string t nil)))
-
-(defun mm-parse-mailcaps (&optional path)
- ;; Parse out all the mailcaps specified in a unix-style path string PATH
- (cond
- (path nil)
- ((getenv "MAILCAPS") (setq path (getenv "MAILCAPS")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
- (setq path (mapconcat 'expand-file-name '("~/mail.cap" "~/etc/mail.cap")
- ";")))
- (t (setq path (mapconcat 'expand-file-name
- '("~/.mailcap"
- "/etc/mailcap:/usr/etc/mailcap"
- "/usr/local/etc/mailcap") ":"))))
- (let ((fnames (reverse
- (mm-string-to-tokens path
- (if (memq system-type
- '(ms-dos ms-windows windows-nt))
- ?;
- ?:))))
- fname)
- (while fnames
- (setq fname (car fnames))
- (if (and (file-exists-p fname) (file-readable-p fname))
- (mm-parse-mailcap (car fnames)))
- (setq fnames (cdr fnames)))))
-
-(defun mm-parse-mailcap (fname)
- ;; Parse out the mailcap file specified by FNAME
- (let (major ; The major mime type (image/audio/etc)
- minor ; The minor mime type (gif, basic, etc)
- save-pos ; Misc saved positions used in parsing
- viewer ; How to view this mime type
- info ; Misc info about this mime type
- )
- (save-excursion
- (set-buffer (get-buffer-create " *mailcap*"))
- (erase-buffer)
- (insert-file-contents fname)
- (set-syntax-table mm-parse-args-syntax-table)
- (mm-replace-regexp "#.*" "") ; Remove all comments
- (mm-replace-regexp "\n+" "\n") ; And blank lines
- (mm-replace-regexp "\\\\[ \t\n]+" " ") ; And collapse spaces
- (mm-replace-regexp (concat (regexp-quote "\\") "[ \t]*\n") "")
- (goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n")
- (setq save-pos (point)
- info nil)
- (skip-chars-forward "^/;")
- (downcase-region save-pos (point))
- (setq major (buffer-substring save-pos (point)))
- (skip-chars-forward "/ \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^;")
- (downcase-region save-pos (point))
- (setq minor
- (cond
- ((= ?* (or (char-after save-pos) 0)) ".*")
- ((= (point) save-pos) ".*")
- (t (buffer-substring save-pos (point)))))
- (skip-chars-forward "; \t\n")
- ;;; Got the major/minor chunks, now for the viewers/etc
- ;;; The first item _must_ be a viewer, according to the
- ;;; RFC for mailcap files (#1343)
- (skip-chars-forward "; \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^;\n")
- (if (= (or (char-after save-pos) 0) ?')
- (setq viewer (progn
- (narrow-to-region (1+ save-pos) (point))
- (goto-char (point-min))
- (prog1
- (read (current-buffer))
- (goto-char (point-max))
- (widen))))
- (setq viewer (buffer-substring save-pos (point))))
- (setq save-pos (point))
- (end-of-line)
- (setq info (nconc (list (cons "viewer" viewer)
- (cons "type" (concat major "/"
- (if (string= minor ".*")
- "*" minor))))
- (mm-parse-mailcap-extras save-pos (point))))
- (mm-mailcap-entry-passes-test info)
- (mm-add-mailcap-entry major minor info)))))
-
-(defun mm-parse-mailcap-extras (st nd)
- ;; Grab all the extra stuff from a mailcap entry
- (let (
- name ; From name=
- value ; its value
- results ; Assoc list of results
- name-pos ; Start of XXXX= position
- val-pos ; Start of value position
- done ; Found end of \'d ;s?
- )
- (save-restriction
- (narrow-to-region st nd)
- (goto-char (point-min))
- (skip-chars-forward " \n\t;")
- (while (not (eobp))
- (setq done nil)
- (skip-chars-forward " \";\n\t")
- (setq name-pos (point))
- (skip-chars-forward "^ \n\t=")
- (downcase-region name-pos (point))
- (setq name (buffer-substring name-pos (point)))
- (skip-chars-forward " \t\n")
- (if (/= (or (char-after (point)) 0) ?=) ; There is no value
- (setq value nil)
- (skip-chars-forward " \t\n=")
- (setq val-pos (point))
- (if (memq (char-after val-pos) '(?\" ?'))
- (progn
- (setq val-pos (1+ val-pos))
- (condition-case nil
- (progn
- (forward-sexp 1)
- (backward-char 1))
- (error (goto-char (point-max)))))
- (while (not done)
- (skip-chars-forward "^;")
- (if (= (or (char-after (1- (point))) 0) ?\\ )
- (progn
- (subst-char-in-region (1- (point)) (point) ?\\ ? )
- (skip-chars-forward ";"))
- (setq done t))))
- (setq value (buffer-substring val-pos (point))))
- (setq results (cons (cons name value) results)))
- results)))
-
-(defun mm-string-to-tokens (str &optional delim)
- "Return a list of words from the string STR"
- (setq delim (or delim ? ))
- (let (results y)
- (mapcar
- (function
- (lambda (x)
- (cond
- ((and (= x delim) y) (setq results (cons y results) y nil))
- ((/= x delim) (setq y (concat y (char-to-string x))))
- (t nil)))) str)
- (nreverse (cons y results))))
-
-(defun mm-mailcap-entry-passes-test (info)
- ;; Return t iff a mailcap entry passes its test clause or no test
- ;; clause is present.
- (let (status ; Call-process-regions return value
- (test (assoc "test" info)); The test clause
- )
- (setq status (and test (mm-string-to-tokens (cdr test))))
- (if (and (assoc "needsx11" info) (not (getenv "DISPLAY")))
- (setq status nil)
- (cond
- ((and (equal (nth 0 status) "test")
- (equal (nth 1 status) "-n")
- (or (equal (nth 2 status) "$DISPLAY")
- (equal (nth 2 status) "\"$DISPLAY\"")))
- (setq status (if (getenv "DISPLAY") t nil)))
- ((and (equal (nth 0 status) "test")
- (equal (nth 1 status) "-z")
- (or (equal (nth 2 status) "$DISPLAY")
- (equal (nth 2 status) "\"$DISPLAY\"")))
- (setq status (if (getenv "DISPLAY") nil t)))
- (test nil)
- (t nil)))
- (and test (listp test) (setcdr test status))))
-
-(defun mm-parse-args (st &optional nd nodowncase)
- ;; Return an assoc list of attribute/value pairs from an RFC822-type string
- (let (
- name ; From name=
- value ; its value
- results ; Assoc list of results
- name-pos ; Start of XXXX= position
- val-pos ; Start of value position
- )
- (save-excursion
- (if (stringp st)
- (progn
- (set-buffer (get-buffer-create " *mm-temp*"))
- (set-syntax-table mm-parse-args-syntax-table)
- (erase-buffer)
- (insert st)
- (setq st (point-min)
- nd (point-max)))
- (set-syntax-table mm-parse-args-syntax-table))
- (save-restriction
- (narrow-to-region st nd)
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward "; \n\t")
- (setq name-pos (point))
- (skip-chars-forward "^ \n\t=;")
- (if (not nodowncase)
- (downcase-region name-pos (point)))
- (setq name (buffer-substring name-pos (point)))
- (skip-chars-forward " \t\n")
- (if (/= (or (char-after (point)) 0) ?=) ; There is no value
- (setq value nil)
- (skip-chars-forward " \t\n=")
- (setq val-pos (point)
- value
- (cond
- ((or (= (or (char-after val-pos) 0) ?\")
- (= (or (char-after val-pos) 0) ?'))
- (buffer-substring (1+ val-pos)
- (condition-case ()
- (prog2
- (forward-sexp 1)
- (1- (point))
- (skip-chars-forward "\""))
- (error
- (skip-chars-forward "^ \t\n")
- (point)))))
- (t
- (buffer-substring val-pos
- (progn
- (skip-chars-forward "^;")
- (skip-chars-backward " \t")
- (point)))))))
- (setq results (cons (cons name value) results))
- (skip-chars-forward "; \n\t"))
- results))))
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; The action routines.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-possible-viewers (major minor)
- ;; Return a list of possible viewers from MAJOR for minor type MINOR
- (let ((exact '())
- (wildcard '()))
- (while major
- (cond
- ((equal (car (car major)) minor)
- (setq exact (cons (cdr (car major)) exact)))
- ((string-match (car (car major)) minor)
- (setq wildcard (cons (cdr (car major)) wildcard))))
- (setq major (cdr major)))
- (nconc (nreverse exact) (nreverse wildcard))))
-
-(defun mm-unescape-mime-test (test type-info)
- (let ((buff (get-buffer-create " *unescape*"))
- save-pos save-chr subst)
- (cond
- ((symbolp test) test)
- ((and (listp test) (symbolp (car test))) test)
- ((or (stringp test)
- (and (listp test) (stringp (car test))
- (setq test (mapconcat 'identity test " "))))
- (save-excursion
- (set-buffer buff)
- (erase-buffer)
- (insert test)
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward "^%")
- (if (/= (- (point)
- (progn (skip-chars-backward "\\\\")
- (point)))
- 0) ; It is an escaped %
- (progn
- (delete-char 1)
- (skip-chars-forward "%."))
- (setq save-pos (point))
- (skip-chars-forward "%")
- (setq save-chr (char-after (point)))
- (cond
- ((null save-chr) nil)
- ((= save-chr ?t)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert (or (cdr (assoc "type" type-info)) "\"\"")))
- ((= save-chr ?M)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?n)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?F)
- (delete-region save-pos (progn (forward-char 1) (point)))
- (insert "\"\""))
- ((= save-chr ?{)
- (forward-char 1)
- (skip-chars-forward "^}")
- (downcase-region (+ 2 save-pos) (point))
- (setq subst (buffer-substring (+ 2 save-pos) (point)))
- (delete-region save-pos (1+ (point)))
- (insert (or (cdr (assoc subst type-info)) "\"\"")))
- (t nil))))
- (buffer-string)))
- (t (error "Bad value to mm-unescape-mime-test. %s" test)))))
-
-(defun mm-viewer-passes-test (viewer-info type-info)
- ;; Return non-nil iff the viewer specified by VIEWER-INFO passes its
- ;; test clause (if any).
- (let* ((test-info (assoc "test" viewer-info))
- (test (cdr test-info))
- (viewer (cdr (assoc "viewer" viewer-info)))
- (default-directory (expand-file-name "~/"))
- status
- parsed-test
- )
- (cond
- ((not test-info) t) ; No test clause
- ((not test) nil) ; Already failed test
- ((eq test t) t) ; Already passed test
- ((and (symbolp test) ; Lisp function as test
- (fboundp test))
- (funcall test type-info))
- ((and (symbolp test) ; Lisp variable as test
- (boundp test))
- (symbol-value test))
- ((and (listp test) ; List to be eval'd
- (symbolp (car test)))
- (eval test))
- (t
- (setq test (mm-unescape-mime-test test type-info)
- test (list shell-file-name nil nil nil shell-command-switch test)
- status (apply 'call-process test))
- (= 0 status)))))
-
-(defun mm-add-mailcap-entry (major minor info)
- (let ((old-major (assoc major mm-mime-data)))
- (if (null old-major) ; New major area
- (setq mm-mime-data
- (cons (cons major (list (cons minor info)))
- mm-mime-data))
- (let ((cur-minor (assoc minor old-major)))
- (cond
- ((or (null cur-minor) ; New minor area, or
- (assoc "test" info)) ; Has a test, insert at beginning
- (setcdr old-major (cons (cons minor info) (cdr old-major))))
- ((and (not (assoc "test" info)); No test info, replace completely
- (not (assoc "test" cur-minor)))
- (setcdr cur-minor info))
- (t
- (setcdr old-major (cons (cons minor info) (cdr old-major)))))))))
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; The main whabbo
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-viewer-lessp (x y)
- ;; Return t iff viewer X is more desirable than viewer Y
- (let ((x-wild (string-match "[*?]" (or (cdr-safe (assoc "type" x)) "")))
- (y-wild (string-match "[*?]" (or (cdr-safe (assoc "type" y)) "")))
- (x-lisp (not (stringp (or (cdr-safe (assoc "viewer" x)) ""))))
- (y-lisp (not (stringp (or (cdr-safe (assoc "viewer" y)) "")))))
- (cond
- ((and x-lisp (not y-lisp))
- t)
- ((and (not y-lisp) x-wild (not y-wild))
- t)
- ((and (not x-wild) y-wild)
- t)
- (t nil))))
-
-(defun mm-mime-info (st &optional nd request)
- "Get the mime viewer command for HEADERLINE, return nil if none found.
-Expects a complete content-type header line as its argument. This can
-be simple like text/html, or complex like text/plain; charset=blah; foo=bar
-
-Third argument REQUEST specifies what information to return. If it is
-nil or the empty string, the viewer (second field of the mailcap
-entry) will be returned. If it is a string, then the mailcap field
-corresponding to that string will be returned (print, description,
-whatever). If a number, then all the information for this specific
-viewer is returned."
- (let (
- major ; Major encoding (text, etc)
- minor ; Minor encoding (html, etc)
- info ; Other info
- save-pos ; Misc. position during parse
- major-info ; (assoc major mm-mime-data)
- minor-info ; (assoc minor major-info)
- test ; current test proc.
- viewers ; Possible viewers
- passed ; Viewers that passed the test
- viewer ; The one and only viewer
- )
- (save-excursion
- (cond
- ((null st)
- (set-buffer (get-buffer-create " *mimeparse*"))
- (erase-buffer)
- (insert "text/plain")
- (setq st (point-min)))
- ((stringp st)
- (set-buffer (get-buffer-create " *mimeparse*"))
- (erase-buffer)
- (insert st)
- (setq st (point-min)))
- ((null nd)
- (narrow-to-region st (progn (goto-char st) (end-of-line) (point))))
- (t (narrow-to-region st nd)))
- (goto-char st)
- (skip-chars-forward ": \t\n")
- (buffer-enable-undo)
- (setq viewer
- (catch 'mm-exit
- (setq save-pos (point))
- (skip-chars-forward "^/")
- (downcase-region save-pos (point))
- (setq major (buffer-substring save-pos (point)))
- (if (not (setq major-info (cdr (assoc major mm-mime-data))))
- (throw 'mm-exit nil))
- (skip-chars-forward "/ \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^ \t\n;")
- (downcase-region save-pos (point))
- (setq minor (buffer-substring save-pos (point)))
- (if (not
- (setq viewers (mm-possible-viewers major-info minor)))
- (throw 'mm-exit nil))
- (skip-chars-forward "; \t")
- (if (eolp)
- nil ; No qualifiers
- (setq save-pos (point))
- (end-of-line)
- (setq info (mm-parse-args save-pos (point)))
- )
- (while viewers
- (if (mm-viewer-passes-test (car viewers) info)
- (setq passed (cons (car viewers) passed)))
- (setq viewers (cdr viewers)))
- (setq passed (sort (nreverse passed) 'mm-viewer-lessp))
- (car passed)))
- (if (and (stringp (cdr (assoc "viewer" viewer)))
- passed)
- (setq viewer (car passed)))
- (widen)
- (cond
- ((and (null viewer) (not (equal major "default")))
- (mm-mime-info "default" nil request))
- ((or (null request) (equal request ""))
- (mm-unescape-mime-test (cdr (assoc "viewer" viewer)) info))
- ((stringp request)
- (if (or (string= request "test") (string= request "viewer"))
- (mm-unescape-mime-test (cdr-safe (assoc request viewer)) info)))
- (t
- ;; MUST make a copy *sigh*, else we modify mm-mime-data
- (setq viewer (mm-copy-tree viewer))
- (let ((view (assoc "viewer" viewer))
- (test (assoc "test" viewer)))
- (if view (setcdr view (mm-unescape-mime-test (cdr view) info)))
- (if test (setcdr test (mm-unescape-mime-test (cdr test) info))))
- viewer)))))
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Experimental MIME-types parsing
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defvar mm-mime-extensions
- '(
- ("" . "text/plain")
- (".abs" . "audio/x-mpeg")
- (".aif" . "audio/aiff")
- (".aifc" . "audio/aiff")
- (".aiff" . "audio/aiff")
- (".ano" . "application/x-annotator")
- (".au" . "audio/ulaw")
- (".avi" . "video/x-msvideo")
- (".bcpio" . "application/x-bcpio")
- (".bin" . "application/octet-stream")
- (".cdf" . "application/x-netcdr")
- (".cpio" . "application/x-cpio")
- (".csh" . "application/x-csh")
- (".dvi" . "application/x-dvi")
- (".el" . "application/emacs-lisp")
- (".eps" . "application/postscript")
- (".etx" . "text/x-setext")
- (".exe" . "application/octet-stream")
- (".fax" . "image/x-fax")
- (".gif" . "image/gif")
- (".hdf" . "application/x-hdf")
- (".hqx" . "application/mac-binhex40")
- (".htm" . "text/html")
- (".html" . "text/html")
- (".icon" . "image/x-icon")
- (".ief" . "image/ief")
- (".jpg" . "image/jpeg")
- (".macp" . "image/x-macpaint")
- (".man" . "application/x-troff-man")
- (".me" . "application/x-troff-me")
- (".mif" . "application/mif")
- (".mov" . "video/quicktime")
- (".movie" . "video/x-sgi-movie")
- (".mp2" . "audio/x-mpeg")
- (".mp2a" . "audio/x-mpeg2")
- (".mpa" . "audio/x-mpeg")
- (".mpa2" . "audio/x-mpeg2")
- (".mpe" . "video/mpeg")
- (".mpeg" . "video/mpeg")
- (".mpega" . "audio/x-mpeg")
- (".mpegv" . "video/mpeg")
- (".mpg" . "video/mpeg")
- (".mpv" . "video/mpeg")
- (".ms" . "application/x-troff-ms")
- (".nc" . "application/x-netcdf")
- (".nc" . "application/x-netcdf")
- (".oda" . "application/oda")
- (".pbm" . "image/x-portable-bitmap")
- (".pdf" . "application/pdf")
- (".pgm" . "image/portable-graymap")
- (".pict" . "image/pict")
- (".png" . "image/png")
- (".pnm" . "image/x-portable-anymap")
- (".ppm" . "image/portable-pixmap")
- (".ps" . "application/postscript")
- (".qt" . "video/quicktime")
- (".ras" . "image/x-raster")
- (".rgb" . "image/x-rgb")
- (".rtf" . "application/rtf")
- (".rtx" . "text/richtext")
- (".sh" . "application/x-sh")
- (".sit" . "application/x-stuffit")
- (".snd" . "audio/basic")
- (".src" . "application/x-wais-source")
- (".tar" . "archive/tar")
- (".tcl" . "application/x-tcl")
- (".tcl" . "application/x-tcl")
- (".tex" . "application/x-tex")
- (".texi" . "application/texinfo")
- (".tga" . "image/x-targa")
- (".tif" . "image/tiff")
- (".tiff" . "image/tiff")
- (".tr" . "application/x-troff")
- (".troff" . "application/x-troff")
- (".tsv" . "text/tab-separated-values")
- (".txt" . "text/plain")
- (".vbs" . "video/mpeg")
- (".vox" . "audio/basic")
- (".vrml" . "x-world/x-vrml")
- (".wav" . "audio/x-wav")
- (".wrl" . "x-world/x-vrml")
- (".xbm" . "image/xbm")
- (".xpm" . "image/x-pixmap")
- (".xwd" . "image/windowdump")
- (".zip" . "application/zip")
- (".ai" . "application/postscript")
- (".jpe" . "image/jpeg")
- (".jpeg" . "image/jpeg")
- )
- "*An assoc list of file extensions and the MIME content-types they
-correspond to.")
-
-(defun mm-parse-mimetypes (&optional path)
- ;; Parse out all the mimetypes specified in a unix-style path string PATH
- (cond
- (path nil)
- ((getenv "MIMETYPES") (setq path (getenv "MIMETYPES")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
- (setq path (mapconcat 'expand-file-name
- '("~/mime.typ" "~/etc/mime.typ") ";")))
- (t (setq path (mapconcat 'expand-file-name
- '("~/.mime-types"
- "/etc/mime-types:/usr/etc/mime-types"
- "/usr/local/etc/mime-types"
- "/usr/local/www/conf/mime-types") ":"))))
- (let ((fnames (reverse
- (mm-string-to-tokens path
- (if (memq system-type
- '(ms-dos ms-windows windows-nt))
- ?;
- ?:))))
- fname)
- (while fnames
- (setq fname (car fnames))
- (if (and (file-exists-p fname) (file-readable-p fname))
- (mm-parse-mimetype-file (car fnames)))
- (setq fnames (cdr fnames)))))
-
-(defun mm-parse-mimetype-file (fname)
- ;; Parse out a mime-types file
- (let (type ; The MIME type for this line
- extns ; The extensions for this line
- save-pos ; Misc. saved buffer positions
- )
- (save-excursion
- (set-buffer (get-buffer-create " *mime-types*"))
- (erase-buffer)
- (insert-file-contents fname)
- (mm-replace-regexp "#.*" "")
- (mm-replace-regexp "\n+" "\n")
- (mm-replace-regexp "[ \t]+$" "")
- (goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n")
- (setq save-pos (point))
- (skip-chars-forward "^ \t")
- (downcase-region save-pos (point))
- (setq type (buffer-substring save-pos (point)))
- (while (not (eolp))
- (skip-chars-forward " \t")
- (setq save-pos (point))
- (skip-chars-forward "^ \t\n")
- (setq extns (cons (buffer-substring save-pos (point)) extns)))
- (while extns
- (setq mm-mime-extensions
- (cons
- (cons (if (= (string-to-char (car extns)) ?.)
- (car extns)
- (concat "." (car extns))) type) mm-mime-extensions)
- extns (cdr extns)))))))
-
-(defun mm-extension-to-mime (extn)
- "Return the MIME content type of the file extensions EXTN"
- (if (and (stringp extn)
- (not (eq (string-to-char extn) ?.)))
- (setq extn (concat "." extn)))
- (cdr (assoc (downcase extn) mm-mime-extensions)))
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Editing/Composition of body parts
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-compose-type (type)
- ;; Compose a body section of MIME-type TYPE.
- (let* ((info (mm-mime-info type nil 5))
- (fnam (mm-generate-unique-filename))
- (comp (or (cdr (assoc "compose" info))))
- (ctyp (cdr (assoc "composetyped" info)))
- (buff (get-buffer-create " *mimecompose*"))
- (typeit (not ctyp))
- (retval "")
- (usef nil))
- (setq comp (mm-unescape-mime-test (or comp ctyp) info))
- (while (string-match "\\([^\\\\]\\)%s" comp)
- (setq comp (concat (substring comp 0 (match-end 1)) fnam
- (substring comp (match-end 0) nil))
- usef t))
- (call-process shell-file-name nil
- (if usef nil buff)
- nil shell-command-switch comp)
- (setq retval
- (concat
- (if typeit (concat "Content-type: " type "\r\n\r\n") "")
- (if usef
- (save-excursion
- (set-buffer buff)
- (erase-buffer)
- (insert-file-contents fnam)
- (buffer-string))
- (save-excursion
- (set-buffer buff)
- (buffer-string)))
- "\r\n"))
- retval))
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Misc.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-type-to-file (type)
- "Return the file extension for content-type TYPE"
- (rassoc type mm-mime-extensions))
-
-\f
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Miscellaneous MIME viewers written in elisp
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-play-sound-file (&optional buff)
- "Play a sound file in buffer BUFF (defaults to current buffer)"
- (setq buff (or buff (current-buffer)))
- (let ((fname (mm-generate-unique-filename "%s.au"))
- (synchronous-sounds t)) ; Play synchronously
- (mule-write-region-no-coding-system (point-min) (point-max) fname)
- (kill-buffer (current-buffer))
- (play-sound-file fname)
- (condition-case ()
- (delete-file fname)
- (error nil))))
-
-(defun mm-parse-mime-headers (&optional no-delete)
- "Return a list of the MIME headers at the top of this buffer. If
-optional argument NO-DELETE is non-nil, don't delete the headers."
- (let* ((st (point-min))
- (nd (progn
- (goto-char (point-min))
- (skip-chars-forward " \t\n")
- (if (re-search-forward "^\r*$" nil t)
- (1+ (point))
- (point-max))))
- save-pos
- status
- hname
- hvalu
- result
- search
- )
- (narrow-to-region st (min nd (point-max)))
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n\r")
- (setq save-pos (point))
- (skip-chars-forward "^:\n\r")
- (downcase-region save-pos (point))
- (setq hname (buffer-substring save-pos (point)))
- (skip-chars-forward ": \t ")
- (setq save-pos (point))
- (skip-chars-forward "^\n\r")
- (setq search t)
- (while search
- (skip-chars-forward "^\n\r")
- (save-excursion
- (skip-chars-forward "\n\r")
-
- (setq search
- (string-match "[ \t]"
- (char-to-string
- (or (char-after (point)) ?a)))))
- (if search
- (skip-chars-forward "\n\r")))
- (setq hvalu (buffer-substring save-pos (point))
- result (cons (cons hname hvalu) result)))
- (or no-delete (delete-region st nd))
- result))
-
-(defun mm-find-available-multiparts (separator &optional buf)
- "Return a list of mime-headers for the various body parts of a
-multipart message in buffer BUF with separator SEPARATOR.
-The different multipart specs are put in `mm-temporary-directory'."
- (let ((sep (concat "^--" separator "\r*$"))
- headers
- fname
- results)
- (save-excursion
- (and buf (set-buffer buf))
- (goto-char (point-min))
- (while (re-search-forward sep nil t)
- (let ((st (set-marker (make-marker)
- (progn
- (forward-line 1)
- (beginning-of-line)
- (point))))
- (nd (set-marker (make-marker)
- (if (re-search-forward sep nil t)
- (1- (match-beginning 0))
- (point-max)))))
- (narrow-to-region st nd)
- (goto-char st)
- (if (looking-at "^\r*$")
- (insert "Content-type: text/plain\n"
- "Content-length: " (int-to-string (- nd st)) "\n"))
- (setq headers (mm-parse-mime-headers)
- fname (mm-generate-unique-filename))
- (let ((x (or (cdr (assoc "content-type" headers)) "text/plain")))
- (if (string-match "name=\"*\\([^ \"]+\\)\"*" x)
- (setq fname (expand-file-name
- (substring x (match-beginning 1)
- (match-end 1))
- mm-temporary-directory))))
- (widen)
- (if (assoc "content-transfer-encoding" headers)
- (let ((coding (cdr
- (assoc "content-transfer-encoding" headers)))
- (cmd nil))
- (setq coding (and coding (downcase coding))
- cmd (or (cdr (assoc coding
- mm-content-transfer-encodings))
- (read-string
- (concat "How shall I decode " coding "? ")
- "cat")))
- (if (string= cmd "") (setq cmd "cat"))
- (if (stringp cmd)
- (shell-command-on-region st nd cmd t)
- (funcall cmd st nd))
- (or (eq cmd 'ignore) (set-marker nd (point)))))
- (write-region st nd fname nil 5)
- (delete-region st nd)
- (setq results (cons
- (cons
- (cons "mm-filename" fname) headers) results)))))
- results))
-
-(defun mm-format-multipart-as-html (&optional buf type)
- (if buf (set-buffer buf))
- (let* ((boundary (if (string-match
- "boundary[ \t]*=[ \t\"]*\\([^ \"\t\n]+\\)"
- type)
- (regexp-quote
- (substring type (match-beginning 1) (match-end 1)))))
- (parts (mm-find-available-multiparts boundary)))
- (erase-buffer)
- (insert "<html>\n"
- " <head>\n"
- " <title>Multipart Message</title>\n"
- " </head>\n"
- " <body>\n"
- " <h1> Multipart message encountered </h1>\n"
- " <p> I have encountered a multipart MIME message.\n"
- " The following parts have been detected. Please\n"
- " select which one you want to view.\n"
- " </p>\n"
- " <ul>\n"
- (mapconcat
- (function (lambda (x)
- (concat " <li> <a href=\"file:"
- (cdr (assoc "mm-filename" x))
- "\">"
- (or (cdr (assoc "content-description" x)) "")
- "--"
- (or (cdr (assoc "content-type" x))
- "unknown type")
- "</a> </li>")))
- parts "\n")
- " </ul>\n"
- " </body>\n"
- "</html>\n"
- "<!-- Automatically generated by MM v" mm-version "-->\n")))
-
-(defun mm-multipart-viewer ()
- (mm-format-multipart-as-html
- (current-buffer)
- (cdr (assoc "content-type" url-current-mime-headers)))
- (let ((w3-working-buffer (current-buffer)))
- (w3-prepare-buffer)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Transfer encodings we can decrypt automatically
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun mm-decode-quoted-printable (&optional st nd)
- (interactive)
- (setq st (or st (point-min))
- nd (or nd (point-max)))
- (save-restriction
- (narrow-to-region st nd)
- (save-excursion
- (let ((buffer-read-only nil))
- (goto-char (point-min))
- (while (re-search-forward "=[0-9A-F][0-9A-F]" nil t)
- (replace-match
- (char-to-string
- (+
- (* 16 (mm-hex-char-to-integer
- (char-after (1+ (match-beginning 0)))))
- (mm-hex-char-to-integer
- (char-after (1- (match-end 0))))))))))
- (goto-char (point-max))))
-
-;; Taken from hexl.el.
-(defun mm-hex-char-to-integer (character)
- "Take a char and return its value as if it was a hex digit."
- (if (and (>= character ?0) (<= character ?9))
- (- character ?0)
- (let ((ch (logior character 32)))
- (if (and (>= ch ?a) (<= ch ?f))
- (- ch (- ?a 10))
- (error (format "Invalid hex digit `%c'." ch))))))
-
-
-\f
-(require 'base64)
-(provide 'mm)
+++ /dev/null
-;;; rfc1522.el --- Functions for encoding and decoding rfc1522 messages
-;; Copyright (C) 1998 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'base64)
-(require 'qp)
-(require 'mm-util)
-
-(defvar rfc1522-header-encoding-alist
- '(("Newsgroups" . nil)
- ("Message-ID" . nil)
- (t . mime))
- "*Header/encoding method alist.
-The list is traversed sequentially. The keys can either be
-header regexps or `t'.
-
-The values can be:
-
-1) nil, in which case no encoding is done;
-2) `mime', in which case the header will be encoded according to RFC1522;
-3) a charset, in which case it will be encoded as that charse;
-4) `default', in which case the field will be encoded as the rest
- of the article.")
-
-(defvar rfc1522-charset-encoding-alist
- '((us-ascii . nil)
- (iso-8859-1 . Q)
- (iso-8859-2 . Q)
- (iso-8859-3 . Q)
- (iso-8859-4 . Q)
- (iso-8859-5 . Q)
- (koi8-r . Q)
- (iso-8859-7 . Q)
- (iso-8859-8 . Q)
- (iso-8859-9 . Q)
- (iso-2022-jp . B)
- (iso-2022-kr . B)
- (gb2312 . B)
- (cn-gb . B)
- (cn-gb-2312 . B)
- (euc-kr . B)
- (iso-2022-jp-2 . B)
- (iso-2022-int-1 . B))
- "Alist of MIME charsets to RFC1522 encodings.
-Valid encodings are nil, `Q' and `B'.")
-
-(defvar rfc1522-encoding-function-alist
- '((Q . rfc1522-q-encode-region)
- (B . base64-encode-region)
- (nil . ignore))
- "Alist of RFC1522 encodings to encoding functions.")
-
-(defvar rfc1522-q-encoding-alist
- '(("\\(From\\|Cc\\|To\\|Bcc\||Reply-To\\):" . "[^-A-Za-z0-9!*+/=_]")
- ("." . "[\000-\007\013\015-\037\200-\377=_?]"))
- "Alist of header regexps and valid Q characters.")
-
-;;;
-;;; Functions for encoding RFC1522 messages
-;;;
-
-(defun rfc1522-narrow-to-field ()
- "Narrow the buffer to the header on the current line."
- (beginning-of-line)
- (narrow-to-region
- (point)
- (progn
- (forward-line 1)
- (if (re-search-forward "^[^ \n\t]" nil t)
- (progn
- (beginning-of-line)
- (point))
- (point-max))))
- (goto-char (point-min)))
-
-;;;###autoload
-(defun rfc1522-encode-message-header ()
- "Encode the message header according to `rfc1522-header-encoding-alist'.
-Should be called narrowed to the head of the message."
- (interactive "*")
- (when (featurep 'mule)
- (save-excursion
- (let ((alist rfc1522-header-encoding-alist)
- elem method)
- (while (not (eobp))
- (save-restriction
- (rfc1522-narrow-to-field)
- (when (find-non-ascii-charset-region (point-min) (point-max))
- ;; We found something that may perhaps be encoded.
- (while (setq elem (pop alist))
- (when (or (and (stringp (car elem))
- (looking-at (car elem)))
- (eq (car elem) t))
- (setq alist nil
- method (cdr elem))))
- (when method
- (cond
- ((eq method 'mime)
- (rfc1522-encode-region (point-min) (point-max)))
- ;; Hm.
- (t))))
- (goto-char (point-max))))))))
-
-(defun rfc1522-encode-region (b e)
- "Encode all encodable words in REGION."
- (let (prev c start qstart qprev qend)
- (save-excursion
- (goto-char b)
- (while (re-search-forward "[^ \t\n]+" nil t)
- (save-restriction
- (narrow-to-region (match-beginning 0) (match-end 0))
- (goto-char (setq start (point-min)))
- (setq prev nil)
- (while (not (eobp))
- (unless (eq (setq c (char-charset (following-char))) 'ascii)
- (cond
- ((eq c prev)
- )
- ((null prev)
- (setq qstart (or qstart start)
- qend (point-max)
- qprev c)
- (setq prev c))
- (t
- ;(rfc1522-encode start (setq start (point)) prev)
- (setq prev c))))
- (forward-char 1)))
- (when (and (not prev) qstart)
- (rfc1522-encode qstart qend qprev)
- (setq qstart nil)))
- (when qstart
- (rfc1522-encode qstart qend qprev)
- (setq qstart nil)))))
-
-(defun rfc1522-encode-string (string)
- "Encode words in STRING."
- (with-temp-buffer
- (insert string)
- (rfc1522-encode-region (point-min) (point-max))
- (buffer-string)))
-
-(defun rfc1522-encode (b e charset)
- "Encode the word in the region with CHARSET."
- (let* ((mime-charset (mm-mule-charset-to-mime-charset charset))
- (encoding (cdr (assq mime-charset
- rfc1522-charset-encoding-alist)))
- (start (concat
- "=?" (downcase (symbol-name mime-charset)) "?"
- (downcase (symbol-name encoding)) "?")))
- (save-restriction
- (narrow-to-region b e)
- (insert
- (prog1
- (mm-encode-coding-string (buffer-string) mime-charset)
- (delete-region (point-min) (point-max))))
- (funcall (cdr (assq encoding rfc1522-encoding-function-alist))
- (point-min) (point-max))
- (goto-char (point-min))
- (insert start)
- (goto-char (point-max))
- (insert "?=")
- ;; Encoded words can't be more than 75 chars long, so we have to
- ;; split the long ones up.
- (end-of-line)
- (while (> (current-column) 74)
- (beginning-of-line)
- (forward-char 73)
- (insert "?=\n " start)
- (end-of-line)))))
-
-(defun rfc1522-q-encode-region (b e)
- "Encode the header contained in REGION with the Q encoding."
- (save-excursion
- (save-restriction
- (narrow-to-region (goto-char b) e)
- (let ((alist rfc1522-q-encoding-alist))
- (while alist
- (when (looking-at (caar alist))
- (quoted-printable-encode-region b e nil (cdar alist))
- (subst-char-in-region (point-min) (point-max) ? ?_))
- (pop alist))))))
-
-;;;
-;;; Functions for decoding RFC1522 messages
-;;;
-
-(defvar rfc1522-encoded-word-regexp
- "=\\?\\([^][\000-\040()<>@,\;:\\\"/?.=]+\\)\\?\\(B\\|Q\\)\\?\\([!->@-~]+\\)\\?=")
-
-;;;###autoload
-(defun rfc1522-decode-region (start end)
- "Decode MIME-encoded words in region between START and END."
- (interactive "r")
- (save-excursion
- (save-restriction
- (narrow-to-region start end)
- (goto-char (point-min))
- ;; Remove whitespace between encoded words.
- (while (re-search-forward
- (concat "\\(" rfc1522-encoded-word-regexp "\\)"
- "\\(\n?[ \t]\\)+"
- "\\(" rfc1522-encoded-word-regexp "\\)")
- nil t)
- (delete-region (goto-char (match-end 1)) (match-beginning 6)))
- ;; Decode the encoded words.
- (goto-char (point-min))
- (while (re-search-forward rfc1522-encoded-word-regexp nil t)
- (insert (rfc1522-parse-and-decode
- (prog1
- (match-string 0)
- (delete-region (match-beginning 0) (match-end 0)))))))))
-
-;;;###autoload
-(defun rfc1522-decode-string (string)
- "Decode the quoted-printable-encoded STRING and return the results."
- (with-temp-buffer
- (insert string)
- (inline
- (rfc1522-decode-region (point-min) (point-max)))
- (buffer-string)))
-
-(defun rfc1522-parse-and-decode (word)
- "Decode WORD and return it if it is an encoded word.
-Return WORD if not."
- (if (not (string-match rfc1522-encoded-word-regexp word))
- word
- (or
- (condition-case nil
- (rfc1522-decode
- (match-string 1 word)
- (upcase (match-string 2 word))
- (match-string 3 word))
- (error word))
- word)))
-
-(defun rfc1522-decode (charset encoding string)
- "Decode STRING as an encoded text.
-Valid ENCODINGs are \"B\" and \"Q\".
-If your Emacs implementation can't decode CHARSET, it returns nil."
- (let ((cs (mm-charset-to-coding-system charset)))
- (when cs
- (mm-decode-coding-string
- (cond
- ((equal "B" encoding)
- (base64-decode string))
- ((equal "Q" encoding)
- (quoted-printable-decode-string
- (mm-replace-chars-in-string string ?_ ? )))
- (t (error "Invalid encoding: %s" encoding)))
- cs))))
-
-(provide 'rfc1522)
-
-;;; rfc1522.el ends here
+++ /dev/null
-This package contains a beta version of Gnus. The lisp directory
-contains the source lisp files, and the texi directory contains a
-draft of the Gnus info pages.
-
-To use Gnus you first have to unpack the files, which you've obviously
-done, because you are reading this.
-
-You should definitely byte-compile the source files. To do that, you
-can simply say "./configure; make" in this directory. If you are
-using XEmacs, you *must* say "make EMACS=xemacs". In that case you
-may also want to pull down the package of nice glyphs from
-<URL:http://www.gnus.org/etc.tar.gz>. It should be installed
-into the "gnus-5.4.53/etc" directory.
-
-Then you have to tell Emacs where Gnus is. You might put something
-like
-
- (setq load-path (cons (expand-file-name "~/gnus-5.4.53/lisp") load-path))
-
-in your .emacs file, or wherever you keep such things.
-
-To enable reading the Gnus manual, you could say something like:
-
- (setq Info-default-directory-list
- (cons "~/gnus-5.4.53/texi" Info-default-directory-list))
-
-Note that Gnus and GNUS can't coexist in a single Emacs. They both use
-the same function and variable names. If you have been running GNUS
-in your Emacs, you should probably exit that Emacs and start a new one
-to fire up Gnus.
-
-Gnus does absolutely not work with anything older than Emacs 19.33 or
-XEmacs 19.14. So you definitely need a new Emacs.
-
-Then you do a `M-x gnus', and everything should... uhm... it should
-work, but it might not. Set `debug-on-error' to t, and mail me the
-backtraces, or, better yet, find out why Gnus does something wrong,
-fix it, and send me the diffs. :-)
-
-There are four main things I want your help and input on:
-
-1) Startup. Does everything go smoothly, and why not?
-
-2) Any errors while you read news normally?
-
-3) Any errors if you do anything abnormal?
-
-4) Features you do not like, or do like, but would like to tweak a
- bit, and features you would like to see.
-
-Send any comments and all your bug fixes/complaints to
-`bugs@gnus.org'.
+++ /dev/null
-TEXI2DVI=texi2dvi
-EMACS=emacs
-MAKEINFO=$(EMACS) -batch -q -no-site-file
-INFOSWI=-l texinfmt -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer
-XINFOSWI=-l texinfmt -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer
-LATEX=latex
-DVIPS=dvips
-PERL=perl
-INFODIR=/usr/local/info
-
-all: gnus message
-
-most: texi2latex.elc latex latexps
-
-.SUFFIXES: .texi .dvi .ps
-
-.texi:
- $(MAKEINFO) -eval '(find-file "$<")' $(XINFOSWI)
-
-dvi: gnus.dvi message.dvi
-
-.texi.dvi :
- $(PERL) -n -e 'print unless (/\@iflatex/ .. /\@end iflatex/)' $< > gnustmp.texi
- $(TEXI2DVI) gnustmp.texi
- cp gnustmp.dvi $*.dvi
- rm gnustmp.*
-
-refcard.dvi: refcard.tex gnuslogo.refcard gnusref.tex
- $(LATEX) refcard.tex
-
-clean:
- rm -f gnus.*.bak *.ky *.cp *.fn *.cps *.kys *.log *.aux *.dvi *.vr \
- *.tp *.toc *.pg gnus.latexi *.aux *.[cgk]idx \
- gnus.ilg gnus.ind gnus.[cgk]ind gnus.idx \
- gnus.tmptexi *.tmplatexi gnus.tmplatexi1 texput.log *.orig *.rej \
- gnus.latexi*~* tmp/*.ps xface.tex picons.tex smiley.tex *.latexi
-
-makeinfo:
- makeinfo -o gnus gnus.texi
- makeinfo -o message message.texi
-
-texi2latex.elc: texi2latex.el
- $(EMACS) -batch -l bytecomp --eval '(byte-compile-file "texi2latex.el")'
-
-latex: gnus.texi texi2latex.elc
- $(EMACS) -batch -q -no-site-file gnus.texi -l ./texi2latex.elc -f latexi-translate
-
-latexps:
- make texi2latex.elc
- rm -f gnus.aux
- egrep -v "label.*Index|chapter.*Index" gnus.latexi > gnus.tmplatexi1
- $(LATEX) gnus.tmplatexi1
- ./splitindex
- makeindex -o gnus.kind gnus.kidx
- makeindex -o gnus.cind gnus.cidx
- makeindex -o gnus.gind gnus.gidx
- sed 's/\\char 5E\\relax {}/\\symbol{"5E}/' < gnus.kind > gnus.tmpkind
- mv gnus.tmpkind gnus.kind
- egrep -v "end{document}" gnus.tmplatexi1 > gnus.tmplatexi
- cat postamble.tex >> gnus.tmplatexi
- $(LATEX) gnus.tmplatexi
- $(LATEX) gnus.tmplatexi
- $(DVIPS) -f gnus.dvi > gnus.ps
-
-pss:
- make latex
- make latexps
-
-psout:
- make latex
- make latexboth
- make out
-
-latexboth:
- rm -f gnus-manual-a4.ps.gz gnus-manual-standard.ps.gz
- make latexps
- mv /local/tmp/larsi/gnus.ps /local/tmp/larsi/gnus-manual-a4.ps
- gzip /local/tmp/larsi/gnus-manual-a4.ps
- sed 's/,a4paper//' gnus.latexi > gnus-standard.latexi
- mv gnus-standard.latexi gnus.latexi
- make latexps
- mv /local/tmp/larsi/gnus.ps /local/tmp/larsi/gnus-manual-standard.ps
- gzip /local/tmp/larsi/gnus-manual-standard.ps
-
-out:
- cp /local/tmp/larsi/gnus-manual-standard.ps.gz \
- /local/tmp/larsi/gnus-manual-a4.ps.gz \
- /local/ftp/pub/emacs/gnus/manual
- mv /local/tmp/larsi/gnus-manual-standard.ps.gz \
- /local/tmp/larsi/gnus-manual-a4.ps.gz \
- /hom/larsi/www_docs/www.gnus.org/documents
-
-veryclean:
- make clean
- rm -f gnus.dvi gnus.ps
-
-distclean:
- make clean
- rm -f *.orig *.rej *.elc *~ gnus gnus-[0-9] gnus-[0-9][0-9]
- rm -f message message-[0-9]
-
-install:
- cp gnus gnus-[0-9] gnus-[0-9][0-9] $(INFODIR)
- cp message $(INFODIR)
-
-
-tmps:
- if [ ! -e tmp ]; then mkdir tmp; fi
- make screens
- make herdss
- make etcs
- make piconss
- make xfaces
- make smiley
- make miscs
-
-herdss:
- cd herds ; for i in new-herd-[0-9]*.gif; do echo $$i; giftopnm $$i | pnmcrop -white | pnmmargin -white 9 | pnmscale 2 | pnmconvol convol5.pnm | ppmtopgm | pnmdepth 255 | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done
- cd herds ; giftopnm new-herd-section.gif | pnmscale 4 | pnmconvol convol11.pnm | ppmtopgm | pnmdepth 255 | pnmtops -noturn -width 100 -height 100 > ../tmp/new-herd-section.ps
-
-
-screens:
- cd screen ; for i in *.gif; do echo $$i; giftopnm $$i | pnmmargin -black 1 | ppmtopgm | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done
-
-miscs:
- giftopnm misc/larsi.gif | ppmtopgm | pnmtops -noturn > tmp/larsi.ps
- tifftopnm misc/eseptember.tif | pnmscale 4 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/september.ps
- tifftopnm misc/fseptember.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fseptember.ps
- tifftopnm misc/fred.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fred.ps
- tifftopnm misc/ered.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/red.ps
-
-etcs:
- cd etc; for i in gnus-*.xpm; do echo $$i; xpmtoppm $$i | ppmtopgm | pnmdepth 255 | pnmtops -noturn > ../tmp/`basename $$i .xpm`.ps; done
-
-piconss:
- cd picons; for i in *.xbm; do echo $$i; xbmtopbm $$i | pnmtops -noturn > ../tmp/picons-`basename $$i .xbm`.ps; done
- cd picons; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/picons-`basename $$i .gif`.ps; done
- for i in tmp/picons-*.ps; do echo "\\gnuspicon{$$i}"; done > picons.tex
-
-xfaces:
- cd xface; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/xface-`basename $$i .gif`.ps; done
- for i in tmp/xface-*.ps; do \
- if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \
- a="h"; echo -n "\\gnusxface{$$i}"; fi done > xface.tex; \
- if [ -n "$$a" ]; then echo "{$$i}" >> xface.tex; fi
-
-smiley:
- cd smilies; tifftopnm BigFace.tif | ppmtopgm | pnmtops > ../tmp/BigFace.ps
- cd smilies; for i in *.xpm; do echo $$i; sed "s/none/#FFFFFF/" $$i | xpmtoppm | ppmtopgm | pnmdepth 255 | pnmtops > ../tmp/smiley-`basename $$i .xpm`.ps; done
- for i in tmp/smiley-*.ps; do \
- if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \
- a="h"; echo -n "\\gnussmiley{$$i}"; fi done > smiley.tex; \
- if [ -n "$$a" ]; then echo "{$$i}" >> smiley.tex; fi
-
-pspackage:
- tar czvf pspackage.tar.gz gnus-faq.texi gnus.texi herds misc pagestyle.sty picons pixidx.sty postamble.tex ps screen smilies splitindex texi2latex.el xface Makefile README etc
-
-complete:
- make texi2latex.elc
- make tmps
- make pss
+++ /dev/null
-\input texinfo.tex
-
-@c %**start of header
-@setfilename custom
-@settitle The Customization Library
-@iftex
-@afourpaper
-@headings double
-@end iftex
-@c %**end of header
-
-@node Top, Introduction, (dir), (dir)
-@comment node-name, next, previous, up
-@top The Customization Library
-
-Version: 1.82
-
-@menu
-* Introduction::
-* User Commands::
-* The Customization Buffer::
-* Declarations::
-* Utilities::
-* The Init File::
-* Wishlist::
-@end menu
-
-@node Introduction, User Commands, Top, Top
-@comment node-name, next, previous, up
-@section Introduction
-
-This library allows customization of @dfn{user options}. Currently two
-types of user options are supported, namely @dfn{variables} and
-@dfn{faces}. Each user option can have four different values
-simultaneously:
-@table @dfn
-@item factory setting
-The value specified by the programmer.
-@item saved value
-The value saved by the user as the default for this variable. This
-overwrites the factory setting when starting a new emacs.
-@item current value
-The value used by Emacs. This will not be remembered next time you
-run Emacs.
-@item widget value
-The value entered by the user in a customization buffer, but not yet
-applied.
-@end table
-
-Variables also have a @dfn{type}, which specifies what kind of values
-the variable can hold, and how the value is presented in a customization
-buffer. By default a variable can hold any valid expression, but the
-programmer can specify a more limited type when declaring the variable.
-
-The user options are organized in a number of @dfn{groups}. Each group
-can contain a number user options, as well as other groups. The groups
-allows the user to concentrate on a specific part of emacs.
-
-@node User Commands, The Customization Buffer, Introduction, Top
-@comment node-name, next, previous, up
-@section User Commands
-
-The following commands will create a customization buffer:
-
-@table @code
-@item customize
-Create a customization buffer containing a specific group, by default
-the @code{emacs} group.
-
-@item customize-variable
-Create a customization buffer containing a single variable.
-
-@item customize-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, Declarations, User Commands, Top
-@comment node-name, next, previous, up
-@section The Customization Buffer.
-
-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 customization buffer contains three types of text:
-
-@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
-
-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.
-
-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.
-
-@menu
-* The Introductory Text::
-* The Customization Options::
-* The Variable Options::
-* The Face Options::
-* The Group Options::
-* The State Button::
-* The Customization Buttons::
-@end menu
-
-@node The Introductory Text, The Customization Options, The Customization Buffer, The Customization Buffer
-@comment node-name, next, previous, up
-@subsection The Introductory Text
-
-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
- State: this item is unchanged from its factory setting.
- [ ] [?] 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 State: this item is unchanged from its factory setting.
-The state line. This line will explain 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. set
-or reset the changes you have made. This is explained in detail in the
-following sections.
-
-@item [ ]
-The magic button. This is an abbreviated version of the state line.
-
-@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 lisp
-value for that variable. The lisp 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
-lisp 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 lisp' 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 lisp
-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 lisp} from the menu.
-
-You can change the state of the variable with the other menu items:
-
-@table @samp
-@item Set
-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 Save
-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 Saved
-Activating this item will reset the value of the variable to the last
-value you marked as permanent with `Save'.
-
-@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. You do this by
-activating `Edit All' in the state menu.
-
-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)
- State: this item is unchanged from its factory setting.
- [ ] Face used when the customize item is invalid.
- [INS] [DEL] Display: [ ] Type: [ ] X [ ] PM [ ] Win32 [ ] DOS [ ] 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 what window system the device belongs to, 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 those listed.
-
-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{Set} 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{Set} 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 Line and The Magic Button
-
-The state line 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.
-
-For the magic button, 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 item has has been set by the user.
-
-@item :
-The current value of this option is different from the saved value.
-
-@item !
-The saved 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
-[Set] [Save] [Reset] [Done]
-@end example
-
-Activating the @samp{[Set]}, @samp{[Save]}, or @samp{[Reset]}
-button will affect all modified customization items that are visible in
-the buffer. @samp{[Done]} will bury the buffer.
-
-@node Declarations, Utilities, The Customization Buffer, Top
-@comment node-name, next, previous, up
-@section Declarations
-
-This section describes how to declare customization groups, variables,
-and faces. It doesn't contain any examples, but please look at the file
-@file{cus-edit.el} which contains many declarations you can learn from.
-
-@menu
-* Declaring Groups::
-* Declaring Variables::
-* Declaring Faces::
-* Usage for Package Authors::
-@end menu
-
-All the customization declarations can be changes by keyword arguments.
-Groups, variables, and faces all share these common keywords:
-
-@table @code
-@item :group
-@var{value} should be a customization group.
-Add @var{symbol} to that group.
-@item :link
-@var{value} should be a widget type.
-Add @var{value} to the extrenal links for this customization option.
-Useful widget types include @code{custom-manual}, @code{info-link}, and
-@code{url-link}.
-@item :load
-Add @var{value} to the files that should be loaded nefore displaying
-this customization option. The value should be iether a string, which
-should be a string which will be loaded with @code{load-library} unless
-present in @code{load-history}, or a symbol which will be loaded with
-@code{require}.
-@item :tag
-@var{Value} should be a short string used for identifying the option in
-customization menus and buffers. By default the tag will be
-automatically created from the options name.
-@end table
-
-@node Declaring Groups, Declaring Variables, Declarations, Declarations
-@comment node-name, next, previous, up
-@subsection Declaring Groups
-
-Use @code{defgroup} to declare new customization groups.
-
-@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
-
-Internally, custom uses the symbol property @code{custom-group} to keep
-track of the group members, and @code{group-documentation} for the
-documentation string.
-
-The following additional @var{keyword}'s are defined:
-
-@table @code
-@item :prefix
-@var{value} should be a string. If the string is a prefix for the name
-of a member of the group, that prefix will be ignored when creating a
-tag for that member.
-@end table
-@end defun
-
-@node Declaring Variables, Declaring Faces, Declaring Groups, Declarations
-@comment node-name, next, previous, up
-@subsection Declaring Variables
-
-Use @code{defcustom} to declare user editable variables.
-
-@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}.
-
-@var{doc} is the variable documentation.
-
-The following additional @var{keyword}'s are defined:
-
-@table @code
-@item :type
-@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.
-@end table
-
-@xref{Sexp Types,,,widget,The Widget Library}, for information about
-widgets to use together with the @code{:type} keyword.
-@end defun
-
-Internally, custom uses the symbol property @code{custom-type} to keep
-track of the variables type, @code{factory-value} for the program
-specified default value, @code{saved-value} for a value saved by the
-user, and @code{variable-documentation} for the documentation string.
-
-Use @code{custom-add-option} to specify that a specific function is
-useful as an meber of a hook.
-
-@defun custom-add-option symbol option
-To the variable @var{symbol} add @var{option}.
-
-If @var{symbol} is a hook variable, @var{option} should be a hook
-member. For other types variables, the effect is undefined."
-@end defun
-
-@node Declaring Faces, Usage for Package Authors, Declaring Variables, Declarations
-@comment node-name, next, previous, up
-@subsection Declaring Faces
-
-Faces are declared with @code{defface}.
-
-@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.
-
-If @var{face} has been set with `custom-set-face', set the face attributes
-as specified by that function, otherwise set the face attributes
-according to @var{spec}.
-
-@var{doc} is the face documentation.
-
-@var{spec} should be an alist of the form @samp{((@var{display} @var{atts})...)}.
-
-@var{atts} is a list of face attributes and their values. The possible
-attributes are defined in the variable `custom-face-attributes'.
-Alternatively, @var{atts} can be a face in which case the attributes of
-that face is used.
-
-The @var{atts} of the first entry in @var{spec} where the @var{display}
-matches the frame should take effect in that frame. @var{display} can
-either be the symbol `t', which will match all frames, or an alist of
-the form @samp{((@var{req} @var{item}...)...)}@refill
-
-For the @var{display} to match a FRAME, the @var{req} property of the
-frame must match one of the @var{item}. The following @var{req} are
-defined:@refill
-
-@table @code
-@item type
-(the value of (window-system))@*
-Should be one of @code{x} or @code{tty}.
-
-@item class
-(the frame's color support)@*
-Should be one of @code{color}, @code{grayscale}, or @code{mono}.
-
-@item background
-(what color is used for the background text)@*
-Should be one of @code{light} or @code{dark}.
-@end table
-
-Internally, custom uses the symbol property @code{factory-face} for the
-program specified default face properties, @code{saved-face} for
-properties saved by the user, and @code{face-doc-string} for the
-documentation string.@refill
-
-@end defun
-
-@node Usage for Package Authors, , Declaring Faces, Declarations
-@comment node-name, next, previous, up
-@subsection Usage for Package Authors
-
-The recommended usage for the author of a typical emacs lisp package is
-to create one group identifying the package, and make all user options
-and faces members of that group. If the package has more than around 20
-such options, they should be divided into a number of subgroups, with
-each subgroup being member of the top level group.
-
-The top level group for the package should itself be member of one or
-more of the standard customization groups. There exists a group for
-each @emph{finder} keyword. Press @kbd{C-c p} to see a list of finder
-keywords, and add you group to each of them, using the @code{:group}
-keyword.
-
-@node Utilities, The Init File, Declarations, Top
-@comment node-name, next, previous, up
-@section Utilities
-
-These utilities can come in handy when adding customization support.
-
-@deffn Widget custom-manual
-Widget type for specifying the info manual entry for a customization
-option. It takes one argument, an info address.
-@end deffn
-
-@defun custom-add-to-group group member widget
-To existing @var{group} add a new @var{member} of type @var{widget},
-If there already is an entry for that member, overwrite it.
-@end defun
-
-@defun custom-add-link symbol widget
-To the custom option @var{symbol} add the link @var{widget}.
-@end defun
-
-@defun custom-add-load symbol load
-To the custom option @var{symbol} add the dependency @var{load}.
-@var{load} should be either a library file name, or a feature name.
-@end defun
-
-@defun custom-menu-create symbol &optional name
-Create menu for customization group @var{symbol}.
-If optional @var{name} is given, use that as the name of the menu.
-Otherwise make up a name from @var{symbol}.
-The menu is in a format applicable to @code{easy-menu-define}.
-@end defun
-
-@node The Init File, Wishlist, Utilities, Top
-@comment node-name, next, previous, up
-@section The Init File
-
-When you save the customizations, call to @code{custom-set-variables},
-@code{custom-set-faces} are inserted into the file specified by
-@code{custom-file}. By default @code{custom-file} is your @file{.emacs}
-file. If you use another file, you must explicitly load it yourself.
-The two functions will initialize variables and faces as you have
-specified.
-
-@node Wishlist, , The Init File, Top
-@comment node-name, next, previous, up
-@section Wishlist
-
-@itemize @bullet
-@item
-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.
-
-@item
-Better support for keyboard operations in the customize buffer.
-
-@item
-Integrate with @file{w3} so you can customization buffers with much
-better formatting. I'm thinking about adding a <custom>name</custom>
-tag. The latest w3 have some support for this, so come up with a
-convincing example.
-
-@item
-Add an `examples' section, with explained examples of custom type
-definitions.
-
-@item
-Support selectable color themes. I.e., change many faces by setting one
-variable.
-
-@item
-Support undo using lmi's @file{gnus-undo.el}.
-
-@item
-Make it possible to append to `choice', `radio', and `set' options.
-
-@item
-Make it possible to customize code, for example to enable or disable a
-global minor mode.
-
-@item
-Ask whether set or modified variables should be saved in
-@code{kill-buffer-hook}.
-
-Ditto for @code{kill-emacs-query-functions}.
-
-@item
-Command to check if there are any customization options that
-does not belong to an existing group.
-
-@item
-Optionally disable the point-cursor and instead highlight the selected
-item in XEmacs. This is like the *Completions* buffer in XEmacs.
-Suggested by Jens Lautenbacher
-@samp{<jens@@lemming0.lem.uni-karlsruhe.de>}.@refill
-
-@item
-Empty customization groups should start open (harder than it looks).
-
-@item
-Make it possible to include a comment/remark/annotation when saving an
-option.
-
-@end itemize
-
-@contents
-@bye
+++ /dev/null
-\input texinfo.tex
-
-@c %**start of header
-@setfilename widget
-@settitle The Emacs Widget Library
-@iftex
-@afourpaper
-@headings double
-@end iftex
-@c %**end of header
-
-@node Top, Introduction, (dir), (dir)
-@comment node-name, next, previous, up
-@top The Emacs Widget Library
-
-Version: 1.82
-
-@menu
-* Introduction::
-* User Interface::
-* Programming Example::
-* Setting Up the Buffer::
-* Basic Types::
-* Sexp Types::
-* Widget Properties::
-* Defining New Widgets::
-* Widget Wishlist.::
-@end menu
-
-@node Introduction, User Interface, Top, Top
-@comment node-name, next, previous, up
-@section Introduction
-
-Most graphical user interface toolkits, such as Motif and XView, provide
-a number of standard user interface controls (sometimes known as
-`widgets' or `gadgets'). Emacs doesn't really support anything like
-this, except for an incredible powerful text ``widget''. On the other
-hand, Emacs does provide the necessary primitives to implement many
-other widgets within a text buffer. The @code{widget} package
-simplifies this task.
-
-The basic widgets are:
-
-@table @code
-@item link
-Areas of text with an associated action. Intended for hypertext links
-embedded in text.
-@item push-button
-Like link, but intended for stand-alone buttons.
-@item editable-field
-An editable text field. It can be either variable or fixed length.
-@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-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{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.
-@item toggle
-A simple @samp{on}/@samp{off} switch.
-@item checkbox
-A checkbox (@samp{[ ]}/@samp{[X]}).
-@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
-
-Now of what possible use can support for widgets be in a text editor?
-I'm glad you asked. The answer is that widgets are useful for
-implementing forms. A @dfn{form} in emacs is a buffer where the user is
-supposed to fill out a number of fields, each of which has a specific
-meaning. The user is not supposed to change or delete any of the text
-between the fields. Examples of forms in Emacs are the @file{forms}
-package (of course), the customize buffers, the mail and news compose
-modes, and the @sc{html} form support in the @file{w3} browser.
-
-The advantages for a programmer of using the @code{widget} package to
-implement forms are:
-
-@enumerate
-@item
-More complex field than just editable text are supported.
-@item
-You can give the user immediate feedback if he enters invalid data in a
-text field, and sometimes prevent entering invalid data.
-@item
-You can have fixed sized fields, thus allowing multiple field to be
-lined up in columns.
-@item
-It is simple to query or set the value of a field.
-@item
-Editing happens in buffer, not in the mini-buffer.
-@item
-Packages using the library get a uniform look, making them easier for
-the user to learn.
-@item
-As support for embedded graphics improve, the widget library will
-extended to support it. This means that your code using the widget
-library will also use the new graphic features by automatic.
-@end enumerate
-
-In order to minimize the code that is loaded by users who does not
-create any widgets, the code has been split in two files:
-
-@table @file
-@item widget.el
-This will declare the user variables, define the function
-@code{widget-define}, and autoload the function @code{widget-create}.
-@item wid-edit.el
-Everything else is here, there is no reason to load it explicitly, as
-it will be autoloaded when needed.
-@end table
-
-@node User Interface, Programming Example, Introduction, Top
-@comment node-name, next, previous, up
-@section User Interface
-
-A form consist of read only text for documentation and some fields,
-where each the fields contain two parts, as tag and a value. The tags
-are used to identify the fields, so the documentation can refer to the
-foo field, meaning the field tagged with @samp{Foo}. Here is an example
-form:
-
-@example
-Here is some documentation.
-
-Name: @i{My Name} @strong{Choose}: This option
-Address: @i{Some Place
-In some City
-Some country.}
-
-See also @b{_other work_} for more information.
-
-Numbers: count to three below
-@b{[INS]} @b{[DEL]} @i{One}
-@b{[INS]} @b{[DEL]} @i{Eh, two?}
-@b{[INS]} @b{[DEL]} @i{Five!}
-@b{[INS]}
-
-Select multiple:
-
-@b{[X]} This
-@b{[ ]} That
-@b{[X]} Thus
-
-Select one:
-
-@b{(*)} One
-@b{( )} Another One.
-@b{( )} A Final One.
-
-@b{[Apply Form]} @b{[Reset Form]}
-@end example
-
-The top level widgets in is example are tagged @samp{Name},
-@samp{Choose}, @samp{Address}, @samp{_other work_}, @samp{Numbers},
-@samp{Select multiple}, @samp{Select one}, @samp{[Apply Form]}, and
-@samp{[Reset Form]}. There are basically two thing the user can do within
-a form, namely editing the editable text fields and activating the
-buttons.
-
-@subsection Editable Text Fields
-
-In the example, the value for the @samp{Name} is most likely displayed
-in an editable text field, and so are values for each of the members of
-the @samp{Numbers} list. All the normal Emacs editing operations are
-available for editing these fields. The only restriction is that each
-change you make must be contained within a single editable text field.
-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{editable-field} widget.
-
-The editing text fields are highlighted with the
-@code{widget-field-face} face, making them easy to find.
-
-@deffn Face widget-field-face
-Face used for other editing fields.
-@end deffn
-
-@subsection Buttons
-
-Some portions of the buffer have an associated @dfn{action}, which can
-be @dfn{activated} by a standard key or mouse command. These portions
-are called @dfn{buttons}. The default commands for activating a button
-are:
-
-@table @kbd
-@item @key{RET}
-@deffn Command widget-button-press @var{pos} &optional @var{event}
-Activate the button at @var{pos}, defaulting to point.
-If point is not located on a button, activate the binding in
-@code{widget-global-map} (by default the global map).
-@end deffn
-
-@item mouse-2
-@deffn Command widget-button-click @var{event}
-Activate the button at the location of the mouse pointer. If the mouse
-pointer is located in an editable text field, activate the binding in
-@code{widget-global-map} (by default the global map).
-@end deffn
-@end table
-
-There are several different kind of buttons, all of which are present in
-the example:
-
-@table @emph
-@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{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{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
-any purpose, such as implementing hypertext references. They are
-usually created by the @code{link} widget.
-@item The @samp{@b{[ ]}} and @samp{@b{[X]}} buttons.
-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-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-button} widget. The main
-difference from the @code{link} widget is that the buttons are will be
-displayed as GUI buttons when possible.
-enough.
-@end table
-
-To make them easier to locate, buttons are emphasized in the buffer.
-
-@deffn Face widget-button-face
-Face used for buttons.
-@end deffn
-
-@defopt widget-mouse-face
-Face used for buttons when the mouse pointer is above it.
-@end defopt
-
-@subsection Navigation
-
-You can use all the normal Emacs commands to move around in a form
-buffer, plus you will have these additional commands:
-
-@table @kbd
-@item @key{TAB}
-@deffn Command widget-forward &optional count
-Move point @var{count} buttons or editing fields forward.
-@end deffn
-@item @key{M-TAB}
-@deffn Command widget-backward &optional count
-Move point @var{count} buttons or editing fields backward.
-@end deffn
-@end table
-
-@node Programming Example, Setting Up the Buffer, User Interface, Top
-@comment node-name, next, previous, up
-@section Programming Example
-
-Here is the code to implement the user interface example (see @ref{User
-Interface}).
-
-@lisp
-(require 'widget)
-
-(eval-when-compile
- (require 'wid-edit))
-
-(defvar widget-example-repeat)
-
-(defun widget-example ()
- "Create the widgets from the Widget manual."
- (interactive)
- (switch-to-buffer "*Widget Example*")
- (kill-all-local-variables)
- (make-local-variable 'widget-example-repeat)
- (let ((inhibit-read-only t))
- (erase-buffer))
- (widget-insert "Here is some documentation.\n\nName: ")
- (widget-create 'editable-field
- :size 13
- "My Name")
- (widget-create 'menu-choice
- :tag "Choose"
- :value "This"
- :help-echo "Choose me, please!"
- :notify (lambda (widget &rest ignore)
- (message "%s is a good choice!"
- (widget-value widget)))
- '(item :tag "This option" :value "This")
- '(choice-item "That option")
- '(editable-field :menu-tag "No option" "Thus option"))
- (widget-insert "Address: ")
- (widget-create 'editable-field
- "Some Place\nIn some City\nSome country.")
- (widget-insert "\nSee also ")
- (widget-create 'link
- :notify (lambda (&rest ignore)
- (widget-value-set widget-example-repeat
- '("En" "To" "Tre"))
- (widget-setup))
- "other work")
- (widget-insert " for more information.\n\nNumbers: count to three below\n")
- (setq widget-example-repeat
- (widget-create 'editable-list
- :entry-format "%i %d %v"
- :notify (lambda (widget &rest ignore)
- (let ((old (widget-get widget
- ':example-length))
- (new (length (widget-value widget))))
- (unless (eq old new)
- (widget-put widget ':example-length new)
- (message "You can count to %d." new))))
- :value '("One" "Eh, two?" "Five!")
- '(editable-field :value "three")))
- (widget-insert "\n\nSelect multiple:\n\n")
- (widget-create 'checkbox t)
- (widget-insert " This\n")
- (widget-create 'checkbox nil)
- (widget-insert " That\n")
- (widget-create 'checkbox
- :notify (lambda (&rest ignore) (message "Tickle"))
- t)
- (widget-insert " Thus\n\nSelect one:\n\n")
- (widget-create 'radio-button-choice
- :value "One"
- :notify (lambda (widget &rest ignore)
- (message "You selected %s"
- (widget-value widget)))
- '(item "One") '(item "Anthor One.") '(item "A Final One."))
- (widget-insert "\n")
- (widget-create 'push-button
- :notify (lambda (&rest ignore)
- (if (= (length (widget-value widget-example-repeat))
- 3)
- (message "Congratulation!")
- (error "Three was the count!")))
- "Apply Form")
- (widget-insert " ")
- (widget-create 'push-button
- :notify (lambda (&rest ignore)
- (widget-example))
- "Reset Form")
- (widget-insert "\n")
- (use-local-map widget-keymap)
- (widget-setup))
-@end lisp
-
-@node Setting Up the Buffer, Basic Types, Programming Example, Top
-@comment node-name, next, previous, up
-@section Setting Up the Buffer
-
-Widgets are created with @code{widget-create}, which returns a
-@dfn{widget} object. This object can be queried and manipulated by
-other widget functions, until it is deleted with @code{widget-delete}.
-After the widgets have been created, @code{widget-setup} must be called
-to enable them.
-
-@defun widget-create type [ keyword argument ]@dots{}
-Create and return a widget of type @var{type}.
-The syntax for the @var{type} argument is described in @ref{Basic Types}.
-
-The keyword arguments can be used to overwrite the keyword arguments
-that are part of @var{type}.
-@end defun
-
-@defun widget-delete widget
-Delete @var{widget} and remove it from the buffer.
-@end defun
-
-@defun widget-setup
-Setup a buffer to support widgets.
-
-This should be called after creating all the widgets and before allowing
-the user to edit them.
-@refill
-@end defun
-
-If you want to insert text outside the widgets in the form, the
-recommended way to do that is with @code{widget-insert}.
-
-@defun widget-insert
-Insert the arguments, either strings or characters, at point.
-The inserted text will be read only.
-@end defun
-
-There is a standard widget keymap which you might find useful.
-
-@defvr Const widget-keymap
-A keymap with the global keymap as its parent.@*
-@key{TAB} and @kbd{C-@key{TAB}} are bound to @code{widget-forward} and
-@code{widget-backward}, respectively. @kbd{@key{RET}} and @kbd{mouse-2}
-are bound to @code{widget-button-press} and
-@code{widget-button-}.@refill
-@end defvr
-
-@defvar widget-global-map
-Keymap used by @code{widget-button-press} and @code{widget-button-click}
-when not on a button. By default this is @code{global-map}.
-@end defvar
-
-@node Basic Types, Sexp Types, Setting Up the Buffer, Top
-@comment node-name, next, previous, up
-@section Basic Types
-
-The syntax of a type specification is given below:
-
-@example
-NAME ::= (NAME [KEYWORD ARGUMENT]... ARGS)
- | NAME
-@end example
-
-Where, @var{name} is a widget name, @var{keyword} is the name of a
-property, @var{argument} is the value of the property, and @var{args}
-are interpreted in a widget specific way.
-
-There following keyword arguments that apply to all widgets:
-
-@table @code
-@item :value
-The initial value for widgets of this type.
-
-@item :format
-This string will be inserted in the buffer when you create a widget.
-The following @samp{%} escapes are available:
-
-@table @samp
-@item %[
-@itemx %]
-The text inside will be marked as a button.
-
-@item %@{
-@itemx %@}
-The text inside will be displayed with the face specified by
-@code{:sample-face}.
-
-@item %v
-This will be replaces with the buffer representation of the widgets
-value. What this is depends on the widget type.
-
-@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.
-
-@item %%
-Insert a literal @samp{%}.
-@end table
-
-@item :button-face
-Face used to highlight text inside %[ %] in the format.
-
-@item :doc
-The string inserted by the @samp{%d} escape in the format
-string.
-
-@item :tag
-The string inserted by the @samp{%t} escape in the format
-string.
-
-@item :tag-glyph
-Name of image to use instead of the string specified by `:tag' on
-Emacsen that supports it.
-
-@item :help-echo
-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
-is the widget itself, the second argument is the widget that was
-changed, and the third argument is the event leading to the change, if
-any.
-
-@item :menu-tag
-Tag used in the menu when the widget is used as an option in a
-@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{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.
-
-@item :match
-Should be a function called with two arguments, the widget and a value,
-and returning non-nil if the widget can represent the specified value.
-
-@item :validate
-A function which takes a widget as an argument, and return nil if the
-widgets current value is valid for the widget. Otherwise, it should
-return the widget containing the invalid data, and set that widgets
-@code{:error} property to a string explaining the error.
-
-@item :tab-order
-Specify the order in which widgets are traversed with
-@code{widget-forward} or @code{widget-backward}. This is only partially
-implemented.
-
-@enumerate a
-@item
-Widgets with tabbing order @code{-1} are ignored.
-
-@item
-(Unimplemented) When on a widget with tabbing order @var{n}, go to the
-next widget in the buffer with tabbing order @var{n+1} or @code{nil},
-whichever comes first.
-
-@item
-When on a widget with no tabbing order specified, go to the next widget
-in the buffer with a positive tabbing order, or @code{nil}
-@end enumerate
-
-@item :parent
-The parent of a nested widget (e.g. a @code{menu-choice} item or an
-element of a @code{editable-list} widget).
-
-@item :sibling-args
-This keyword is only used for members of a @code{radio-button-choice} or
-@code{checklist}. The value should be a list of extra keyword
-arguments, which will be used when creating the @code{radio-button} or
-@code{checkbox} associated with this item.
-
-@end table
-
-@deffn {User Option} widget-glyph-directory
-Directory where glyphs are found.
-Widget will look here for a file with the same name as specified for the
-image, with either a @samp{.xpm} (if supported) or @samp{.xbm} extension.
-@end deffn
-
-@deffn{User Option} widget-glyph-enable
-If non-nil, allow glyphs to appear on displayes where they are supported.
-@end deffn
-
-
-@menu
-* link::
-* url-link::
-* info-link::
-* push-button::
-* editable-field::
-* text::
-* menu-choice::
-* radio-button-choice::
-* item::
-* choice-item::
-* toggle::
-* checkbox::
-* checklist::
-* editable-list::
-@end menu
-
-@node link, url-link, Basic Types, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{link} Widget
-
-Syntax:
-
-@example
-TYPE ::= (link [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 url-link, info-link, link, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{url-link} Widget
-
-Syntax:
-
-@example
-TYPE ::= (url-link [KEYWORD ARGUMENT]... URL)
-@end example
-
-When this link is activated, the @sc{www} browser specified by
-@code{browse-url-browser-function} will be called with @var{url}.
-
-@node info-link, push-button, url-link, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{info-link} Widget
-
-Syntax:
-
-@example
-TYPE ::= (info-link [KEYWORD ARGUMENT]... ADDRESS)
-@end example
-
-When this link is activated, the build-in info browser is started on
-@var{address}.
-
-@node push-button, editable-field, info-link, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{push-button} Widget
-
-Syntax:
-
-@example
-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.
-
-The following extra properties are recognized.
-
-@table @code
-@item :text-format
-The format string used when the push button cannot be displayed
-graphically. There are two escapes, @code{%s}, which must be present
-exactly once, will be substituted with the tag, and @code{%%} will be
-substituted with a singe @samp{%}.
-@end table
-
-By default the tag will be shown in brackets.
-
-@node editable-field, text, push-button, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{editable-field} Widget
-
-Syntax:
-
-@example
-TYPE ::= (editable-field [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
-field. This widget will match all string values.
-
-The following extra properties are recognized.
-
-@table @code
-@item :size
-The width of the editable field.@*
-By default the field will reach to the end of the line.
-
-@item :value-face
-Face used for highlighting the editable field. Default is
-@code{widget-field-face}.
-
-@item :secret
-Character used to display the value. You can set this to e.g. @code{?*}
-if the field contains a password or other secret information. By
-default, the value is not secret.
-
-@item :valid-regexp
-By default the @code{:validate} function will match the content of the
-field with the value of this attribute. The default value is @code{""}
-which matches everything.
-
-@item :keymap
-Keymap used in the editable field. The default value is
-@code{widget-field-keymap}, which allows you to use all the normal
-editing commands, even if the buffers major mode supress some of them.
-Pressing return activates the function specified by @code{:activate}.
-
-@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, menu-choice, editable-field, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{text} Widget
-
-This is just like @code{editable-field}, but intended for multiline text
-fields. The default @code{:keymap} is @code{widget-text-keymap}, which
-does not rebind the return key.
-
-@node menu-choice, radio-button-choice, text, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{menu-choice} Widget
-
-Syntax:
-
-@example
-TYPE ::= (menu-choice [KEYWORD ARGUMENT]... TYPE ... )
-@end example
-
-The @var{type} arguments represents each possible choice. The widgets
-value of will be the value of the chosen @var{type} argument. This
-widget will match any value that matches at least one of the specified
-@var{type} arguments.
-
-@table @code
-@item :void
-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.
-
-@item :choice
-The current chosen type
-
-@item :args
-The list of types.
-@end table
-
-@node radio-button-choice, item, menu-choice, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{radio-button-choice} Widget
-
-Syntax:
-
-@example
-TYPE ::= (radio-button-choice [KEYWORD ARGUMENT]... TYPE ... )
-@end example
-
-The @var{type} arguments represents each possible choice. The widgets
-value of will be the value of the chosen @var{type} argument. This
-widget will match any value that matches at least one of the specified
-@var{type} arguments.
-
-The following extra properties are recognized.
-
-@table @code
-@item :entry-format
-This string will be inserted for each entry in the list.
-The following @samp{%} escapes are available:
-@table @samp
-@item %v
-Replaced with the buffer representation of the @var{type} widget.
-@item %b
-Replace with the radio button.
-@item %%
-Insert a literal @samp{%}.
-@end table
-
-@item button-args
-A list of keywords to pass to the radio buttons. Useful for setting
-e.g. the @samp{:help-echo} for each button.
-
-@item :buttons
-The widgets representing the radio buttons.
-
-@item :children
-The widgets representing each type.
-
-@item :choice
-The current chosen type
-
-@item :args
-The list of types.
-@end table
-
-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 @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 @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-button-choice, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{item} Widget
-
-Syntax:
-
-@example
-ITEM ::= (item [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. This widget will only match the specified value.
-
-@node choice-item, toggle, item, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{choice-item} Widget
-
-Syntax:
-
-@example
-ITEM ::= (choice-item [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 as a button. Activating the button of a @code{choice-item} is
-equivalent to activating the parent widget. This widget will only match
-the specified value.
-
-@node toggle, checkbox, choice-item, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{toggle} Widget
-
-Syntax:
-
-@example
-TYPE ::= (toggle [KEYWORD ARGUMENT]...)
-@end example
-
-The widget has two possible states, `on' and `off', which corresponds to
-a @code{t} or @code{nil} value.
-
-The following extra properties are recognized.
-
-@table @code
-@item :on
-String representing the `on' state. By default the string @samp{on}.
-@item :off
-String representing the `off' state. By default the string @samp{off}.
-@item :on-glyph
-Name of a glyph to be used instead of the `:on' text string, on emacsen
-that supports it.
-@item :off-glyph
-Name of a glyph to be used instead of the `:off' text string, on emacsen
-that supports it.
-@end table
-
-@node checkbox, checklist, toggle, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{checkbox} Widget
-
-The widget has two possible states, `selected' and `unselected', which
-corresponds to a @code{t} or @code{nil} value.
-
-Syntax:
-
-@example
-TYPE ::= (checkbox [KEYWORD ARGUMENT]...)
-@end example
-
-@node checklist, editable-list, checkbox, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{checklist} Widget
-
-Syntax:
-
-@example
-TYPE ::= (checklist [KEYWORD ARGUMENT]... TYPE ... )
-@end example
-
-The @var{type} arguments represents each checklist item. The widgets
-value of will be a list containing the value of each ticked @var{type}
-argument. The checklist widget will match a list whose elements all
-matches at least one of the specified @var{type} arguments.
-
-The following extra properties are recognized.
-
-@table @code
-@item :entry-format
-This string will be inserted for each entry in the list.
-The following @samp{%} escapes are available:
-@table @samp
-@item %v
-Replaced with the buffer representation of the @var{type} widget.
-@item %b
-Replace with the checkbox.
-@item %%
-Insert a literal @samp{%}.
-@end table
-
-@item button-args
-A list of keywords to pass to the checkboxes. Useful for setting
-e.g. the @samp{:help-echo} for each checkbox.
-
-@item :buttons
-The widgets representing the checkboxes.
-
-@item :children
-The widgets representing each type.
-
-@item :args
-The list of types.
-@end table
-
-@node editable-list, , checklist, Basic Types
-@comment node-name, next, previous, up
-@subsection The @code{editable-list} Widget
-
-Syntax:
-
-@example
-TYPE ::= (editable-list [KEYWORD ARGUMENT]... TYPE)
-@end example
-
-The value is a list, where each member represent one widget of type
-@var{type}.
-
-The following extra properties are recognized.
-
-@table @code
-@item :entry-format
-This string will be inserted for each entry in the list.
-The following @samp{%} escapes are available:
-@table @samp
-@item %v
-This will be replaced with the buffer representation of the @var{type}
-widget.
-@item %i
-Insert the @b{[INS]} button.
-@item %d
-Insert the @b{[DEL]} button.
-@item %%
-Insert a literal @samp{%}.
-@end table
-
-@item :insert-button-args
-A list of keyword arguments to pass to the insert buttons.
-
-@item :delete-button-args
-A list of keyword arguments to pass to the delete buttons.
-
-@item :append-button-args
-A list of keyword arguments to pass to the trailing insert button.
-
-
-@item :buttons
-The widgets representing the insert and delete buttons.
-
-@item :children
-The widgets representing the elements of the list.
-
-@item :args
-List whose car is the type of the list elements.
-
-@end table
-
-@node Sexp Types, Widget Properties, Basic Types, Top
-@comment
-@section Sexp Types
-
-A number of widgets for editing s-expressions (lisp types) are also
-available. These basically fall in three categories: @dfn{atoms},
-@dfn{composite types}, and @dfn{generic}.
-
-@menu
-* generic::
-* atoms::
-* composite::
-@end menu
-
-@node generic, atoms, Sexp Types, Sexp Types
-@comment node-name, next, previous, up
-@subsection The Generic Widget.
-
-The @code{const} and @code{sexp} widgets can contain any lisp
-expression. In the case of the @code{const} widget the user is
-prohibited from editing edit it, which is mainly useful as a component
-of one of the composite widgets.
-
-The syntax for the generic widgets is
-
-@example
-TYPE ::= (const [KEYWORD ARGUMENT]... [ VALUE ])
-@end example
-
-The @var{value}, if present, is used to initialize the @code{:value}
-property and can be any s-expression.
-
-@deffn Widget const
-This will display any valid s-expression in an immutable part of the
-buffer.
-@end deffn
-
-@deffn Widget sexp
-This will allow you to edit any valid s-expression in an editable buffer
-field.
-
-The @code{sexp} widget takes the same keyword arguments as the
-@code{editable-field} widget.
-@end deffn
-
-@node atoms, composite, generic, Sexp Types
-@comment node-name, next, previous, up
-@subsection Atomic Sexp Widgets.
-
-The atoms are s-expressions that does not consist of other
-s-expressions. A string is an atom, while a list is a composite type.
-You can edit the value of an atom with the following widgets.
-
-The syntax for all the atoms are
-
-@example
-TYPE ::= (NAME [KEYWORD ARGUMENT]... [ VALUE ])
-@end example
-
-The @var{value}, if present, is used to initialize the @code{:value}
-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{editable-field}
-widget.
-
-@deffn Widget string
-Allows you to edit a string in an editable field.
-@end deffn
-
-@deffn Widget file
-Allows you to edit a file name in an editable field. You you activate
-the tag button, you can edit the file name in the mini-buffer with
-completion.
-
-Keywords:
-@table @code
-@item :must-match
-If this is set to non-nil, only existing file names will be allowed in
-the minibuffer.
-@end table
-@end deffn
-
-@deffn Widget directory
-Allows you to edit a directory name in an editable field.
-Similar to the @code{file} widget.
-@end deffn
-
-@deffn Widget symbol
-Allows you to edit a lisp symbol in an editable field.
-@end deffn
-
-@deffn Widget integer
-Allows you to edit an integer in an editable field.
-@end deffn
-
-@deffn Widget number
-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.
-
-The syntax for the composite are
-
-@example
-TYPE ::= (NAME [KEYWORD ARGUMENT]... COMPONENT...)
-@end example
-
-Where each @var{component} must be a widget type. Each component widget
-will be displayed in the buffer, and be editable to the user.
-
-@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
-component. There must be exactly two components.
-@end deffn
-
-@deffn Widget lisp
-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{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{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
- (choice (const t)
- (list :inline t
- :value ("foo" "bar")
- string string)))
-@end example
-
-The value of a widget of this type will either have the form
-@samp{(file t)} or @code{(file string string)}.
-
-This concept of inline is probably hard to understand. It was certainly
-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
-
-You can examine or set the value of a widget by using the widget object
-that was returned by @code{widget-create}.
-
-@defun widget-value widget
-Return the current value contained in @var{widget}.
-It is an error to call this function on an uninitialized widget.
-@end defun
-
-@defun widget-value-set widget value
-Set the value contained in @var{widget} to @var{value}.
-It is an error to call this function with an invalid @var{value}.
-@end defun
-
-@strong{Important:} You @emph{must} call @code{widget-setup} after
-modifying the value of a widget before the user is allowed to edit the
-widget again. It is enough to call @code{widget-setup} once if you
-modify multiple widgets. This is currently only necessary if the widget
-contains an editing field, but may be necessary for other widgets in the
-future.
-
-If your application needs to associate some information with the widget
-objects, for example a reference to the item being edited, it can be
-done with @code{widget-put} and @code{widget-get}. The property names
-must begin with a @samp{:}.
-
-@defun widget-put widget property value
-In @var{widget} set @var{property} to @var{value}.
-@var{property} should be a symbol, while @var{value} can be anything.
-@end defun
-
-@defun widget-get widget property
-In @var{widget} return the value for @var{property}.
-@var{property} should be a symbol, the value is what was last set by
-@code{widget-put} for @var{property}.
-@end defun
-
-@defun widget-member widget property
-Non-nil if @var{widget} has a value (even nil) for property @var{property}.
-@end defun
-
-Occasionally it can be useful to know which kind of widget you have,
-i.e. the name of the widget type you gave when the widget was created.
-
-@defun widget-type widget
-Return the name of @var{widget}, a symbol.
-@end defun
-
-Widgets can be in two states: active, which means they are modifiable by
-the user, or inactive, which means they cannot be modified by the user.
-You can query or set the state with the following code:
-
-@lisp
-;; Examine if @var{widget} is active or not.
-(if (widget-apply @var{widget} :active)
- (message "Widget is active.")
- (message "Widget is inactive.")
-
-;; Make @var{widget} inactive.
-(widget-apply @var{widget} :deactivate)
-
-;; Make @var{widget} active.
-(widget-apply @var{widget} :activate)
-@end lisp
-
-A widget is inactive if itself, or any of its ancestors (found by
-following the @code{:parent} link) have been deactivated. To make sure
-a widget is really active, you must therefore activate both itself, and
-all its ancestors.
-
-@lisp
-(while widget
- (widget-apply widget :activate)
- (setq widget (widget-get widget :parent)))
-@end lisp
-
-You can check if a widget has been made inactive by examining the value
-of @code{:inactive} keyword. If this is non-nil, the widget itself has
-been deactivated. This is different from using the @code{:active}
-keyword, in that the later tell you if the widget @strong{or} any of its
-ancestors have been deactivated. Do not attempt to set the
-@code{:inactive} keyword directly. Use the @code{:activate}
-@code{:deactivated} keywords instead.
-
-
-@node Defining New Widgets, Widget Wishlist., Widget Properties, Top
-@comment node-name, next, previous, up
-@section Defining New Widgets
-
-You can define specialized widgets with @code{define-widget}. It allows
-you to create a shorthand for more complex widgets, including specifying
-component widgets and default new default values for the keyword
-arguments.
-
-@defun widget-define name class doc &rest args
-Define a new widget type named @var{name} from @code{class}.
-
-@var{name} and class should both be symbols, @code{class} should be one
-of the existing widget types.
-
-The third argument @var{DOC} is a documentation string for the widget.
-
-After the new widget has been defined, the following two calls will
-create identical widgets:
-
-@itemize @bullet
-@item
-@lisp
-(widget-create @var{name})
-@end lisp
-
-@item
-@lisp
-(apply widget-create @var{class} @var{args})
-@end lisp
-@end itemize
-
-@end defun
-
-Using @code{widget-define} does just store the definition of the widget
-type in the @code{widget-type} property of @var{name}, which is what
-@code{widget-create} uses.
-
-If you just want to specify defaults for keywords with no complex
-conversions, you can use @code{identity} as your conversion function.
-
-The following additional keyword arguments are useful when defining new
-widgets:
-@table @code
-@item :convert-widget
-Function to convert a widget type before creating a widget of that
-type. It takes a widget type as an argument, and returns the converted
-widget type. When a widget is created, this function is called for the
-widget type and all the widgets parent types, most derived first.
-
-@item :value-to-internal
-Function to convert the value to the internal format. The function
-takes two arguments, a widget and an external value, and returns the
-internal value. The function is called on the present @code{:value}
-when the widget is created, and on any value set later with
-@code{widget-value-set}.
-
-@item :value-to-external
-Function to convert the value to the external format. The function
-takes two arguments, a widget and an internal value, and returns the
-internal value. The function is called on the present @code{:value}
-when the widget is created, and on any value set later with
-@code{widget-value-set}.
-
-@item :create
-Function to create a widget from scratch. The function takes one
-argument, a widget type, and create a widget of that type, insert it in
-the buffer, and return a widget object.
-
-@item :delete
-Function to delete a widget. The function takes one argument, a widget,
-and should remove all traces of the widget from the buffer.
-
-@item :value-create
-Function to expand the @samp{%v} escape in the format string. It will
-be called with the widget as its argument. Should
-insert a representation of the widgets value in the buffer.
-
-@item :value-delete
-Should remove the representation of the widgets value from the buffer.
-It will be called with the widget as its argument. It doesn't have to
-remove the text, but it should release markers and delete nested widgets
-if such has been used.
-
-@item :format-handler
-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}
-widget as its base.
-
-@deffn Widget default [ keyword argument ]
-Widget used as a base for other widgets.
-
-It provides most of the functionality that is referred to as ``by
-default'' in this text.
-@end deffn
-
-@node Widget Wishlist., , Defining New Widgets, Top
-@comment node-name, next, previous, up
-@section Wishlist.
-
-@itemize @bullet
-@item
-It should be possible to add or remove items from a list with @kbd{C-k}
-and @kbd{C-o} (suggested by @sc{rms}).
-
-@item
-The @samp{[INS]} and @samp{[DEL]} buttons should be replaced by a single
-dash (@samp{-}). The dash should be a button that, when activated, ask
-whether you want to add or delete an item (@sc{rms} wanted to git rid of
-the ugly buttons, the dash is my idea).
-
-@item
-Widgets such as @code{file} and @code{symbol} should prompt with completion.
-
-@item
-The @code{menu-choice} tag should be prettier, something like the abbreviated
-menus in Open Look.
-
-@item
-The functions used in many widgets, like
-@code{widget-item-convert-widget}, should not have names that are
-specific to the first widget where I happended to use them.
-
-@item
-Flag to make @code{widget-move} skip a specified button.
-
-@item
-Document `helper' functions for defining new widgets.
-
-@item
-Activate the item this is below the mouse when the button is
-released, not the item this is below the mouse when the button is
-pressed. Dired and grep gets this right. Give feedback if possible.
-
-@item
-Use @samp{@@deffn Widget} to document widgets.
-
-@item
-Document global keywords in one place.
-
-Document keywords particular to a specific widget in the widget
-definition.
-
-Document the `default' widget first.
-
-Split, when needed, keywords into those useful for normal
-customization, those primarily useful when deriving, and those who
-represent runtime information.
-
-@item
-Figure out terminology and @sc{api} for the class/type/object/super
-stuff.
-
-Perhaps the correct model is delegation?
-
-@item
-Document @code{widget-browse}.
-
-@item
-Make indentation work with glyphs and propertional fonts.
-
-@item
-Add object and class hierarchies to the browser.
-
-@end itemize
-
-@contents
-@bye