From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.io/gmane.emacs.gnus.general/6714 Path: main.gmane.org!not-for-mail From: Erik Selberg Newsgroups: gmane.emacs.gnus.general Subject: incorporating MH Aliases Date: 14 Jun 1996 23:56:31 -0700 Sender: speed@cs.washington.edu Message-ID: NNTP-Posting-Host: coloc-standby.netfonds.no X-Trace: main.gmane.org 1035147131 4522 80.91.224.250 (20 Oct 2002 20:52:11 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Sun, 20 Oct 2002 20:52:11 +0000 (UTC) Return-Path: ding-request@ifi.uio.no Original-Received: from ifi.uio.no (ifi.uio.no [129.240.64.2]) by deanna.miranova.com (8.7.5/8.6.9) with SMTP id AAA29452 for ; Sat, 15 Jun 1996 00:37:23 -0700 Original-Received: from meitner.cs.washington.edu (meitner.cs.washington.edu [128.95.2.104]) by ifi.uio.no with ESMTP (8.6.11/ifi2.4) id for ; Sat, 15 Jun 1996 08:56:39 +0200 Original-Received: (speed@localhost) by meitner.cs.washington.edu (8.7.5/7.2ws+) id XAA02436; Fri, 14 Jun 1996 23:56:32 -0700 (PDT) Original-To: ding@ifi.uio.no Original-Lines: 439 X-Mailer: Gnus v5.2.17/Emacs 19.30 Xref: main.gmane.org gmane.emacs.gnus.general:6714 X-Report-Spam: http://spam.gmane.org/gmane.emacs.gnus.general:6714 Hi, I finally figured out how to incorporate MH aliases for those of you who use them. Lars --- can these please be incorporated into message.el? I've done some preliminary work in terms of an easy interface. (defvar message-use-mh-aliases nil "If non-nil, use mh-aliases (as specified in .mhprofile) file instead of .mailrc for mail aliases. Requires e-mh-alias.el") ;; needs e-mh-alias by Peter Galbraith; perhaps it can be ;; distributed with gnus as I don't believe it's part of emacs? it ;; does have the gnu license, so this should be OK (require 'e-mh-alias) ;; included at bottom of this message ;; convenience; if non-nil reads the /etc/password file and does ;; the right thing. Usually pointless with things like yppasswd though (setq e-mh-alias-local-users nil) ;; first, learn the mh-aliases. (e-mh-learn-aliases) ;; sets e-mh-alias-lowercase-alist ;; then, insert them into the mail-abbrev table, and you're all set (mapcar (lambda (x) (define-mail-abbrev (car x) (cdr x))) (mapcar (lambda (y) (cons (car y) (mapconcat (function (lambda (x) (format "%s" x))) (cdr y) ",\n " ))) e-mh-alias-lowercase-alist)) ---------------------------------------------------------------------- For those who don't, MH aliases are like normail aliases in .mailrc except: they're in the format joebob: joebob@some.dom and you can specify files as distribution lists, as in buddies: <~/dl/buddies.dl gnus message system doesn't incorporate them. ---------------------------------------------------------------------- ;; e-mh-alias.el - MH mail alias expansion and substitution. ;; ;; Copyright (C) 1995 Peter S. Galbraith ;; Author: Peter S. Galbraith ;; Created: 16 June 1994. ;; Version: 2.04 (29 Sep 95) ;; Keywords: mh-e, mail, alias, emacs, xemacs ;; Everyone is granted permission to copy, modify and redistribute this ;; file provided: ;; 1. All copies contain this copyright notice. ;; 2. All modified copies shall carry a prominant notice stating who ;; made modifications and the date of such modifications. ;; 3. The name of the modified file be changed. ;; 4. No charge is made for this software or works derived from it. ;; This clause shall not be construed as constraining other software ;; distributed on the same medium as this software, nor is a ;; distribution fee considered a charge. ;; LCD Archive Entry: ;; e-mh-alias|Peter Galbraith|galbraith@mixing.qc.dfo.ca| ;; MH mail alias expansion and substitution.| ;; 29-Sep-1995|2.04|~/misc/e-mh-alias.el ;; ---------------------------------------------------------------------------- ;;; Commentary: ;; New versions of this package (if they exist) may be found at: ;; ftp://mixing.qc.dfo.ca/pub/elisp/e-mh-alias.el ;; ftp://bathybius.meteo.mcgill.ca/pub/users/rhogee/elisp/e-mh-alias.el ;; Description: ;; ;; This packages makes [TAB] do completion in minibuffer To: and CC: ;; prompts on mail aliases (and optionally local usernames) and will ;; substitute these aliases in the MH-letter buffer. You may enter ;; multiple addressees by separating them with a comma, which (by default) ;; will flash the alias translation of the previous address. ;; ;; This package also makes [C-c C-f TAB] and Meta-[TAB] (aka M-\t) do ;; completion in the letter header itself. The Meta-[TAB] binding only ;; works for emacs version 19.29 (and above), because I use text-properties ;; to set a local keymap for a range of text (namely the mail header) ;; because M-\t is useful as ispell-complete-word in the rest of the letter ;; buffer. This feature is useful when you want to add an addressee as an ;; afterthought while editing a letter, or add an addresse to a reply. ;; ;; Installation instructions: ;; ;; All you need to do is add this line to your .emacs file ;; (require 'e-mh-alias) ;; ;; By default, completion is case insensitive. Should you want to change ;; this, you can set the following variable: ;; (defvar e-mh-alias-completion-ignore-case nil) ;; This is useful, for example, if you set all people aliases to lowercase ;; like ;; p.galbraith: Peter Galbraith ;; and lists in uppercase, like: ;; MH-E: mh-e mailing list ;; Note that this variable affects minibuffer completion only. If you ;; have an alias for P.Galbraith and type in p.galbraith at the prompt, it ;; will still be substituted in the letter buffer because these are ;; identical aliases as far as MH and e-mh-alias are concerned. ;; ;; By default, when you press the [comma] key at the To: or Cc: prompts, ;; the previous mail alias translation is flashed. To inhibit this, add ;; the following to your ~/.emacs file *before* you load e-mh-alias. ;; ;; (setq e-mh-alias-flash-on-comma nil) ;; ;; Completion and substitutions are also done on usernames extracted from ;; your /etcd/passwd file. This can be a handy tool on a machine where ;; you and co-workers exchange messages, but should probably be disabled ;; on a system with 100 users whom you don't know. This feature is ;; disabled by adding the following to your ~/.emacs file: ;; ;; (setq e-mh-alias-local-users nil) ;; ;; If you do use this feature, check that the variable e-mh-hostname is set ;; to a string containing @ followed by your hostname for better results ;; (e.g. C-h v e-mh-hostname). This should be set correctly after e-mh-alias ;; is loaded, but if it isn't do it in your ~/.emacs file using, for example ;; ;; (setq e-mh-hostname "@mixing.qc.dfo.ca") ;; ;; To do minibuffer completion on many comma-separated aliases, I use the ;; package `complete.el'. This affects minibuffer completion in everyday ;; use, and you might not like it. If you find that you can do without ;; completion on multiple aliases, you may then set the following variable ;; to nil, like so ;; ;; (setq e-mh-alias-use-complete nil) ;; ;; It is set to nil by default in xemacs, because it ddoesn't have the ;; `complete.el' package. ;; ---------------------------------------------------------------------------- ;;; Change log: ;; V1.00 16Jun94 Peter S Galbraith - Created as mh-aliases.el ;; V2.00 20Jul95 PSG - new version called mh-alias.el ;; - get aliases from MH's ali command. ;; - allow for comma separated list. ;; - optionally flash aliases when [comma] is pressed. ;; - [C-c C-f \t] or [M-\t] in MH-Letter header expands/substitutes aliases ;; V2.01 24Jul95 PSG - Added e-mh-alias-completion-ignore-case ;; V2.02 24Jul95 PSG - ;; - called e-mh-alias.el because mh- prefix reserved for mh-e packages. ;; - e-mh-alias-flash-on-comma may be unset after package loaded and can take ;; values nil, 1 or t. (Eric Ding ) ;; - initialize e-mh-hostname (Stephen Gildea ) ;; - shows completions buffer immediately on \M-\t in MH-Letter-buffer ;; V2.03 27Jul95 PSG - Made truly case insensitive for substitution. ;; Thanks to Christopher Lott for bug reports. ;; V2.04 29Sep95 PSG - Added e-mh-alias-use-complete for xemacs compatibility. ;; ---------------------------------------------------------------------------- ;;; Code: (defvar e-mh-alias-completion-ignore-case t "Non-nil means don't consider case significant in MH alias completion. This is the default in plain MH, so it is the default here as well. But you can change it usefully if, for example, you use lowercase aliases for people and uppercase for lists.") (defvar e-mh-alias-flash-on-comma t "Determines if alias translation displayed when [comma] pressed in mh queries t flash alias translation but don't warn if there is no translation. 1 flash alias translation and warn if there is no translation. nil don't flash alias translation or warn if there is no translation.") (defvar e-mh-alias-local-users t "If t, local users (with UID >= 200 from /etc/passwd) will be completed to and expanded by MH To: and Cc: prompts.") (defvar e-mh-alias-use-complete (not (string-match "XEmacs\\|Lucid" emacs-version)) "Non-nil means to use complete.el package. This will affect minibuffer completion in everyday emacs usage, and so is optional. You cannot use minibuffer completion for comma-separated aliases in e-mh-alias if you do not use complete.el") (defvar e-mh-hostname (concat "@" (or (and (boundp 'mail-host-address) mail-host-address) (system-name))) "String to append to local usernames from /etc/passwd to make addresses. This should be \"@\" your fully qualified hostname (e.g. \"@mixing.qc.dfo.ca\") See variable e-mh-alias-local-users.") ;; If you use the ffap package, then load e-mh-alias *before* ffap because the ;; complete package will interfere with ffap if loaded afterward ffap. ;; Using complete.el is overkill, but it allows me to taylor prompting. (if e-mh-alias-use-complete (require 'complete)) ;; load mh-comp because I redefine mh-read-address. (require 'mh-comp) (defvar e-mh-alias-alist nil "Alist of MH mailaliases.") (defvar e-mh-alias-lowercase-alist nil "Alist of lowercased MH mailaliases.") (defvar e-mh-read-address-map nil) (if e-mh-read-address-map () (setq e-mh-read-address-map (copy-keymap minibuffer-local-completion-map)) (if (featurep 'complete) (define-key e-mh-read-address-map "\t" 'e-mh-complete-address)) (if e-mh-alias-flash-on-comma (define-key e-mh-read-address-map "," 'e-mh-minibuffer-confirm-address)) (define-key e-mh-read-address-map " " 'self-insert-command)) (defun mh-read-address (prompt &optional initial-address) ;; Read a To: or Cc: address, prompting in the minibuffer with PROMPT. (if (not (or e-mh-alias-alist (e-mh-learn-aliases))) (read-string prompt) (let* ((minibuffer-local-completion-map e-mh-read-address-map) (completion-ignore-case e-mh-alias-completion-ignore-case) ;; initial-address is nil with minibuffer To: and CC: prompts ;; maybe "" in MH-letter-mode (unread-command-char (cond ((or (not initial-address) (string-equal "" initial-address)) -1) (t ??))) (the-answer (or (completing-read prompt e-mh-alias-alist nil nil initial-address) ""))) ;; Here I find all comma-whitespace-delimited words to test as aliases. (let ((the-aliases)) (while (and the-answer ;; Catches comma-delimited address with trailing whitespace (string-match "^[ \t,]*\\([^,]+\\)" the-answer)) (let* ((the-index (match-end 0)) (the-match (substring the-answer (match-beginning 1)(match-end 1))) ;; Now trim off trailing whitespace (trim-match (substring the-match 0 (string-match "[ \t]*$" the-match)))) (setq the-aliases (concat the-aliases ",\n " (if (assoc (downcase trim-match) e-mh-alias-lowercase-alist) ;Translates to alias? (mapconcat (function (lambda (x) (format "%s" x))) (cdr (assoc (downcase trim-match) e-mh-alias-lowercase-alist)) ",\n ") trim-match))) ; Does not translate (setq the-answer (substring the-answer the-index)))) ;; remove leading comma (if the-aliases (substring the-aliases 3) ""))))) (defun e-mh-complete-address () "Called by pressing [TAB] while in mh TO: or CC: prompts." (interactive) (PC-do-completion nil (save-excursion (skip-chars-backward "^ \t,")(point)))) (defun e-mh-minibuffer-confirm-address () "Called by pressing [comma] if e-mh-alias-flash-on-comma is t." (interactive) (if (not e-mh-alias-flash-on-comma) () (save-excursion (let ((the-name (buffer-substring (progn (skip-chars-backward " \t")(point)) ;; This moves over to previous comma, if any (progn (or (and (not (= 0 (skip-chars-backward "^,"))) ;; the skips over leading whitespace (skip-chars-forward " ")) ;; no comma, then to beginning of word (skip-chars-backward "^ \t")) (point))))) (if (assoc (downcase the-name) e-mh-alias-lowercase-alist) (message "%s -> %s" the-name (mapconcat (function (lambda (x) (format "%s" x))) (cdr (assoc (downcase the-name) e-mh-alias-lowercase-alist)) ", ")) ;; Check if if was a single word likely to be an alias (if (and (equal e-mh-alias-flash-on-comma 1) (not (string-match " " the-name))) (message "No alias for %s" the-name)))))) (self-insert-command 1)) (defun e-mh-learn-aliases () "Learn MH aliases, building an alist to complete with, and substitute with. This can be called interactively to rebuild from updated files." ;;; Could be done using an obarray and `intern' to create it. ;;; elisp info doesn't say if completing-read is more efficient with alists ;;; or obarrays. (interactive) (let ((mailalias-buffer (get-buffer-create " *e-mh-ali-command*"))) (save-excursion (set-buffer mailalias-buffer) (erase-buffer) (insert (expand-file-name "ali" mh-progs) " -list\n") (write-region (point-min) (point-max) "/tmp/e-mh-ali-command" nil nil) (message "building list of MH mail aliases...") (erase-buffer) (call-process "/bin/sh" "/tmp/e-mh-ali-command" t nil) (delete-file "/tmp/e-mh-ali-command") (setq e-mh-alias-alist nil e-mh-alias-lowercase-alist nil) (goto-char (point-min)) (let ((zero 0)) (while (= zero 0) (cond ((looking-at "\\(.*\\): *\\(.*\\)$") ; A new MH alias (setq e-mh-alias-alist (cons (list (buffer-substring (match-beginning 1)(match-end 1))) e-mh-alias-alist)) (setq e-mh-alias-lowercase-alist (cons (list (downcase (buffer-substring (match-beginning 1)(match-end 1))) (buffer-substring (match-beginning 2)(match-end 2))) e-mh-alias-lowercase-alist))) ((looking-at "[ ]+\\(.*\\)$") ; A alias continued (let ((the-first (car e-mh-alias-lowercase-alist)) ;;^^The previous alias list entered ("NEW" "schneider@awi") (the-rest (cdr e-mh-alias-lowercase-alist)) ;;^^The others before (the-new (buffer-substring(match-beginning 1)(match-end 1)))) (setq e-mh-alias-lowercase-alist (cons (append ; ("NEW" "budeus@awi" "schneider@awi") (list (car the-first)) ; ("NEW") (list the-new) ; ("budeus@awi") (cdr the-first)) ; ("schneider@awi") the-rest))))) (setq zero (forward-line 1))))) (kill-buffer mailalias-buffer)) (if e-mh-alias-local-users (e-mh-learn-local-users)) (message "building list of MH mail aliases... done.")) (defun e-mh-learn-local-users () "Add local users from /etc/passwd to e-mh-alias-alist" (let ((mailalias-buffer (get-buffer-create " *mailalias*"))) (save-excursion (set-buffer mailalias-buffer) (if (file-readable-p "/etc/passwd") (insert-file-contents "/etc/passwd")) (let ((zero 0)) (while (= zero 0) (cond ((looking-at "\\([^:]*\\):[^:]*:\\([^:]*\\):[^:]*:\\([^:]*\\):") (if (> (string-to-int (buffer-substring (match-beginning 2)(match-end 2))) 200) (let ((username (buffer-substring (match-beginning 1)(match-end 1))) (realname (buffer-substring (match-beginning 3)(match-end 3)))) (setq e-mh-alias-lowercase-alist (cons (list username (if (string-equal "" realname) (concat "<" username e-mh-hostname ">") (concat realname " <" username e-mh-hostname ">"))) e-mh-alias-lowercase-alist)) (setq e-mh-alias-alist (cons (list username) e-mh-alias-alist)))))) (setq zero (forward-line 1))))) (kill-buffer mailalias-buffer))) ;;; -------------------------------------------------------------------------- ;;; This part of e-mh-alias adds [M-TAB] expansion/substitution in letter head (define-key mh-letter-mode-map "\C-c\C-f\t" 'e-mh-letter-expand-alias) (cond ((string< "19.28.9" emacs-version) ;; wanted also to test (emacs-type) but this is unbound in -batch mode ! (setq e-mh-expand-alias-map (copy-keymap mh-letter-mode-map)) (define-key e-mh-expand-alias-map "\M-\t" 'e-mh-letter-expand-alias) (defun e-mh-letter-mode-expand-alias-hook () "Make M-[TAB] expand mail alias within letter header" (save-excursion ;; Take extra precautions to not return errors if regexp not found. (add-text-properties (progn (goto-char (point-min))(point)) (progn (re-search-forward "^---" nil t)(point)) (list 'local-map e-mh-expand-alias-map)))) (add-hook 'mh-letter-mode-hook 'e-mh-letter-mode-expand-alias-hook))) (defun e-mh-letter-expand-alias () "expand/convert mail alias before/under point." (interactive) (save-excursion (skip-chars-backward "^ ,:") (let ((the-match)(init-address "")(the-address)) (if (looking-at "[^ ,;\n]+") (setq the-match (match-data) init-address (or (and (string< "19.28.9" emacs-version) (buffer-substring-no-properties (match-beginning 0)(match-end 0))) (buffer-substring (match-beginning 0)(match-end 0))))) (if (assoc (try-completion (downcase init-address) e-mh-alias-lowercase-alist) e-mh-alias-lowercase-alist) ;; init-address is "p.gal" which has unique completion to ;; "p.galbraith", then substitute its alias, possibly multi-line. (setq the-address (mapconcat (function (lambda (x) (format "%s" x))) (cdr (assoc (try-completion (downcase init-address) e-mh-alias-lowercase-alist) e-mh-alias-lowercase-alist)) ",\n ")) (setq the-address (mh-read-address "Address: " init-address))) (if (string-equal "" the-address) () (if (not the-match) (insert the-address) (set-match-data the-match) (replace-match the-address t t)))))) (provide 'e-mh-alias) ;;; e-mh-alias.el ends here