[Mew-dist 08706] bbdb-ml.el, bbdb-ml-ext.el
sen_ml at example.com
sen_ml at example.com
1999年 5月 4日 (火) 22:03:32 JST
メーリングリスト情報 (参加、脱会方法、その他) を保存、管理等する
ためのコード、bbdb-ml.el と bbdb-ml-ext.el を書いてみました。
bbdb を使用しているので、使用するには、.emacs 等に:
(require 'bbdb)
(bbdb-initialize)
(require 'bbdb-ml)
(require 'bbdb-ml-ext)
と記述し、適当な場所に bbdb-ml.el と bbdb-ml-ext.el を置いて下さい。
mew で使用するには、
(setq bme-mail-client "mew")
wl で使用するには、
(setq bme-mail-client "wl")
と .emacs に記述してやって下さい。
emacs を起動し、mew か wl を起動し、Shift Mouse Button 2 と
やってみて下さい。
# Shift Mouse Button 2 がいやな人は bbdb-ml-ext.el の最後の
方をいじって下さい。ほんとうは、global-map を使わない方が
良いのでしょうね。
bbdb-ml.el を使用するには、bbdb が必要です。2.00 でテストしたつもりです。
bbdb-ml-ext.el を使用するには、bbdb, bbdb-ml の他に mew-mailto.el
(mew の場合)、wl-mailto.el (wl の場合) が必要です。
bbdb-ml.el と bbdb-ml-ext.el、あと、.bbdb のサンプルを添付します。
P.S. wl が 0.10.0 になってからはテストしていません。最後にテストしたのは
0.9.8 です。mew の方は、1.93 でテストしました。
-------------- next part --------------
;;; file-version: 3
["Mailing List:" "wl" nil nil nil nil nil ((ml-type . "fml") (ml-help . "mailto:wl-ctl at example.com?body=%23%20guide") (ml-unsubscribe . "mailto:wl-ctl at example.com?body=unsubscribe%0aend") (ml-subscribe . "mailto:wl-ctl at example.com?body=%23%20subscribe%20firstname%20lastname") (ml-post . "mailto:wl at example.com") (ml-owner . "mailto:wl-admin at example.com") (ml-archive . "http://lists.airs.net/wl/archive/") (creation-date . "1999-05-04") (timestamp . "1999-05-04")) nil]
["Mailing List:" "mew-dist" nil nil nil nil nil ((ml-type . "fml") (ml-unsubscribe . "mailto:mew-dist-ctl at example.com?body=unsubscribe%20name") (ml-subscribe . "mailto:mew-dist-ctl at example.com?body=subscribe%20name") (ml-post . "mailto:mew-dist at example.com") (ml-archive . "http://www.mew.org/Win32/search-j.html") (creation-date . "1999-05-01") (timestamp . "1999-05-01")) nil]
["Mailing List:" "mgp-users-jp" nil nil nil nil nil ((ml-type . "fml") (ml-help . "mailto:mgp-users-jp-ctl at example.com?body=%23%20help") (ml-unsubscribe . "mailto:mgp-users-jp-ctl at example.com?body=%23%20bye") (ml-subscribe . "mailto:mgp-users-jp-ctl at example.com?body=%23%20subscribe%20firstname%20lastname") (ml-post . "mailto:mgp-users-jp at example.com") (ml-owner . "mailto:mgp-users-jp-admin at example.com") (ml-archive . "http://www.mew.org/search/index-j.html") (creation-date . "1999-05-02") (timestamp . "1999-05-02")) nil]
["Mailing List:" "mgp-users" nil nil nil nil nil ((ml-type . "fml") (ml-help . "mailto:mgp-users-ctl at example.com?body=%23%20help") (ml-unsubscribe . "mailto:mgp-users-ctl at example.com?body=%23%20bye") (ml-subscribe . "mailto:mgp-users-ctl at example.com?body=%23%20subscribe%20firstname%20lastname") (ml-post . "mailto:mgp-users at example.com") (ml-owner . "mailto:mgp-users-admin at example.com") (creation-date . "1999-05-02") (timestamp . "1999-05-02")) nil]
-------------- next part --------------
;;; -*- emacs-lisp -*-
;;; This file is an addition to the Insidious Big Brother Database
;;; (aka BBDB), copyright (c) 1991, 1992 Jamie Zawinski
;;; <jwz at example.com>.
;;;
;;; Copyright (C) 1999 Sen Nagata <sen at example.com>
;;; This program 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 of
;;; the License.
;;; This program 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 this program; if not, write to the Free
;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;;; MA 02111-1307 USA
;;; This file was heavily based on bbdb-ftp.el by Ivan Vazquez
;;; <ivan at example.com>
;;; This file adds the ability to define mailing lists in a BBDB, much the same
;;; way one adds a regular person's name to the BBDB. See RFC 2369.
;;; Note that Mailing List BBDB entries differ from regular entries by the
;;; fact that the Name Field must have the mailing list name preceeded by the
;;; bbdb-mailing-list-name-designator-prefix. This defaults to
;;; "Mailing List:" BBDB Mailing List entries also have some new fields added:
;;;
;;; ml-type
;;; ml-help
;;; ml-unsubscribe
;;; ml-subscribe
;;; ml-post
;;; ml-owner
;;; ml-archive
;;;
;;; These are added to the notes alist part of the bbdb-records, the original
;;; bbdb-record structure remains untouched.
;;; The following user-level commands are defined for use:
;;;
;;; bbdb-create-mailing-list -
;;; Add a new mailing-list entry to the bbdb database; prompts
;;; for all relevant info using the echo area, inserts the
;;; new record in the db, sorted alphabetically.
;;; TODO: implement the following:
;;; The package can be installed by compiling and adding the following
;;; line to your .emacs.
;;; (autoload 'bbdb-create-mailing-list "bbdb-ml" "Mailing List BBDB Package" t)
(require 'bbdb)
(defconst bbdb-ml-version "bbdb-ml.el 0.1")
;; based this on something in bbdb.el
(defgroup bbdb-utilities-ml nil
"Customizations for using mailing lists stored in BBDB records."
:group 'bbdb-utilities)
(put 'bbdb-utilities-ml 'custom-loads '("bbdb-ml"))
(defcustom bbdb-default-mailto-command-prefix "mailto:"
"*The prefix for a mailing list mailto url command."
:group 'bbdb-utilities-ml
:type 'string)
(defcustom bbdb-default-http-command-prefix "http://"
"*The prefix for a mailing list http url command."
:group 'bbdb-utilities-ml
:type 'string)
(defcustom bbdb-mailing-list-name-designator-prefix "Mailing List: "
"*The prefix that all mailing lists in the bbdb will have in their name
field."
:group 'bbdb-utilities-ml
:type 'string)
(defmacro defun-bbdb-raw-notes-accessor (slot)
"Expands into an accessor function for slots in the notes alist."
(let ((fn-name (intern (concat "bbdb-record-" (symbol-name slot)))))
(list 'defun fn-name (list 'record)
(list 'cdr
(list 'assoc (list 'quote slot)
(list 'bbdb-record-raw-notes 'record))))))
;; (defun-bbdb-raw-notes-accessor ml-type) expands to:
;;
;; (defun bbdb-record-ml-type (record)
;; (cdr (assoc (quote ml-type) (bbdb-record-raw-notes record))))
(defvar bbdb-ml-field-prefix "ml-")
(defvar bbdb-ml-notes-action-name-list
'("help"
"unsubscribe"
"subscribe"
"post"
"owner"
"archive")
"List of actions for mailing list records.")
;; check passed value?
(defun bbdb-ml-action-name-to-symbol (action-name)
"Return symbol corresponding to ACTION-NAME."
(intern (concat bbdb-ml-field-prefix (downcase action-name))))
;; check passed value?
(defun bbdb-ml-symbol-to-action-name (symbol)
"Return action name corresponding to SYMBOL."
(substring (symbol-name symbol)
(length bbdb-ml-field-prefix)))
;; check passed value?
(defun bbdb-ml-action-name-to-symbol-name (action-name)
"Return symbol name corresponding to ACTION-NAME."
(symbol-name
(intern
(concat bbdb-ml-field-prefix (downcase action-name)))))
;; check passed value?
(defun bbdb-ml-symbol-name-to-action-name (symbol-name)
"Return action name corresponding to SYMBOL-NAME."
(substring symbol-name
(length bbdb-ml-field-prefix)))
(defvar bbdb-ml-notes-fieldname-alist
(cons (cons "ml-type" nil)
(mapcar
(lambda (x)
(cons
(bbdb-ml-action-name-to-symbol-name x)
nil))
bbdb-ml-notes-action-name-list))
"List of notes fields for mailing list records.")
; TODO: can't we do the following programmatically based on some list?
(defun-bbdb-raw-notes-accessor ml-type)
(defun-bbdb-raw-notes-accessor ml-help)
(defun-bbdb-raw-notes-accessor ml-unsubscribe)
(defun-bbdb-raw-notes-accessor ml-subscribe)
(defun-bbdb-raw-notes-accessor ml-post)
(defun-bbdb-raw-notes-accessor ml-owner)
(defun-bbdb-raw-notes-accessor ml-archive)
(defun bbdb-record-mailing-list (record)
"Acessor Function. Returns the mailing-list field of the BBDB record or
nil."
(let* ((name (bbdb-record-name record))
(ml-pfx-regexp (concat bbdb-mailing-list-name-designator-prefix " *"))
(mailing-list
(and (string-match ml-pfx-regexp name)
(substring name (match-end 0)))))
mailing-list))
(defun remove-leading-whitespace (string)
"Remove any spaces or tabs from only the start of the string."
(let ((space-char-code (string-to-char " "))
(tab-char-code ?\t)
(index 0))
(if string
(progn
(while (or (char-equal (elt string index) space-char-code)
(char-equal (elt string index) tab-char-code))
(setq index (+ index 1)))
(substring string index))
nil)))
(defun bbdb-read-new-mailing-list-record ()
"Prompt for and return a completely new bbdb-record that is
specifically a mailing list entry. Doesn't insert it in to the database
or update the hashtables, but does insure that there will not be name
collisions."
(bbdb-records) ; make sure database is loaded
(if bbdb-readonly-p
(error "The Insidious Big Brother Database is read-only."))
(let (mailing-list)
(bbdb-error-retry
(progn
(setq mailing-list
(bbdb-read-string "Mailing List: "))
(setq mailing-list
(concat bbdb-mailing-list-name-designator-prefix mailing-list))
(if (bbdb-gethash (downcase mailing-list))
(error "%s is already in the database" mailing-list))))
(let* ((ml-type
(bbdb-read-string "ML type: "))
(ml-help
(bbdb-read-string "Help URL: "
bbdb-default-mailto-command-prefix))
(ml-unsubscribe
(bbdb-read-string "Unsubscription URL: "
bbdb-default-mailto-command-prefix))
(ml-subscribe
(bbdb-read-string "Subscription URL: "
bbdb-default-mailto-command-prefix))
(ml-post
(bbdb-read-string "Post URL: "
bbdb-default-mailto-command-prefix))
(ml-owner
(bbdb-read-string "Owner URL: "
bbdb-default-mailto-command-prefix))
(ml-archive
(bbdb-read-string "Archive URL: "
bbdb-default-http-command-prefix))
(company
(bbdb-read-string "Company: "))
(notes
(bbdb-read-string "Additional Comments: "))
(names (bbdb-divide-name mailing-list))
(firstname (car names))
(lastname (nth 1 names)))
(if (string= company "")
(setq company nil))
(if (string= ml-type "")
(setq ml-type nil))
(if (or (string= ml-help bbdb-default-mailto-command-prefix)
(string= ml-help ""))
(setq ml-help nil))
(if (or (string= ml-unsubscribe bbdb-default-mailto-command-prefix)
(string= ml-unsubscribe ""))
(setq ml-unsubscribe nil))
(if (or (string= ml-subscribe bbdb-default-mailto-command-prefix)
(string= ml-subscribe ""))
(setq ml-subscribe nil))
(if (or (string= ml-post bbdb-default-mailto-command-prefix)
(string= ml-post ""))
(setq ml-post nil))
(if (or (string= ml-owner bbdb-default-mailto-command-prefix)
(string= ml-owner ""))
(setq ml-owner nil))
(if (or (string= ml-archive bbdb-default-http-command-prefix)
(string= ml-archive ""))
(setq ml-archive nil))
(if (string= notes "")
(setq notes nil))
(let ((record
(vector firstname lastname nil company nil nil nil
(append
(if notes
(list (cons 'notes notes)) nil)
(if ml-type
(list (cons 'ml-type ml-type)) nil)
(if ml-help
(list (cons 'ml-help ml-help)) nil)
(if ml-unsubscribe
(list (cons 'ml-unsubscribe ml-unsubscribe)) nil)
(if ml-subscribe
(list (cons 'ml-subscribe ml-subscribe)) nil)
(if ml-post
(list (cons 'ml-post ml-post)) nil)
(if ml-owner
(list (cons 'ml-owner ml-owner)) nil)
(if ml-archive
(list (cons 'ml-archive ml-archive)) nil))
(make-vector bbdb-cache-length nil))))
record))
))
(defun bbdb-create-mailing-list (record)
"Add a new mailing-list entry to the bbdb database; prompts for all
relevant info using the echo area, inserts the new record in the db,
sorted alphabetically."
(interactive (list (bbdb-read-new-mailing-list-record)))
(bbdb-invoke-hook 'bbdb-create-hook record)
(bbdb-change-record record t)
(bbdb-display-records (list record)))
(provide 'bbdb-ml)
-------------- next part --------------
;;; -*- emacs-lisp -*-
;;; This file is an addition to the Insidious Big Brother Database
;;; (aka BBDB), copyright (c) 1991, 1992 Jamie Zawinski
;;; <jwz at example.com>.
;;; Copyright (C) 1999 Sen Nagata <sen at example.com>
;;; This program 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 of
;;; the License.
;;; This program 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 this program; if not, write to the Free
;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;;; MA 02111-1307 USA
;;; The following user-level commands are defined for use:
;;;
;;; bbdb-ml-help
;;; bbdb-ml-unsubscribe
;;; bbdb-ml-subscribe
;;; bbdb-ml-post
;;; bbdb-ml-owner
;;; bbdb-ml.el is required
;;;
;;; if mew is going to be used, mew-mailto.el is required
;;; if wl is going to be used, wl-mailto.el is required
;;; TODO: work on naming in this file...
;; this file uses a macro from bbdb-ml.el
(eval-when-compile
(require 'bbdb-ml))
;; bme stands for 'bbdb-ml-ext'
(defconst bbdb-ml-ext-version "bbdb-ml-ext.el 0.1")
;; ah recusrion, wonderful recursion
(defun sln-collapse-list (target-list)
"Return a list of elements from TARGET-LIST w/ nil elements removed. The
order of the returned elements is preserved."
(if (null target-list)
nil
(if (car target-list)
(cons (car target-list)
(sln-collapse-list (cdr target-list)))
(sln-collapse-list (cdr target-list)))))
(defvar bme-mail-client "mew"
"String identifying mail client. E.g. mew, wl, etc.")
(cond
;; mew
((equal bme-mail-client "mew")
(progn
(require 'mew-mailto)
(defalias 'mail-client-mailto-compose-function
'mew-mailto-summary-send)))
;; wl
((equal bme-mail-client "wl")
(progn
(require 'wl-mailto)
(defalias 'mail-client-mailto-compose-function
'wl-mailto-draft))))
(defvar bme-ml-records-alist nil
"Association list of mailing list records.")
(defun bme-make-ml-records-alist ()
;(interactive)
(sln-collapse-list
(mapcar
(lambda (x)
;; (if (equal bbdb-mailing-list-name-designator-prefix
;; bbdb-mailing-list-name-designator-prefix contains a trailing space
;; while the value of the firstname field doesn't...
(if (equal "Mailing List:"
(bbdb-record-firstname x))
(cons (bbdb-record-lastname x) x)))
(bbdb-records))))
;(setq bme-ml-records-alist (bme-make-ml-records-alist))
(defun bme-get-record-for (mailing-list-name)
(cdr (assoc mailing-list-name
; bme-ml-records-alist
(bme-make-ml-records-alist)
)))
(defun bme-make-field-alist (fieldname)
(sln-collapse-list
(mapcar
(lambda (x)
(if x
(let* ((ml-name (car x))
(record (cdr x))
(fn-name (intern (concat "bbdb-record-" fieldname)))
(fieldvalue (funcall fn-name record)))
(if fieldvalue
(cons ml-name fieldvalue)))))
; bme-ml-records-alist
(bme-make-ml-records-alist)
)))
(defun bme-prompt-for-action ()
(let ((action
;; can't we get completing-read to not accept non-completing input?
(completing-read
"Action: "
(mapcar
(lambda (x)
(cons x nil))
bbdb-ml-notes-action-name-list)
nil
;; must choose from alist
t)))
(if (equal action "")
(error "No value for an action was specified")
action)))
(defun bme-prompt-for-mailing-list-with (action-name)
(let ((ml-field-alist
(bme-make-field-alist
(bbdb-ml-action-name-to-symbol-name action-name)))
mailing-list-name)
(if ml-field-alist
(progn
(setq mailing-list-name
(completing-read "Mailing List: " ml-field-alist nil t))
(if (equal mailing-list-name "")
(error "No value for a mailing list was specified")
mailing-list-name))
(error "No mailing lists w/ action %s defined" action-name))))
(defun bme-retrive-value-for (action-name mailing-list-name)
(interactive
(let* ((action-name
(bme-prompt-for-action))
(mailing-list-name
(bme-prompt-for-mailing-list-with action-name)))
(list action-name mailing-list-name)))
(let (lookup-function-name lookup-function looked-up-result)
(setq lookup-function-name
(concat "bbdb-record-"
(bbdb-ml-action-name-to-symbol-name action-name)))
;; quite defensive
(setq lookup-function
(intern-soft lookup-function-name))
(if lookup-function
(setq looked-up-result
(funcall
lookup-function
(bme-get-record-for mailing-list-name)))
;; shouldn't reach this point
(message "Function named: %s not found" lookup-function-name)))
)
(defun bme-do-action (action-name mailing-list-name)
(interactive
(let* ((action-name
(bme-prompt-for-action))
(mailing-list-name
(bme-prompt-for-mailing-list-with action-name)))
(list action-name mailing-list-name)))
(let ((field-value
(bme-retrive-value-for action-name mailing-list-name)))
; (message "%s for %s is: %s"
; action-name
; mailing-list-name
; field-value)
(mail-client-mailto-compose-function field-value)
)
)
;; the macro should expand to something like:
;;
;; (defun bbdb-ml-subscribe (mailing-list-name)
;; (interactive
;; (list
;; (bme-prompt-for-mailing-list-with "subscribe")))
;;
;; (bme-do-action "subscribe" mailing-list-name))
(defmacro defun-bme-do-action (action-name)
"Expands into a function for performing an action."
(let* ((fn-name (intern (concat
"bbdb-" "ml-" action-name))))
(list 'defun fn-name (list 'mailing-list-name)
(list 'interactive
(list 'list
(list 'bme-prompt-for-mailing-list-with
action-name)))
(list 'bme-do-action
action-name
'mailing-list-name)))
)
(defun-bme-do-action "help")
(defun-bme-do-action "unsubscribe")
(defun-bme-do-action "subscribe")
(defun-bme-do-action "post")
(defun-bme-do-action "owner")
;(defun-bme-do-action "archive")
(defun bme-popup-menu-emacs (mouse-event)
(interactive "e")
(let (command-name)
(setq command-name
(x-popup-menu mouse-event
'("Test BBDB Menu"
("Create Message"
("Help message" . bbdb-ml-help)
("Unsubscribe message" . bbdb-ml-unsubscribe)
("Subscribe message" . bbdb-ml-subscribe)
("Post message" . bbdb-ml-post)
("Owner message" . bbdb-ml-owner)
;("Archive message" . bbdb-ml-archive)
)
("Extras"
("Create mailing list record" .
bbdb-create-mailing-list))
)))
(if command-name
(command-execute command-name)
(message "No command selected"))))
(defun bme-popup-menu-xemacs (mouse-event)
(interactive "e")
(popup-menu '("Test BBDB Menu"
("Create Message"
["Help message" bbdb-ml-help t]
["Unsubscribe message" bbdb-ml-unsubscribe t]
["Subscribe message" bbdb-ml-subscribe t]
["Post message" bbdb-ml-post t]
["Owner message" bbdb-ml-owner t]
)
("Extras"
["Create mailing list record" bbdb-create-mailing-list t]
))))
(if (string-match "^XEmacs" (emacs-version))
;; xemacs
(progn
(defalias 'bme-popup-menu 'bme-popup-menu-xemacs)
(define-key global-map [(shift button2)] 'bme-popup-menu))
;; vanilla emacs
(progn
(defalias 'bme-popup-menu 'bme-popup-menu-emacs)
(define-key global-map [S-down-mouse-2] 'bme-popup-menu))
)
(provide 'bbdb-ml-ext)
Mew-dist メーリングリストの案内