;; Sets up the MH variant (currently nmh, MH, or GNU mailutils).
;;
;; Users may customize `mh-variant' to switch between available variants.
-;; Available MH variants are described in the variable `mh-variants'.
+;; Available MH variants are returned by the function `mh-variants'.
;; Developers may check which variant is currently in use with the
;; variable `mh-variant-in-use' or the function `mh-variant-p'.
;;
(mh-require-cl)
(require 'mh-utils)
+(defvar mh-sys-path
+ '("/usr/local/nmh/bin" ; nmh default
+ "/usr/local/bin/mh/"
+ "/usr/local/mh/"
+ "/usr/bin/mh/" ; Ultrix 4.2, Linux
+ "/usr/new/mh/" ; Ultrix < 4.2
+ "/usr/contrib/mh/bin/" ; BSDI
+ "/usr/pkg/bin/" ; NetBSD
+ "/usr/local/bin/"
+ "/usr/local/bin/mu-mh/" ; GNU mailutils - default
+ "/usr/bin/mu-mh/") ; GNU mailutils - packaged
+ "List of directories to search for variants of the MH variant.
+The list `exec-path' is searched in addition to this list.
+There's no need for users to modify this list. Instead add extra
+directories to the customizable variable `mh-path'.")
+
;; Set for local environment:
;; mh-progs and mh-lib used to be set in paths.el, which tried to
;; figure out at build time which of several possible directories MH
(defvar mh-variants nil
"List describing known MH variants.
-Created by the function `mh-variants'")
+Do not access this variable directly as it may not have yet been initialized.
+Use the function `mh-variants' instead.")
;;;###mh-autoload
(defun mh-variants ()
(add-to-list 'mh-variants variant)))))
mh-variants)))
+(defun mh-variant-info (dir)
+ "Return MH variant found in DIR, or nil if none present."
+ (save-excursion
+ (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
+ (set-buffer tmp-buffer)
+ (cond
+ ((mh-variant-mh-info dir))
+ ((mh-variant-nmh-info dir))
+ ((mh-variant-mu-mh-info dir))))))
+
+(defun mh-variant-mh-info (dir)
+ "Return info for MH variant in DIR assuming a temporary buffer is setup."
+ ;; MH does not have the -version option.
+ ;; Its version number is included in the output of "-help" as:
+ ;;
+ ;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
+ ;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
+ ;; [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
+ ;; [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
+ ;; [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
+ ;; [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
+ ;; [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
+ (let ((mhparam (expand-file-name "mhparam" dir)))
+ (when (mh-file-command-p mhparam)
+ (erase-buffer)
+ (call-process mhparam nil '(t nil) nil "-help")
+ (goto-char (point-min))
+ (when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
+ (let ((version (format "MH %s" (match-string 1))))
+ (erase-buffer)
+ (call-process mhparam nil '(t nil) nil "libdir")
+ (goto-char (point-min))
+ (when (search-forward-regexp "^.*$" nil t)
+ (let ((libdir (match-string 0)))
+ `(,version
+ (variant mh)
+ (mh-lib-progs ,libdir)
+ (mh-lib ,libdir)
+ (mh-progs ,dir)
+ (flists nil)))))))))
+
+(defun mh-variant-mu-mh-info (dir)
+ "Return info for GNU mailutils variant in DIR.
+This assumes that a temporary buffer is setup."
+ ;; 'mhparam -version' output:
+ ;; mhparam (GNU mailutils 0.3.2)
+ (let ((mhparam (expand-file-name "mhparam" dir)))
+ (when (mh-file-command-p mhparam)
+ (erase-buffer)
+ (call-process mhparam nil '(t nil) nil "-version")
+ (goto-char (point-min))
+ (when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
+ nil t)
+ (let ((version (match-string 1))
+ (mh-progs dir))
+ `(,version
+ (variant mu-mh)
+ (mh-lib-progs ,(mh-profile-component "libdir"))
+ (mh-lib ,(mh-profile-component "etcdir"))
+ (mh-progs ,dir)
+ (flists ,(file-exists-p
+ (expand-file-name "flists" dir)))))))))
+
+(defun mh-variant-nmh-info (dir)
+ "Return info for nmh variant in DIR assuming a temporary buffer is setup."
+ ;; `mhparam -version' outputs:
+ ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
+ (let ((mhparam (expand-file-name "mhparam" dir)))
+ (when (mh-file-command-p mhparam)
+ (erase-buffer)
+ (call-process mhparam nil '(t nil) nil "-version")
+ (goto-char (point-min))
+ (when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
+ (let ((version (format "nmh %s" (match-string 1)))
+ (mh-progs dir))
+ `(,version
+ (variant nmh)
+ (mh-lib-progs ,(mh-profile-component "libdir"))
+ (mh-lib ,(mh-profile-component "etcdir"))
+ (mh-progs ,dir)
+ (flists ,(file-exists-p
+ (expand-file-name "flists" dir)))))))))
+
+(defun mh-file-command-p (file)
+ "Return t if file FILE is the name of a executable regular file."
+ (and (file-regular-p file) (file-executable-p file)))
+
(defvar mh-variant-in-use nil
"The MH variant currently in use; a string with variant and version number.
This differs from `mh-variant' when the latter is set to
finally GNU mailutils."
(interactive
(list (completing-read
- "MH Variant: "
+ "MH variant: "
(mapcar (lambda (x) (list (car x))) (mh-variants))
nil t)))
(let ((valid-list (mapcar (lambda (x) (car x)) (mh-variants))))
(t
(message "Unknown variant; use %s"
(mapconcat '(lambda (x) (format "%s" (car x)))
- mh-variants " or "))))))
+ (mh-variants) " or "))))))
(defun mh-variant-set-variant (variant)
"Setup the system variables for the MH variant named VARIANT.
-If VARIANT is a string, use that key in the variable `mh-variants'.
+If VARIANT is a string, use that key in the alist returned by the
+function `mh-variants'.
If VARIANT is a symbol, select the first entry that matches that
variant."
(cond
((stringp variant) ;e.g. "nmh 1.1-RC1"
- (when (assoc variant mh-variants)
- (let* ((alist (cdr (assoc variant mh-variants)))
+ (when (assoc variant (mh-variants))
+ (let* ((alist (cdr (assoc variant (mh-variants))))
(lib-progs (cadr (assoc 'mh-lib-progs alist)))
(lib (cadr (assoc 'mh-lib alist)))
(progs (cadr (assoc 'mh-progs alist)))
mh-progs progs
mh-variant-in-use variant))))
((symbolp variant) ;e.g. 'nmh (pick the first match)
- (loop for variant-list in mh-variants
+ (loop for variant-list in (mh-variants)
when (eq variant (cadr (assoc 'variant (cdr variant-list))))
return (let* ((version (car variant-list))
(alist (cdr variant-list))
"Return t if variant is any of VARIANTS.
Currently known variants are 'MH, 'nmh, and 'mu-mh."
(let ((variant-in-use
- (cadr (assoc 'variant (assoc mh-variant-in-use mh-variants)))))
+ (cadr (assoc 'variant (assoc mh-variant-in-use (mh-variants))))))
(not (null (member variant-in-use variants)))))
-(defvar mh-sys-path
- '("/usr/local/nmh/bin" ; nmh default
- "/usr/local/bin/mh/"
- "/usr/local/mh/"
- "/usr/bin/mh/" ; Ultrix 4.2, Linux
- "/usr/new/mh/" ; Ultrix < 4.2
- "/usr/contrib/mh/bin/" ; BSDI
- "/usr/pkg/bin/" ; NetBSD
- "/usr/local/bin/"
- "/usr/local/bin/mu-mh/" ; GNU mailutils - default
- "/usr/bin/mu-mh/") ; GNU mailutils - packaged
- "List of directories to search for variants of the MH variant.
-The list `exec-path' is searched in addition to this list.
-There's no need for users to modify this list. Instead add extra
-directories to the customizable variable `mh-path'.")
-
-(defun mh-variant-mh-info (dir)
- "Return info for MH variant in DIR assuming a temporary buffer is setup."
- ;; MH does not have the -version option.
- ;; Its version number is included in the output of "-help" as:
- ;;
- ;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
- ;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
- ;; [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
- ;; [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
- ;; [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
- ;; [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
- ;; [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
- (let ((mhparam (expand-file-name "mhparam" dir)))
- (when (and (file-exists-p mhparam) (file-executable-p mhparam))
- (erase-buffer)
- (call-process mhparam nil '(t nil) nil "-help")
- (goto-char (point-min))
- (when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
- (let ((version (format "MH %s" (match-string 1))))
- (erase-buffer)
- (call-process mhparam nil '(t nil) nil "libdir")
- (goto-char (point-min))
- (when (search-forward-regexp "^.*$" nil t)
- (let ((libdir (match-string 0)))
- `(,version
- (variant mh)
- (mh-lib-progs ,libdir)
- (mh-lib ,libdir)
- (mh-progs ,dir)
- (flists nil)))))))))
-
-(defun mh-variant-mu-mh-info (dir)
- "Return info for GNU mailutils variant in DIR.
-This assumes that a temporary buffer is setup."
- ;; 'mhparam -version' output:
- ;; mhparam (GNU mailutils 0.3.2)
- (let ((mhparam (expand-file-name "mhparam" dir)))
- (when (and (file-exists-p mhparam) (file-executable-p mhparam))
- (erase-buffer)
- (call-process mhparam nil '(t nil) nil "-version")
- (goto-char (point-min))
- (when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
- nil t)
- (let ((version (match-string 1))
- (mh-progs dir))
- `(,version
- (variant mu-mh)
- (mh-lib-progs ,(mh-profile-component "libdir"))
- (mh-lib ,(mh-profile-component "etcdir"))
- (mh-progs ,dir)
- (flists ,(file-exists-p
- (expand-file-name "flists" dir)))))))))
-
-(defun mh-variant-nmh-info (dir)
- "Return info for nmh variant in DIR assuming a temporary buffer is setup."
- ;; `mhparam -version' outputs:
- ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
- (let ((mhparam (expand-file-name "mhparam" dir)))
- (when (and (file-exists-p mhparam) (file-executable-p mhparam))
- (erase-buffer)
- (call-process mhparam nil '(t nil) nil "-version")
- (goto-char (point-min))
- (when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
- (let ((version (format "nmh %s" (match-string 1)))
- (mh-progs dir))
- `(,version
- (variant nmh)
- (mh-lib-progs ,(mh-profile-component "libdir"))
- (mh-lib ,(mh-profile-component "etcdir"))
- (mh-progs ,dir)
- (flists ,(file-exists-p
- (expand-file-name "flists" dir)))))))))
+\f
-(defun mh-variant-info (dir)
- "Return MH variant found in DIR, or nil if none present."
- (save-excursion
- (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
- (set-buffer tmp-buffer)
- (cond
- ((mh-variant-mh-info dir))
- ((mh-variant-nmh-info dir))
- ((mh-variant-mu-mh-info dir))))))
+;;; Read MH Profile
+
+(defvar mh-find-path-run nil
+ "Non-nil if `mh-find-path' has been run already.
+Do not access this variable; `mh-find-path' already uses it to
+avoid running more than once.")
+
+(defun mh-find-path ()
+ "Set variables from user's MH profile.
+
+This function sets `mh-user-path' from your \"Path:\" MH profile
+component (but defaults to \"Mail\" if one isn't present),
+`mh-draft-folder' from \"Draft-Folder:\", `mh-unseen-seq' from
+\"Unseen-Sequence:\", `mh-previous-seq' from
+\"Previous-Sequence:\", and `mh-inbox' from \"Inbox:\" (defaults
+to \"+inbox\").
+
+The hook `mh-find-path-hook' is run after these variables have
+been set. This hook can be used the change the value of these
+variables if you need to run with different values between MH and
+MH-E."
+ (unless mh-find-path-run
+ ;; Sanity checks.
+ (if (and (getenv "MH")
+ (not (file-readable-p (getenv "MH"))))
+ (error "MH environment variable contains unreadable file %s"
+ (getenv "MH")))
+ (if (null (mh-variants))
+ (error "Install MH and run install-mh before running MH-E"))
+ (let ((profile "~/.mh_profile"))
+ (if (not (file-readable-p profile))
+ (error "Run install-mh before running MH-E")))
+ ;; Read MH profile.
+ (setq mh-user-path (mh-profile-component "Path"))
+ (if (not mh-user-path)
+ (setq mh-user-path "Mail"))
+ (setq mh-user-path
+ (file-name-as-directory
+ (expand-file-name mh-user-path (expand-file-name "~"))))
+ (unless mh-x-image-cache-directory
+ (setq mh-x-image-cache-directory
+ (expand-file-name ".mhe-x-image-cache" mh-user-path)))
+ (setq mh-draft-folder (mh-profile-component "Draft-Folder"))
+ (if mh-draft-folder
+ (progn
+ (if (not (mh-folder-name-p mh-draft-folder))
+ (setq mh-draft-folder (format "+%s" mh-draft-folder)))
+ (if (not (file-exists-p (mh-expand-file-name mh-draft-folder)))
+ (error
+ "Draft folder \"%s\" not found; create it and try again"
+ (mh-expand-file-name mh-draft-folder)))))
+ (setq mh-inbox (mh-profile-component "Inbox"))
+ (cond ((not mh-inbox)
+ (setq mh-inbox "+inbox"))
+ ((not (mh-folder-name-p mh-inbox))
+ (setq mh-inbox (format "+%s" mh-inbox))))
+ (setq mh-unseen-seq (mh-profile-component "Unseen-Sequence"))
+ (if mh-unseen-seq
+ (setq mh-unseen-seq (intern mh-unseen-seq))
+ (setq mh-unseen-seq 'unseen)) ;old MH default?
+ (setq mh-previous-seq (mh-profile-component "Previous-Sequence"))
+ (if mh-previous-seq
+ (setq mh-previous-seq (intern mh-previous-seq)))
+ (run-hooks 'mh-find-path-hook)
+ (mh-collect-folder-names)
+ (setq mh-find-path-run t)))
\f
(or dont-show (not return-value) (mh-maybe-show number))
return-value))
-(defun mh-get-profile-field (field)
- "Find and return the value of FIELD in the current buffer.
-Returns nil if the field is not in the buffer."
+(defun mh-profile-component (component)
+ "Return COMPONENT value from mhparam, or nil if unset."
+ (save-excursion
+ (mh-exec-cmd-quiet nil "mhparam" "-components" component)
+ (mh-profile-component-value component)))
+
+(defun mh-profile-component-value (component)
+ "Find and return the value of COMPONENT in the current buffer.
+Returns nil if the component is not in the buffer."
(let ((case-fold-search t))
(goto-char (point-min))
- (cond ((not (re-search-forward (format "^%s" field) nil t)) nil)
+ (cond ((not (re-search-forward (format "^%s:" component) nil t)) nil)
((looking-at "[\t ]*$") nil)
(t
(re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t)
(end-of-line)
(buffer-substring start (point)))))))
-(defvar mh-find-path-run nil
- "Non-nil if `mh-find-path' has been run already.")
-
-(defun mh-find-path ()
- "Set variables from user's MH profile.
-
-This function sets `mh-user-path' from your \"Path:\" MH profile
-component (but defaults to \"Mail\" if one isn't present),
-`mh-draft-folder' from \"Draft-Folder:\", `mh-unseen-seq' from
-\"Unseen-Sequence:\", `mh-previous-seq' from
-\"Previous-Sequence:\", and `mh-inbox' from \"Inbox:\" (defaults
-to \"+inbox\").
-
-The hook `mh-find-path-hook' is run after these variables have
-been set. This hook can be used the change the value of these
-variables if you need to run with different values between MH and
-MH-E."
- (mh-variants)
- (unless mh-find-path-run
- (setq mh-find-path-run t)
- (save-excursion
- ;; Be sure profile is fully expanded before switching buffers
- (let ((profile (expand-file-name (or (getenv "MH") "~/.mh_profile"))))
- (set-buffer (get-buffer-create mh-temp-buffer))
- (setq buffer-offer-save nil) ;for people who set default to t
- (erase-buffer)
- (condition-case err
- (insert-file-contents profile)
- (file-error
- (mh-install profile err)))
- (setq mh-user-path (mh-get-profile-field "Path:"))
- (if (not mh-user-path)
- (setq mh-user-path "Mail"))
- (setq mh-user-path
- (file-name-as-directory
- (expand-file-name mh-user-path (expand-file-name "~"))))
- (unless mh-x-image-cache-directory
- (setq mh-x-image-cache-directory
- (expand-file-name ".mhe-x-image-cache" mh-user-path)))
- (setq mh-draft-folder (mh-get-profile-field "Draft-Folder:"))
- (if mh-draft-folder
- (progn
- (if (not (mh-folder-name-p mh-draft-folder))
- (setq mh-draft-folder (format "+%s" mh-draft-folder)))
- (if (not (file-exists-p (mh-expand-file-name mh-draft-folder)))
- (error
- "Draft folder \"%s\" not found. Create it and try again"
- (mh-expand-file-name mh-draft-folder)))))
- (setq mh-inbox (mh-get-profile-field "Inbox:"))
- (cond ((not mh-inbox)
- (setq mh-inbox "+inbox"))
- ((not (mh-folder-name-p mh-inbox))
- (setq mh-inbox (format "+%s" mh-inbox))))
- (setq mh-unseen-seq (mh-get-profile-field "Unseen-Sequence:"))
- (if mh-unseen-seq
- (setq mh-unseen-seq (intern mh-unseen-seq))
- (setq mh-unseen-seq 'unseen)) ;old MH default?
- (setq mh-previous-seq (mh-get-profile-field "Previous-Sequence:"))
- (if mh-previous-seq
- (setq mh-previous-seq (intern mh-previous-seq)))
- (run-hooks 'mh-find-path-hook)
- (mh-collect-folder-names)))))
-
-(defun mh-file-command-p (file)
- "Return t if file FILE is the name of a executable regular file."
- (and (file-regular-p file) (file-executable-p file)))
-
-(defvar mh-no-install nil) ;do not run install-mh
-
-(defun mh-install (profile error-val)
- "Initialize the MH environment.
-This is called if we fail to read the PROFILE file. ERROR-VAL is
-the error that made this call necessary."
- (if (or (getenv "MH")
- (file-exists-p profile)
- mh-no-install)
- (signal (car error-val)
- (list (format "Cannot read MH profile \"%s\"" profile)
- (car (cdr (cdr error-val))))))
- ;; The "install-mh" command will output a short note which
- ;; mh-exec-cmd will display to the user.
- ;; The MH 5 version of install-mh might try prompt the user
- ;; for information, which would fail here.
- (mh-exec-cmd (expand-file-name "install-mh" mh-lib-progs) "-auto")
- ;; now try again to read the profile file
- (erase-buffer)
- (condition-case err
- (insert-file-contents profile)
- (file-error
- (signal (car err) ;re-signal with more specific msg
- (list (format "Cannot read MH profile \"%s\"" profile)
- (car (cdr (cdr err))))))))
-
(defun mh-set-folder-modified-p (flag)
"Mark current folder as modified or unmodified according to FLAG."
(set-buffer-modified-p flag))
(mh-handle-process-error command value)
value)))
-(defun mh-profile-component (component)
- "Return COMPONENT value from mhparam, or nil if unset."
- (save-excursion
- (mh-exec-cmd-quiet nil "mhparam" "-components" component)
- (mh-get-profile-field (concat component ":"))))
-
;; Shush compiler.
(eval-when-compile (defvar mark-active))