Mercurial > hg > xemacs-beta
comparison lisp/utils/ph.el @ 165:5a88923fcbfe r20-3b9
Import from CVS: tag r20-3b9
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:44:42 +0200 |
parents | 28f395d8dc7a |
children | 8eaf7971accc |
comparison
equal
deleted
inserted
replaced
164:4e0740e5aab2 | 165:5a88923fcbfe |
---|---|
1 ;;; ph.el --- Client for the CCSO directory system (aka PH/QI) | 1 ;;; ph.el --- Client for the CCSO directory system (aka PH/QI) |
2 | 2 |
3 ;; Copyright (C) 1997 Oscar Figueiredo | 3 ;; Copyright (C) 1997 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch> | 5 ;; Author: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch> |
6 ;; Maintainer: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch> | 6 ;; Maintainer: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch> |
7 ;; Created: May 1997 | 7 ;; Created: May 1997 |
8 ;; Version: $Revision: 1.2 $ | 8 ;; Version: 2.1 |
9 ;; Keywords: help | 9 ;; Keywords: help |
10 | 10 |
11 ;; This file is part of XEmacs | 11 ;; This file is part of XEmacs |
12 | 12 |
13 ;; XEmacs is free software; you can redistribute it and/or modify it | 13 ;; XEmacs is free software; you can redistribute it and/or modify it |
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | 19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
21 ;; General Public License for more details. | 21 ;; General Public License for more details. |
22 | 22 |
23 ;; You should have received a copy of the GNU General Public License | 23 ;; You should have received a copy of the GNU General Public License |
24 ;; along with XEmacs; see the file COPYING. If not, write to | 24 ;; along with XEmacs; see the file COPYING. If not, write to |
25 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 25 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
26 ;; Boston, MA 02111-1307, USA. | 26 ;; Boston, MA 02111-1307, USA. |
27 | 27 |
28 ;;; Commentary: | 28 ;;; Commentary: |
29 | 29 ;; This package provides functions to query CCSO PH/QI nameservers |
30 ;; LCD Archive Entry (not registered yet): | 30 ;; through an interactive form or replace inline query strings in |
31 ;; ph|Oscar Figueiredo|Oscar.Figueiredo@di.epfl.ch| | 31 ;; buffers with appropriately formatted query results (especially |
32 ;; Client for the CCSO directory system (aka PH/QI)| | 32 ;; used to expand email addresses in message buffers). It also |
33 ;; 27-May-1997|Version $Revision: 1.2 $|ftp://(Not Available) | 33 ;; interfaces with the BBDB package to let you register entries of |
34 | 34 ;; the CCSO PH/QI directory into your own database. The CCSO PH/QI |
35 ;; This package provides functions to query CCSO nameservers through an | 35 ;; white pages system was developped at UIUC and is in use in more |
36 ;; interactive form or replace inline query strings in buffers with | |
37 ;; appropriately formatted query results (especially used to expand email | |
38 ;; addresses in message buffers). It also interfaces with the BBDB package | |
39 ;; to let you register entries of the CCSO directory into your own database. | |
40 ;; The CCSO white pages system was developped at UIUC and is in use in more | |
41 ;; than 300 sites in the world. The distribution can be found at | 36 ;; than 300 sites in the world. The distribution can be found at |
42 ;; ftp://uiarchive.cso.uiuc.edu/pub/packages/ph | 37 ;; ftp://uiarchive.cso.uiuc.edu/pub/packages/ph Traditionally the |
43 ;; Traditionally the server is called QI while the client is called PH. | 38 ;; server is called QI while the client is called PH. |
44 | 39 |
45 ;;; Installation: | 40 ;;; Installation: |
46 ;; This package uses the custom and widget libraries. If they are not already | 41 ;; This package uses the custom and widget libraries. If they are not already |
47 ;; installed on your system get them from http://www.dina.kvl.dk/~abraham/custom/ | 42 ;; installed on your system get them from http://www.dina.kvl.dk/~abraham/custom/ |
48 ;; Then uncomment and add the following to your .emacs file: | 43 ;; Then uncomment and add the following to your .emacs file: |
49 ;; (require 'ph) | 44 ;; (require 'ph) |
50 ;; (eval-after-load "message" | 45 ;; (eval-after-load "message" |
51 ;; (define-key message-mode-map [(control ?c) (tab)] 'ph-expand-inline)) | 46 ;; '(define-key message-mode-map [(control ?c) (tab)] 'ph-expand-inline)) |
52 ;; (eval-after-load "mail" | 47 ;; (eval-after-load "mail" |
53 ;; (define-key mail-mode-map [(control ?c) (tab)] 'ph-expand-inline)) | 48 ;; '(define-key mail-mode-map [(control ?c) (tab)] 'ph-expand-inline)) |
54 | |
55 ;; This package should run under XEmacs 19.15 or 20 as well as under Emacs 19.34 and above | |
56 | 49 |
57 ;;; Usage: | 50 ;;; Usage: |
58 ;; * Provided you did the installation as proposed in the above section, | 51 ;; - Provided you did the installation as proposed in the above section, |
59 ;; inline expansion will be available when you compose an email | 52 ;; inline expansion will be available when you compose an email |
60 ;; message. Type the name of somebody recorded in your PH/QI server and hit | 53 ;; message. Type the name of somebody recorded in your PH/QI server and hit |
61 ;; C-c TAB, this will overwrite the name with the corresponding email | 54 ;; C-c TAB, this will overwrite the name with the corresponding email |
62 ;; address | 55 ;; address |
63 ;; * M-x ph-customize to customize inline expansion and other features to | 56 ;; - M-x ph-customize to customize inline expansion and other features to |
64 ;; your needs. | 57 ;; your needs. |
65 ;; * Look for the Ph submenu in the tools menu for more. | 58 ;; - Look for the Ph submenu in the Tools menu for more. |
66 | 59 |
67 ;;; Code: | 60 ;;; Code: |
68 | 61 |
69 (eval-when-compile | 62 (eval-when-compile |
70 (require 'wid-edit)) | 63 (require 'wid-edit)) |
71 (require 'custom) | 64 (require 'custom) |
72 (if (not (fboundp 'make-overlay)) | 65 (if (not (fboundp 'make-overlay)) |
73 (require 'overlay)) | 66 (require 'overlay)) |
74 (if (locate-library "timer") | 67 (if (locate-library "timer") |
75 (require 'timer)) | 68 (require 'timer)) |
69 | |
76 (autoload 'custom-menu-create "cus-edit") | 70 (autoload 'custom-menu-create "cus-edit") |
71 (autoload 'bbdb-create-internal "bbdb-com") | |
72 (autoload 'bbdb-display-records "bbdb") | |
77 | 73 |
78 ;;{{{ Package customization variables | 74 ;;{{{ Package customization variables |
79 | 75 |
80 (defgroup ph nil | 76 (defgroup ph nil |
81 "CCSO (PH/QI) directory system client" | 77 "CCSO (PH/QI) directory system client" |
114 (const :menu-tag "All" all) | 110 (const :menu-tag "All" all) |
115 (const :menu-tag "Abort" abort) | 111 (const :menu-tag "Abort" abort) |
116 (const :menu-tag "None" nil)) | 112 (const :menu-tag "None" nil)) |
117 :group 'ph) | 113 :group 'ph) |
118 | 114 |
119 (defcustom ph-duplicate-fields-handling-method 'list | 115 (defcustom ph-duplicate-fields-handling-method '((email . duplicate)) |
120 "*A method to handle entries containing duplicate fields. | 116 "*A method to handle entries containing duplicate fields. |
121 This is either an alist (FIELD . METHOD) or a symbol METHOD. | 117 This is either an alist (FIELD . METHOD) or a symbol METHOD. |
122 The alist form of the variable associates a method to an individual field, | 118 The alist form of the variable associates a method to an individual field, |
123 the second form specifies a method applicable to all fields. | 119 the second form specifies a method applicable to all fields. |
124 Available methods are: | 120 Available methods are: |
168 (repeat :inline t | 164 (repeat :inline t |
169 :tag "Field names" | 165 :tag "Field names" |
170 (symbol :tag ""))) | 166 (symbol :tag ""))) |
171 :group 'ph) | 167 :group 'ph) |
172 | 168 |
173 (defcustom ph-form-fields '(name firstname email phone) | 169 (defcustom ph-form-fields '(name email phone) |
174 "*A list of fields presented in the query form." | 170 "*A list of fields presented in the query form." |
175 :tag "Default Fields in Query Forms" | 171 :tag "Default Fields in Query Forms" |
176 :type '(repeat (symbol :tag "Field name")) | 172 :type '(repeat (symbol :tag "Field name")) |
177 :group 'ph) | 173 :group 'ph) |
178 | 174 |
179 (defcustom ph-fieldname-formstring-alist '((url . "URL") | 175 (defcustom ph-fieldname-formstring-alist '((url . "URL") |
180 (unix_gid . "Unix GID") | 176 (unix_gid . "Unix GID") |
181 (unix_uid . "Unix UID") | 177 (unix_uid . "Unix UID") |
182 (unit_code . "Unit Code") | 178 (unit_code . "Unit Code") |
183 (department_code . "Department Code") | 179 (department_code . "Department Code") |
184 (high_school . "High School") | 180 (high_school . "High School") |
185 (home_phone . "Home Phone") | 181 (home_phone . "Home Phone") |
186 (office_phone . "Office Phone") | 182 (office_phone . "Office Phone") |
187 (callsign . "HAM Call Sign") | 183 (callsign . "HAM Call Sign") |
188 (office_address . "Office Address") | 184 (office_address . "Office Address") |
189 (office_location . "Office Location") | 185 (office_location . "Office Location") |
190 (id . "ID") | 186 (id . "ID") |
191 (email . "E-Mail") | 187 (email . "E-Mail") |
192 (firstname . "First Name")) | 188 (firstname . "First Name")) |
193 "*A mapping of CCSO database field names onto prompt strings used in query/response forms. | 189 "*A mapping of CCSO database field names onto prompt strings used in query/response forms. |
194 Prompt strings for fields that are not in this are derived by capitalizing | 190 Prompt strings for fields that are not in this are derived by capitalizing |
195 the field name." | 191 the field name." |
196 :tag "Mapping of Field Names onto Prompt Strings" | 192 :tag "Mapping of Field Names onto Prompt Strings" |
197 :type '(repeat (cons :tag "Field" | 193 :type '(repeat (cons :tag "Field" |
198 (symbol :tag "Name") | 194 (symbol :tag "Name") |
199 (string :tag "Prompt string"))) | 195 (string :tag "Prompt string"))) |
200 :group 'ph) | 196 :group 'ph) |
201 | 197 |
202 (defcustom ph-bbdb-mapping-alist '((name . (firstname name)) | 198 (defcustom ph-bbdb-conversion-alist '((name . name) |
203 (email . net)) | 199 (net . email) |
204 "*A mapping of CCSO database field names onto BBDB field names" | 200 (address . (ph-bbdbify-address address "Address")) |
205 :tag "CCSO to BBDB Field Name Mapping" | 201 (phone . ((ph-bbdbify-phone phone "Phone") |
202 (ph-bbdbify-phone office_phone "Office Phone")))) | |
203 "*A mapping from BBDB to PH/QI fields. | |
204 This is a list of cons cells (BBDB-FIELD . SPEC-OR-LIST) where BBDB-FIELD | |
205 is the name of a field that must be defined in your BBDB (standard field | |
206 names are `name', `company', `net', `phone', `address' and `notes'). | |
207 SPEC-OR-LIST is either a single SPEC or a list of SPECs. Lists of specs are | |
208 valid only for the `phone' and `address' BBDB fields. | |
209 SPECs are sexps which are evaluated: | |
210 -a string evaluates to itself | |
211 -a symbol evaluates to the symbol value. Symbols naming PH/QI fields | |
212 present in the record evaluate to the value of the field in the record | |
213 -a form is evaluated as a function. The argument list may contain PH/QI | |
214 field names which eval to the corresponding values in the record. The form | |
215 evaluation should return something appropriate for the particular | |
216 BBDB-FIELD (see bbdb-create-internal). ph-bbdbify-phone and | |
217 ph-bbdbify-address are provided as convenience functions to parse phones | |
218 and addresses." | |
219 :tag "BBDB to CCSO Field Name Mapping" | |
206 :type '(repeat (cons :tag "Field Name" | 220 :type '(repeat (cons :tag "Field Name" |
207 (symbol :tag "CCSO") | 221 (symbol :tag "BBDB Field") |
208 (sexp :tag "BBDB"))) | 222 (sexp :tag "Conversion Spec"))) |
209 :group 'ph) | 223 :group 'ph) |
210 | 224 |
211 (defcustom ph-options-file "~/.emacs" | 225 (defcustom ph-options-file "~/.emacs" |
212 "*A file where the servers hotlist is stored. | 226 "*A file where the servers hotlist is stored. |
213 It should be loaded automatically at startup so ~/.emacs is a reasonable | 227 It should be loaded automatically at startup so ~/.emacs is a reasonable |
232 "Default TCP port for CCSO directory services") | 246 "Default TCP port for CCSO directory services") |
233 | 247 |
234 (defvar ph-form-widget-list nil) | 248 (defvar ph-form-widget-list nil) |
235 (defvar ph-process-buffer nil) | 249 (defvar ph-process-buffer nil) |
236 (defvar ph-read-point) | 250 (defvar ph-read-point) |
251 | |
252 | |
253 | |
254 | |
255 ;;; FSF Emacs does not provide that one | |
256 (if (not (fboundp 'split-string)) | |
257 (defun split-string (string pattern) | |
258 "Return a list of substrings of STRING which are separated by PATTERN." | |
259 (let (parts (start 0)) | |
260 (while (string-match pattern string start) | |
261 (setq parts (cons (substring string start (match-beginning 0)) parts) | |
262 start (match-end 0))) | |
263 (nreverse (cons (substring string start) parts)) | |
264 ))) | |
237 | 265 |
238 (defun ph-display-records (records &optional raw-field-names) | 266 (defun ph-display-records (records &optional raw-field-names) |
239 "Display the record list RECORDS in a formatted buffer. | 267 "Display the record list RECORDS in a formatted buffer. |
240 If RAW-FIELD-NAMES is non nil, no translation to form strings or | 268 If RAW-FIELD-NAMES is non nil, no translation to form strings or |
241 capitalization is done on field names." | 269 capitalization is done on field names." |
396 (setq current-key key)) | 424 (setq current-key key)) |
397 (if (or (null fields) | 425 (if (or (null fields) |
398 (memq 'all fields) | 426 (memq 'all fields) |
399 (memq current-key fields)) | 427 (memq current-key fields)) |
400 (if key | 428 (if key |
401 (setq record (cons (cons key value) record)) | 429 (setq record (cons (cons key value) record)) ; New key |
402 (setcdr (car record) (cons value (if (listp (cdar record)) | 430 (setcdr (car record) (if (listp (cdar record)) |
403 (cdar record) | 431 (append (cdar record) (list value)) |
404 (cons (cdar record) nil))))))))) | 432 (list (cdar record) value)))))))) |
405 (and (not ignore) | 433 (and (not ignore) |
406 (or (null fields) | 434 (or (null fields) |
407 (memq 'all fields) | 435 (memq 'all fields) |
408 (setq record (nreverse record))) | 436 (setq record (nreverse record))) |
409 (setq record (if (not (eq 'list ph-duplicate-fields-handling-method)) | 437 (setq record (if (not (eq 'list ph-duplicate-fields-handling-method)) |
571 (setq ph-read-point match-end) | 599 (setq ph-read-point match-end) |
572 (if return-response | 600 (if return-response |
573 (buffer-substring (point) match-end) | 601 (buffer-substring (point) match-end) |
574 return-code)))) | 602 return-code)))) |
575 | 603 |
576 ;;; FSF Emacs does not provide that one | 604 (defun ph-create-bbdb-record (record) |
577 (if (not (fboundp 'split-string)) | 605 "Create a BBDB record using the RECORD alist. |
578 (defun split-string (string pattern) | 606 RECORD is an alist of (KEY . VALUE) where KEY is a symbol naming a field |
579 "Return a list of substrings of STRING which are separated by PATTERN." | 607 of the PH/QI database and VALUE is the corresponding value for the record" |
580 (let (parts (start 0)) | 608 ;; This function runs in a special context where lisp symbols corresponding |
581 (while (string-match pattern string start) | 609 ;; to field names in record are bound to the corresponding values |
582 (setq parts (cons (substring string start (match-beginning 0)) parts) | 610 (eval |
583 start (match-end 0))) | 611 `(let* (,@(mapcar '(lambda (c) |
584 (nreverse (cons (substring string start) parts)) | 612 (list (car c) (if (listp (cdr c)) |
585 ))) | 613 (list 'quote (cdr c)) |
586 | 614 (cdr c)))) |
615 record) | |
616 bbdb-name | |
617 bbdb-company | |
618 bbdb-net | |
619 bbdb-address | |
620 bbdb-phones | |
621 bbdb-notes | |
622 spec | |
623 bbdb-record | |
624 value) | |
625 | |
626 ;; BBDB standard fields | |
627 (setq bbdb-name (ph-parse-spec (cdr (assq 'name ph-bbdb-conversion-alist)) record nil) | |
628 bbdb-company (ph-parse-spec (cdr (assq 'company ph-bbdb-conversion-alist)) record nil) | |
629 bbdb-net (ph-parse-spec (cdr (assq 'net ph-bbdb-conversion-alist)) record nil) | |
630 bbdb-notes (ph-parse-spec (cdr (assq 'notes ph-bbdb-conversion-alist)) record nil)) | |
631 (setq spec (cdr (assq 'address ph-bbdb-conversion-alist))) | |
632 (setq bbdb-address (delq nil (ph-parse-spec (if (listp (car spec)) | |
633 spec | |
634 (list spec)) | |
635 record t))) | |
636 (setq spec (cdr (assq 'phone ph-bbdb-conversion-alist))) | |
637 (setq bbdb-phones (delq nil (ph-parse-spec (if (listp (car spec)) | |
638 spec | |
639 (list spec)) | |
640 record t))) | |
641 ;; BBDB custom fields | |
642 (setq bbdb-notes (append (list (and bbdb-notes (cons 'notes bbdb-notes))) | |
643 (mapcar (function | |
644 (lambda (mapping) | |
645 (if (and (not (memq (car mapping) | |
646 '(name company net address phone notes))) | |
647 (setq value (ph-parse-spec (cdr mapping) record nil))) | |
648 (cons (car mapping) value)))) | |
649 ph-bbdb-conversion-alist))) | |
650 (setq bbdb-notes (delq nil bbdb-notes)) | |
651 (setq bbdb-record (bbdb-create-internal bbdb-name | |
652 bbdb-company | |
653 bbdb-net | |
654 bbdb-address | |
655 bbdb-phones | |
656 bbdb-notes)) | |
657 | |
658 (bbdb-display-records (list bbdb-record)) | |
659 ))) | |
660 | |
661 (defun ph-parse-spec (spec record recurse) | |
662 "Parse the conversion SPEC using RECORD. | |
663 If RECURSE is non-nil then SPEC may be a list of atomic specs" | |
664 (cond | |
665 ((or (stringp spec) | |
666 (symbolp spec) | |
667 (and (listp spec) | |
668 (symbolp (car spec)) | |
669 (fboundp (car spec)))) | |
670 (condition-case nil | |
671 (eval spec) | |
672 (void-variable nil))) | |
673 ((and recurse | |
674 (listp spec)) | |
675 (mapcar '(lambda (spec-elem) | |
676 (ph-parse-spec spec-elem record nil)) | |
677 spec)) | |
678 (t | |
679 (error "Invalid mapping specification for `%s'. Fix ph-bbdb-conversion-alist" spec)))) | |
680 | |
681 (defun ph-bbdbify-address (addr location) | |
682 "Parse ADDR into a vector compatible with bbdb-create-internal. | |
683 ADR should be an address string of no more than four lines or a | |
684 list of lines. | |
685 The last line is searched for the zip code, city and state name. | |
686 LOCATION is used as the address location for bbdb" | |
687 (let* ((addr-components (if (listp addr) | |
688 (reverse addr) | |
689 (reverse (split-string addr "\n")))) | |
690 (lastl (pop addr-components)) | |
691 zip city state) | |
692 (setq addr-components (nreverse addr-components)) | |
693 (cond | |
694 ;; American style | |
695 ((string-match "\\(\\w+\\)\\W*\\([A-Z][A-Z]\\)\\W*\\([0-9]+\\)" lastl) | |
696 (setq city (match-string 1 lastl) | |
697 state (match-string 2 lastl) | |
698 zip (string-to-number (match-string 3 lastl)))) | |
699 ;; European style | |
700 ((string-match "\\([0-9]+\\)[ \t]+\\(.*\\)" lastl) | |
701 (setq city (match-string 2 lastl) | |
702 zip (string-to-number (match-string 1 lastl)))) | |
703 (t | |
704 (error "ph-bbdbify-address was unable to parse the address. Customize ph-bbdb-conversion-alist"))) | |
705 (vector location | |
706 (or (nth 0 addr-components) "") | |
707 (or (nth 1 addr-components) "") | |
708 (or (nth 2 addr-components) "") | |
709 (or city "") | |
710 (or state "") | |
711 zip))) | |
712 | |
713 (defun ph-bbdbify-phone (phone location) | |
714 "Parse PHONE into a vector compatible with bbdb-create-internal. | |
715 PHONE is either a string supposedly containing a phone number or | |
716 a list of such strings which are concatenated. | |
717 LOCATION is used as the phone location for bbdb" | |
718 (let ((phone-string (cond | |
719 ((stringp phone) | |
720 phone) | |
721 ((listp phone) | |
722 (mapconcat 'identity phone ", ")) | |
723 (t | |
724 (error "Invalid phone specification. Cannot create bbdb record"))))) | |
725 (vector location phone-string))) | |
726 | |
587 ;;}}} | 727 ;;}}} |
588 | 728 |
589 ;;{{{ High-level interfaces (interactive functions) | 729 ;;{{{ High-level interfaces (interactive functions) |
590 | 730 |
591 (defun ph-customize () | 731 (defun ph-customize () |
594 (customize 'ph)) | 734 (customize 'ph)) |
595 | 735 |
596 (defun ph-set-server (server) | 736 (defun ph-set-server (server) |
597 "Set the server to SERVER." | 737 "Set the server to SERVER." |
598 (interactive "sNew PH/QI Server: ") | 738 (interactive "sNew PH/QI Server: ") |
599 (setq ph-server server) | 739 (message "Selected PH/QI server is now %s" server) |
600 (message "Selected PH/QI server is now %s" server)) | 740 (setq ph-server server)) |
601 | 741 |
602 (defun ph-get-email (name) | 742 (defun ph-get-email (name) |
603 "Get the email field of NAME from the PH/QI directory server." | 743 "Get the email field of NAME from the PH/QI directory server." |
604 (interactive "sName: ") | 744 (interactive "sName: ") |
605 (let ((email (cdaar (ph-query-internal name '(email))))) | 745 (let ((email (cdaar (ph-query-internal name '(email))))) |
832 (prin1 ph-server-hotlist) | 972 (prin1 ph-server-hotlist) |
833 (princ ")\n")) | 973 (princ ")\n")) |
834 (save-buffer)) | 974 (save-buffer)) |
835 ) | 975 ) |
836 | 976 |
977 | |
978 (defun ph-insert-record-at-point-into-bbdb () | |
979 "Insert record at point into the BBDB database. | |
980 This function can only be called from a PH/QI query result buffer." | |
981 (interactive) | |
982 (let ((record (and (overlays-at (point)) | |
983 (overlay-get (car (overlays-at (point))) 'ph-record)))) | |
984 (if (null record) | |
985 (error "Point is not over a record.") | |
986 (ph-create-bbdb-record record)))) | |
987 | |
837 ;;}}} | 988 ;;}}} |
838 | 989 |
839 ;;{{{ Menu interface | 990 ;;{{{ Menu interface |
840 | 991 |
841 (require 'easymenu) | 992 (require 'easymenu) |
842 | 993 |
843 (defconst ph-tail-menu | 994 (defconst ph-tail-menu |
844 `(["---" nil nil] | 995 `(["---" nil nil] |
845 ["Query Form" ph-query-form t] | 996 ["Query Form" ph-query-form t] |
846 ["Expand Inline" ph-expand-inline t] | 997 ["Expand Inline" ph-expand-inline t] |
998 ["Insert Record into BBDB" ph-insert-record-at-point-into-bbdb | |
999 (and (or (featurep 'bbdb) | |
1000 (locate-library 'bbdb)) | |
1001 (overlays-at (point)) | |
1002 (overlay-get (car (overlays-at (point))) 'ph-record))] | |
847 ["---" nil nil] | 1003 ["---" nil nil] |
848 ["Get Email" ph-get-email t] | 1004 ["Get Email" ph-get-email t] |
849 ["Get Phone" ph-get-phone t] | 1005 ["Get Phone" ph-get-phone t] |
850 ["List Valid Field Names" ph-get-field-list t] | 1006 ["List Valid Field Names" ph-get-field-list t] |
851 ["---" nil nil] | 1007 ["---" nil nil] |