1 ;;; mh-init.el --- MH-E initialization.
3 ;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
5 ;; Author: Peter S. Galbraith <psg@debian.org>
6 ;; Maintainer: Bill Wohler <wohler@newt.com>
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
29 ;; Sets up the MH variant (currently nmh, MH, or GNU mailutils).
31 ;; Users may customize `mh-variant' to switch between available variants.
32 ;; Available MH variants are described in the variable `mh-variants'.
33 ;; Developers may check which variant is currently in use with the
34 ;; variable `mh-variant-in-use' or the function `mh-variant-p'.
36 ;; Also contains code that is used at load or initialization time only.
42 (eval-when-compile (require 'mh-acros))
46 ;;; Avoid compiler warnings.
47 (eval-when-compile (defvar image-load-path))
49 ;;; Set for local environment:
50 ;;; mh-progs and mh-lib used to be set in paths.el, which tried to
51 ;;; figure out at build time which of several possible directories MH
52 ;;; was installed into. But if you installed MH after building Emacs,
53 ;;; this would almost certainly be wrong, so now we do it at run time.
56 "Directory containing MH commands, such as inc, repl, and rmm.")
59 "Directory containing the MH library.
60 This directory contains, among other things, the components file.")
62 (defvar mh-lib-progs nil
63 "Directory containing MH helper programs.
64 This directory contains, among other things, the mhl program.")
66 (defvar mh-flists-present-flag nil
67 "Non-nil means that we have `flists'.")
70 (put 'mh-progs 'risky-local-variable t)
72 (put 'mh-lib 'risky-local-variable t)
74 (put 'mh-lib-progs 'risky-local-variable t)
76 (defvar mh-variant-in-use nil
77 "The MH variant currently in use; a string with variant and version number.
78 This differs from `mh-variant' when the latter is set to `autodetect'.")
81 (defun mh-variant-set (variant)
82 "Set the MH variant to VARIANT.
83 Sets `mh-progs', `mh-lib', `mh-lib-progs' and `mh-flists-present-flag'.
84 If the VARIANT is `autodetect', then first try nmh, then MH and finally
87 (list (completing-read
89 (mapcar (lambda (x) (list (car x))) (mh-variants))
91 (let ((valid-list (mapcar (lambda (x) (car x)) (mh-variants))))
94 ((eq variant 'autodetect)
96 ((mh-variant-set-variant 'nmh)
97 (message "%s installed as MH variant" mh-variant-in-use))
98 ((mh-variant-set-variant 'mh)
99 (message "%s installed as MH variant" mh-variant-in-use))
100 ((mh-variant-set-variant 'mu-mh)
101 (message "%s installed as MH variant" mh-variant-in-use))
103 (message "No MH variant found on the system!"))))
104 ((member variant valid-list)
105 (when (not (mh-variant-set-variant variant))
106 (message "Warning: %s variant not found. Autodetecting..." variant)
107 (mh-variant-set 'autodetect)))
109 (message "Unknown variant. Use %s"
110 (mapconcat '(lambda (x) (format "%s" (car x)))
111 mh-variants " or "))))))
113 (defun mh-variant-set-variant (variant)
114 "Setup the system variables for the MH variant named VARIANT.
115 If VARIANT is a string, use that key in the variable `mh-variants'.
116 If VARIANT is a symbol, select the first entry that matches that variant."
118 ((stringp variant) ;e.g. "nmh 1.1-RC1"
119 (when (assoc variant mh-variants)
120 (let* ((alist (cdr (assoc variant mh-variants)))
121 (lib-progs (cadr (assoc 'mh-lib-progs alist)))
122 (lib (cadr (assoc 'mh-lib alist)))
123 (progs (cadr (assoc 'mh-progs alist)))
124 (flists (cadr (assoc 'flists alist))))
125 ;;(set-default mh-variant variant)
126 (setq mh-x-mailer-string nil
127 mh-flists-present-flag flists
128 mh-lib-progs lib-progs
131 mh-variant-in-use variant))))
132 ((symbolp variant) ;e.g. 'nmh (pick the first match)
133 (loop for variant-list in mh-variants
134 when (eq variant (cadr (assoc 'variant (cdr variant-list))))
135 return (let* ((version (car variant-list))
136 (alist (cdr variant-list))
137 (lib-progs (cadr (assoc 'mh-lib-progs alist)))
138 (lib (cadr (assoc 'mh-lib alist)))
139 (progs (cadr (assoc 'mh-progs alist)))
140 (flists (cadr (assoc 'flists alist))))
141 ;;(set-default mh-variant flavor)
142 (setq mh-x-mailer-string nil
143 mh-flists-present-flag flists
144 mh-lib-progs lib-progs
147 mh-variant-in-use version)
151 (defun mh-variant-p (&rest variants)
152 "Return t if variant is any of VARIANTS.
153 Currently known variants are 'MH, 'nmh, and 'mu-mh."
154 (let ((variant-in-use
155 (cadr (assoc 'variant (assoc mh-variant-in-use mh-variants)))))
156 (not (null (member variant-in-use variants)))))
159 '("/usr/local/nmh/bin" ; nmh default
162 "/usr/bin/mh/" ; Ultrix 4.2, Linux
163 "/usr/new/mh/" ; Ultrix < 4.2
164 "/usr/contrib/mh/bin/" ; BSDI
165 "/usr/pkg/bin/" ; NetBSD
167 "/usr/local/bin/mu-mh/" ; GNU mailutils - default
168 "/usr/bin/mu-mh/") ; GNU mailutils - packaged
169 "List of directories to search for variants of the MH variant.
170 The list `exec-path' is searched in addition to this list.
171 There's no need for users to modify this list. Instead add extra
172 directories to the customizable variable `mh-path'.")
174 (defcustom mh-path nil
175 "*List of directories to search for variants of the MH variant.
176 The directories will be searched for `mhparam' in addition to directories
177 listed in `mh-sys-path' and `exec-path'."
179 :type '(repeat (directory)))
181 (defvar mh-variants nil
182 "List describing known MH variants.
183 Created by the function `mh-variants'")
185 (defun mh-variant-mh-info (dir)
186 "Return info for MH variant in DIR assuming a temporary buffer is setup."
187 ;; MH does not have the -version option.
188 ;; Its version number is included in the output of `-help' as:
190 ;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
191 ;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
192 ;; [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
193 ;; [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
194 ;; [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
195 ;; [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
196 ;; [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
197 (let ((mhparam (expand-file-name "mhparam" dir)))
198 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
200 (call-process mhparam nil '(t nil) nil "-help")
201 (goto-char (point-min))
202 (when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
203 (let ((version (format "MH %s" (match-string 1))))
205 (call-process mhparam nil '(t nil) nil "libdir")
206 (goto-char (point-min))
207 (when (search-forward-regexp "^.*$" nil t)
208 (let ((libdir (match-string 0)))
211 (mh-lib-progs ,libdir)
216 (defun mh-variant-mu-mh-info (dir)
217 "Return info for GNU mailutils variant in DIR.
218 This assumes that a temporary buffer is setup."
219 ;; 'mhparam -version' output:
220 ;; mhparam (GNU mailutils 0.3.2)
221 (let ((mhparam (expand-file-name "mhparam" dir)))
222 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
224 (call-process mhparam nil '(t nil) nil "-version")
225 (goto-char (point-min))
226 (when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
228 (let ((version (match-string 1)))
230 (call-process mhparam nil '(t nil) nil "libdir" "etcdir")
231 (goto-char (point-min))
232 (when (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
233 (let ((libdir (match-string 1)))
234 (goto-char (point-min))
235 (when (search-forward-regexp
236 "^etcdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
237 (let ((etcdir (match-string 1))
238 (flists (file-exists-p (expand-file-name "flists" dir))))
241 (mh-lib-progs ,libdir)
244 (flists ,flists)))))))))))
246 (defun mh-variant-nmh-info (dir)
247 "Return info for nmh variant in DIR assuming a temporary buffer is setup."
248 ;; `mhparam -version' outputs:
249 ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
250 (let ((mhparam (expand-file-name "mhparam" dir)))
251 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
253 (call-process mhparam nil '(t nil) nil "-version")
254 (goto-char (point-min))
255 (when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
256 (let ((version (format "nmh %s" (match-string 1))))
258 (call-process mhparam nil '(t nil) nil "libdir" "etcdir")
259 (goto-char (point-min))
260 (when (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
261 (let ((libdir (match-string 1)))
262 (goto-char (point-min))
263 (when (search-forward-regexp
264 "^etcdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
265 (let ((etcdir (match-string 1))
266 (flists (file-exists-p (expand-file-name "flists" dir))))
269 (mh-lib-progs ,libdir)
272 (flists ,flists)))))))))))
274 (defun mh-variant-info (dir)
275 "Return MH variant found in DIR, or nil if none present."
277 (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
278 (set-buffer tmp-buffer)
280 ((mh-variant-mh-info dir))
281 ((mh-variant-nmh-info dir))
282 ((mh-variant-mu-mh-info dir))))))
285 (defun mh-variants ()
286 "Return a list of installed variants of MH on the system.
287 This function looks for MH in `mh-sys-path', `mh-path' and
288 `exec-path'. The format of the list of variants that is returned is described
289 by the variable `mh-variants'."
293 ;; Make a unique list of directories, keeping the given order.
294 ;; We don't want the same MH variant to be listed multiple times.
295 (loop for dir in (append mh-path mh-sys-path exec-path) do
296 (setq dir (file-chase-links (directory-file-name dir)))
297 (add-to-list 'list-unique dir))
298 (loop for dir in (nreverse list-unique) do
299 (when (and dir (file-directory-p dir) (file-readable-p dir))
300 (let ((variant (mh-variant-info dir)))
302 (add-to-list 'mh-variants variant)))))
307 (defvar mh-image-load-path-called-flag nil)
310 (defun mh-image-load-path ()
311 "Ensure that the MH-E images are accessible by `find-image'.
312 Images for MH-E are found in ../../etc/images relative to the files in
313 `lisp/mh-e'. If `image-load-path' exists (since Emacs 22), then the images
314 directory is added to it if isn't already there. Otherwise, the images
315 directory is added to the `load-path' if it isn't already there."
316 (unless mh-image-load-path-called-flag
317 (let (mh-library-name mh-image-load-path)
318 ;; First, find mh-e in the load-path.
319 (setq mh-library-name (locate-library "mh-e"))
320 (if (not mh-library-name)
321 (error "Can not find MH-E in load-path"))
322 (setq mh-image-load-path
323 (expand-file-name (concat (file-name-directory mh-library-name)
324 "../../etc/images")))
325 (if (not (file-exists-p mh-image-load-path))
326 (error "Can not find image directory %s" mh-image-load-path))
327 (if (boundp 'image-load-path)
328 (add-to-list 'image-load-path mh-image-load-path)
329 (add-to-list 'load-path mh-image-load-path)))
330 (setq mh-image-load-path-called-flag t)))
334 (defvar mh-min-colors-defined-flag (and (not mh-xemacs-flag)
335 (>= emacs-major-version 22))
336 "Non-nil means defface supports min-colors display requirement.")
338 (defun mh-defface-compat (spec)
339 "Convert SPEC for defface if necessary to run on older platforms.
340 See `defface' for the spec definition.
342 When `mh-min-colors-defined-flag' is nil, this function finds a display with a
343 single \"class\" requirement with a \"color\" item, renames the requirement to
344 \"tty\" and moves it to the beginning of the list. It then strips any
345 \"min-colors\" requirements."
346 (when (not mh-min-colors-defined-flag)
347 ;; Insert ((class tty)) display with ((class color)) attributes.
348 (let ((attributes (cdr (assoc '((class color)) spec))))
349 (cons (cons '((class tty)) attributes) spec))
350 ;; Delete ((class color)) display.
351 (delq (assoc '((class color)) spec) spec)
353 (loop for entry in spec do
354 (when (not (eq (car entry) t))
355 (if (assoc 'min-colors (car entry))
356 (delq (assoc 'min-colors (car entry)) (car entry)))))))
361 ;;; indent-tabs-mode: nil
362 ;;; sentence-end-double-space: nil
365 ;; arch-tag: e8372aeb-d803-42b1-9c95-3c93ad22f63c
366 ;;; mh-init.el ends here