1 ;;; mh-init.el --- MH-E initialization.
3 ;; Copyright (C) 2003, 2004 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 or MH).
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'.
40 (eval-when-compile (require 'mh-acros))
44 ;;; Avoid compiler warnings.
45 (eval-when-compile (defvar image-load-path))
47 ;;; Set for local environment:
48 ;;; mh-progs and mh-lib used to be set in paths.el, which tried to
49 ;;; figure out at build time which of several possible directories MH
50 ;;; was installed into. But if you installed MH after building Emacs,
51 ;;; this would almost certainly be wrong, so now we do it at run time.
54 "Directory containing MH commands, such as inc, repl, and rmm.")
57 "Directory containing the MH library.
58 This directory contains, among other things, the components file.")
60 (defvar mh-lib-progs nil
61 "Directory containing MH helper programs.
62 This directory contains, among other things, the mhl program.")
64 (defvar mh-flists-present-flag nil
65 "Non-nil means that we have `flists'.")
68 (put 'mh-progs 'risky-local-variable t)
70 (put 'mh-lib 'risky-local-variable t)
72 (put 'mh-lib-progs 'risky-local-variable t)
74 (defvar mh-variant-in-use nil
75 "The MH variant currently in use; a string with variant and version number.
76 This differs from `mh-variant' when the latter is set to `autodetect'.")
79 (defun mh-variant-set (variant)
80 "Set the MH variant to VARIANT.
81 Sets `mh-progs', `mh-lib', `mh-lib-progs' and `mh-flists-present-flag'.
82 If the VARIANT is `autodetect', then first try nmh, then MH and finally
85 (list (completing-read
87 (mapcar (lambda (x) (list (car x))) (mh-variants))
89 (let ((valid-list (mapcar (lambda (x) (car x)) (mh-variants))))
92 ((eq variant 'autodetect)
94 ((mh-variant-set-variant 'nmh)
95 (message "%s installed as MH variant" mh-variant-in-use))
96 ((mh-variant-set-variant 'mh)
97 (message "%s installed as MH variant" mh-variant-in-use))
98 ((mh-variant-set-variant 'mu-mh)
99 (message "%s installed as MH variant" mh-variant-in-use))
101 (message "No MH variant found on the system!"))))
102 ((member variant valid-list)
103 (when (not (mh-variant-set-variant variant))
104 (message "Warning: %s variant not found. Autodetecting..." variant)
105 (mh-variant-set 'autodetect)))
107 (message "Unknown variant. Use %s"
108 (mapconcat '(lambda (x) (format "%s" (car x)))
109 mh-variants " or "))))))
111 (defun mh-variant-set-variant (variant)
112 "Setup the system variables for the MH variant named VARIANT.
113 If VARIANT is a string, use that key in the variable `mh-variants'.
114 If VARIANT is a symbol, select the first entry that matches that variant."
116 ((stringp variant) ;e.g. "nmh 1.1-RC1"
117 (when (assoc variant mh-variants)
118 (let* ((alist (cdr (assoc variant mh-variants)))
119 (lib-progs (cadr (assoc 'mh-lib-progs alist)))
120 (lib (cadr (assoc 'mh-lib alist)))
121 (progs (cadr (assoc 'mh-progs alist)))
122 (flists (cadr (assoc 'flists alist))))
123 ;;(set-default mh-variant variant)
124 (setq mh-x-mailer-string nil
125 mh-flists-present-flag flists
126 mh-lib-progs lib-progs
129 mh-variant-in-use variant))))
130 ((symbolp variant) ;e.g. 'nmh (pick the first match)
131 (loop for variant-list in mh-variants
132 when (eq variant (cadr (assoc 'variant (cdr variant-list))))
133 return (let* ((version (car variant-list))
134 (alist (cdr variant-list))
135 (lib-progs (cadr (assoc 'mh-lib-progs alist)))
136 (lib (cadr (assoc 'mh-lib alist)))
137 (progs (cadr (assoc 'mh-progs alist)))
138 (flists (cadr (assoc 'flists alist))))
139 ;;(set-default mh-variant flavor)
140 (setq mh-x-mailer-string nil
141 mh-flists-present-flag flists
142 mh-lib-progs lib-progs
145 mh-variant-in-use version)
149 (defun mh-variant-p (&rest variants)
150 "Return t if variant is any of VARIANTS.
151 Currently known variants are 'MH, 'nmh, and 'mu-mh."
152 (let ((variant-in-use
153 (cadr (assoc 'variant (assoc mh-variant-in-use mh-variants)))))
154 (not (null (member variant-in-use variants)))))
157 '("/usr/local/nmh/bin" ; nmh default
160 "/usr/bin/mh/" ; Ultrix 4.2, Linux
161 "/usr/new/mh/" ; Ultrix < 4.2
162 "/usr/contrib/mh/bin/" ; BSDI
163 "/usr/pkg/bin/" ; NetBSD
165 "/usr/local/bin/mu-mh/" ; GNU mailutils - default
166 "/usr/bin/mu-mh/") ; GNU mailutils - packaged
167 "List of directories to search for variants of the MH variant.
168 The list `exec-path' is searched in addition to this list.
169 There's no need for users to modify this list. Instead add extra
170 directories to the customizable variable `mh-path'.")
172 (defcustom mh-path nil
173 "*List of directories to search for variants of the MH variant.
174 The directories will be searched for `mhparam' in addition to directories
175 listed in `mh-sys-path' and `exec-path'."
177 :type '(repeat (directory)))
179 (defvar mh-variants nil
180 "List describing known MH variants.
181 Created by the function `mh-variants'")
183 (defun mh-variant-mh-info (dir)
184 "Return info for MH variant in DIR assuming a temporary buffer is setup."
185 ;; MH does not have the -version option.
186 ;; Its version number is included in the output of `-help' as:
188 ;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
189 ;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
190 ;; [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
191 ;; [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
192 ;; [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
193 ;; [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
194 ;; [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
195 (let ((mhparam (expand-file-name "mhparam" dir)))
196 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
198 (call-process mhparam nil '(t nil) nil "-help")
199 (goto-char (point-min))
200 (when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
201 (let ((version (format "MH %s" (match-string 1))))
203 (call-process mhparam nil '(t nil) nil "libdir")
204 (goto-char (point-min))
205 (when (search-forward-regexp "^.*$" nil t)
206 (let ((libdir (match-string 0)))
209 (mh-lib-progs ,libdir)
214 (defun mh-variant-mu-mh-info (dir)
215 "Return info for GNU mailutils variant in DIR.
216 This assumes that a temporary buffer is setup."
217 ;; 'mhparam -version' output:
218 ;; mhparam (GNU mailutils 0.3.2)
219 (let ((mhparam (expand-file-name "mhparam" dir)))
220 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
222 (call-process mhparam nil '(t nil) nil "-version")
223 (goto-char (point-min))
224 (when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
226 (let ((version (match-string 1)))
228 (call-process mhparam nil '(t nil) nil "libdir" "etcdir")
229 (goto-char (point-min))
230 (when (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
231 (let ((libdir (match-string 1)))
232 (goto-char (point-min))
233 (when (search-forward-regexp
234 "^etcdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
235 (let ((etcdir (match-string 1))
236 (flists (file-exists-p (expand-file-name "flists" dir))))
239 (mh-lib-progs ,libdir)
242 (flists ,flists)))))))))))
244 (defun mh-variant-nmh-info (dir)
245 "Return info for nmh variant in DIR assuming a temporary buffer is setup."
246 ;; `mhparam -version' outputs:
247 ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
248 (let ((mhparam (expand-file-name "mhparam" dir)))
249 (when (and (file-exists-p mhparam) (file-executable-p mhparam))
251 (call-process mhparam nil '(t nil) nil "-version")
252 (goto-char (point-min))
253 (when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
254 (let ((version (format "nmh %s" (match-string 1))))
256 (call-process mhparam nil '(t nil) nil "libdir" "etcdir")
257 (goto-char (point-min))
258 (when (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
259 (let ((libdir (match-string 1)))
260 (goto-char (point-min))
261 (when (search-forward-regexp
262 "^etcdir:\\s-\\(\\S-+\\)\\s-*$" nil t)
263 (let ((etcdir (match-string 1))
264 (flists (file-exists-p (expand-file-name "flists" dir))))
267 (mh-lib-progs ,libdir)
270 (flists ,flists)))))))))))
272 (defun mh-variant-info (dir)
273 "Return MH variant found in DIR, or nil if none present."
275 (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
276 (set-buffer tmp-buffer)
278 ((mh-variant-mh-info dir))
279 ((mh-variant-nmh-info dir))
280 ((mh-variant-mu-mh-info dir))))))
283 (defun mh-variants ()
284 "Return a list of installed variants of MH on the system.
285 This function looks for MH in `mh-sys-path', `mh-path' and
286 `exec-path'. The format of the list of variants that is returned is described
287 by the variable `mh-variants'."
291 ;; Make a unique list of directories, keeping the given order.
292 ;; We don't want the same MH variant to be listed multiple times.
293 (loop for dir in (append mh-path mh-sys-path exec-path) do
294 (setq dir (file-chase-links (directory-file-name dir)))
295 (add-to-list 'list-unique dir))
296 (loop for dir in (nreverse list-unique) do
297 (when (and dir (file-directory-p dir) (file-readable-p dir))
298 (let ((variant (mh-variant-info dir)))
300 (add-to-list 'mh-variants variant)))))
303 ;;; XXX The two calls to message in this function should really be calls to
304 ;;; error. However, when this function is compiled via the top-level call in
305 ;;; mh-customize.el, it is actually called, and in a compile environment, the
306 ;;; errors are triggered which botches the compile. As a workaround, the calls
307 ;;; to error have been changed to calls to message, and code following was
308 ;;; inserted as an else clause. This is not robust, so if you can fix this,
311 (defvar mh-image-load-path-called-flag nil)
314 (defun mh-image-load-path ()
315 "Ensure that the MH-E images are accessible by `find-image'.
316 Images for MH-E are found in ../../etc/images relative to the files in
317 `lisp/mh-e'. If `image-load-path' exists (since Emacs 22), then the images
318 directory is added to it if isn't already there. Otherwise, the images
319 directory is added to the `load-path' if it isn't already there."
320 (message "mh-image-load-path called") ;XXX: for debugging
321 (unless mh-image-load-path-called-flag
322 (let (mh-load-path mh-image-load-path)
323 ;; First, find mh-e in the load-path.
325 (loop for dir in load-path
326 for dir-name = (directory-file-name dir)
327 when (and (equal (file-name-nondirectory dir-name) "mh-e")
328 (file-exists-p dir-name))
331 (setq mh-image-load-path
332 (expand-file-name (concat (file-name-directory mh-load-path)
334 (error "Can not find mh-e in load-path"))
335 (cond ((or (not mh-image-load-path)
336 (not (file-exists-p mh-image-load-path)))
337 (error "Can not find image directory %s"
339 ((boundp 'image-load-path)
340 (unless (member mh-image-load-path image-load-path)
341 (push mh-image-load-path image-load-path)))
342 ((not (member mh-image-load-path load-path))
343 (push mh-image-load-path load-path))))
344 (setq mh-image-load-path-called-flag t)))
349 ;;; indent-tabs-mode: nil
350 ;;; sentence-end-double-space: nil
353 ;; arch-tag: e8372aeb-d803-42b1-9c95-3c93ad22f63c
354 ;;; mh-init.el ends here