Anonymous avatar Anonymous committed aad4bd9

EUDC 1.31

Comments (0)

Files changed (12)

 
 	* *: Mega typo fix.
 
+2000-08-17  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc.el (eudc-expand-inline): Perform multiple match processing
+	within server-switch protected zone
+
+2000-08-09  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc-export.el (eudc-create-bbdb-record): Temporarily switch
+	servers before importing to ensure attribute corespondence
+
+	* eudc.el (eudc-server-protect): Restore server even everything
+	runs ok
+
+2000-07-26  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc.el: Fix menu separators according to Ben's advice
+
+2000-07-19  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc.el (eudc-query): Attribute names in the query and in the
+	return list are systematically translated according to
+	`eudc-protocol-attributes-translation-alist'
+	(eudc-expand-inline): Do not translate attributes before calling
+	`eudc-multi-query' since translation is server dependent
+
+2000-07-17  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc.el (eudc-server-protect): New macro
+	(eudc-query
+	(eudc-echo-progress): 
+	(eudc-multi-query): New defun
+	(eudc-process-form): Use it
+	(eudc-setup-record-display-buffer): 
+	(eudc-close-record-display-buffer): New defun
+	(eudc-display-records): Use them
+	(eudc-send-mail): New defun
+	(eudc-format-query): Deleted
+	(eudc-build-query-with-words-on-format): New defun
+	(eudc-query-form): Cosmetic changes for multi-server queries
+	
+	* eudc-vars.el (eudc-multi-query-policy): New variable replacing
+	`eudc-inline-expansion-servers' 
+
+	* eudc-hotlist.el (eudc-edit-hotlist): Avoid error when editing an
+	empty hotlist
+
+2000-07-16  Oscar Figueiredo  <oscar@xemacs.org>
+
+	* eudc-ph.el: 
+	* eudc-ldap.el: 
+	* eudc-bbdb.el: 
+	* eudc.el: 
+	* eudc-vars.el: 	
+	* eudc-hotlist.el: 	
+	* eudc-bob.el: Gerd Moellman's docstring and Emacs compatibility
+	changes
+
 1999-10-17  Oscar Figueiredo  <Oscar.Figueiredo@di.epfl.ch>
 
 	* eudc: EUDC 1.30 is released
 # Boston, MA 02111-1307, USA.
 
 VERSION = 1.33
-AUTHOR_VERSION = 1.30
+AUTHOR_VERSION = 1.31
 MAINTAINER = Oscar Figueiredo <oscar@xemacs.org>
 PACKAGE = eudc
 PKG_TYPE = regular
 
 
 
+* Release 1.31
+  ------------
+
+** You can now send mail directly from query result buffers
+
+** Multi-server queries are now available from query forms as well
+   The variable `eudc-multi-query-policy' indicates how multi-server
+   queries are handled
+
+** Miscellaneous cleanup
+
 * Release 1.30
   ------------
 
 ** Bugfix release, no new features
 
-
 * Release 1.29
   ------------
 
 ** Support for non-textual values 
    Right mouse button pops-up a contextual menu of functions to handle those
    values.
-   Note: internal support for LDAP binary values in XEmacs 21.1 is corrupted
 *** Images can be displayed inline or as buttons (jpegPhoto LDAP attribute)
 *** Sound can be played (audio LDAP attribute)
 *** URLs are clickable (needs browse-url)
 (require 'eudc)
 
 (defvar eudc-bob-generic-keymap nil
-  "Keymap for multimedia objects")
+  "Keymap for multimedia objects.")
 
 (defvar eudc-bob-image-keymap nil
-  "Keymap for inline images")
+  "Keymap for inline images.")
 
 (defvar eudc-bob-sound-keymap nil
-  "Keymap for inline images")
+  "Keymap for inline sounds.")
 
 (defvar eudc-bob-url-keymap nil
-  "Keymap for inline images")
+  "Keymap for inline urls.")
 
 (defconst eudc-bob-generic-menu
   '("EUDC Binary Object Menu"
 
 (defun eudc-bob-can-display-inline-images ()
   "Return non-nil if we can display images inline."
-  (and eudc-xemacs-p
-       (memq (console-type) 
-	     '(x mswindows))
-       (fboundp 'make-glyph)))
+  (if eudc-xemacs-p
+      (and (memq (console-type) '(x mswindows))
+	   (fboundp 'make-glyph))
+    (and (boundp 'image-types)
+	 (not (null images-types)))))
 
 (defun eudc-bob-make-button (label keymap &optional menu plist)
   "Create a button with LABEL.
 
 (defun eudc-bob-display-jpeg (data inline)
   "Display the JPEG DATA at point.
-if INLINE is non-nil then try to inline the image otherwise simply 
+If INLINE is non-nil, try to inline the image otherwise simply 
 display a button."
-  (let ((glyph (if (eudc-bob-can-display-inline-images)
-		   (make-glyph (list (vector 'jpeg :data data) 
-				     [string :data "[JPEG Picture]"])))))
-    (eudc-bob-make-button "[JPEG Picture]"
-			  eudc-bob-image-keymap
-			  eudc-bob-image-menu
-			  (list 'glyph glyph
-				'end-glyph (if inline glyph)
-				'duplicable t
-				'invisible inline
-				'start-open t
-				'end-open t
-				'object-data data))))
+  (cond (eudc-xemacs-p
+	 (let ((glyph (if (eudc-bob-can-display-inline-images)
+			  (make-glyph (list (vector 'jpeg :data data) 
+					    [string :data "[JPEG Picture]"])))))
+	   (eudc-bob-make-button "[JPEG Picture]"
+				 eudc-bob-image-keymap
+				 eudc-bob-image-menu
+				 (list 'glyph glyph
+				       'end-glyph (if inline glyph)
+				       'duplicable t
+				       'invisible inline
+				       'start-open t
+				       'end-open t
+				       'object-data data))))
+	(t
+	 (let* ((image (create-image data nil t))
+		(props (list 'object-data data 'eudc-image image)))
+	   (when inline
+	     (setq props (nconc (list 'display image) props)))
+	   (eudc-bob-make-button "[Picture]"
+				 eudc-bob-image-keymap
+				 eudc-bob-image-menu
+				 props)))))
 
 (defun eudc-bob-toggle-inline-display ()
-  "Toggle inline display of an image"
+  "Toggle inline display of an image."
   (interactive)
-  (if (eudc-bob-can-display-inline-images)
-      (let ((overlays (append (overlays-at (1- (point)))
-			      (overlays-at (point))))
-	    overlay glyph)
-	(setq overlay (car overlays))
-	(while (and overlay
-		    (not (setq glyph (overlay-get overlay 'glyph))))
-	  (setq overlays (cdr overlays))
-	  (setq overlay (car overlays)))
-	(if overlay
-	    (if (overlay-get overlay 'end-glyph)
-		(progn
-		  (overlay-put overlay 'end-glyph nil)
-		  (overlay-put overlay 'invisible nil))
-	      (overlay-put overlay 'end-glyph glyph)
-	      (overlay-put overlay 'invisible t))))))
+  (when (eudc-bob-can-display-inline-images)
+    (cond (eudc-xemacs-p
+	   (let ((overlays (append (overlays-at (1- (point)))
+				   (overlays-at (point))))
+		 overlay glyph)
+	     (setq overlay (car overlays))
+	     (while (and overlay
+			 (not (setq glyph (overlay-get overlay 'glyph))))
+	       (setq overlays (cdr overlays))
+	       (setq overlay (car overlays)))
+	     (if overlay
+		 (if (overlay-get overlay 'end-glyph)
+		     (progn
+		       (overlay-put overlay 'end-glyph nil)
+		       (overlay-put overlay 'invisible nil))
+		   (overlay-put overlay 'end-glyph glyph)
+		   (overlay-put overlay 'invisible t)))))
+	  (t
+	   (let* ((overlays (append (overlays-at (1- (point)))
+				    (overlays-at (point))))
+		  image)
+
+	     ;; Search overlay with an image.
+	     (while (and overlays (null image))
+	       (let ((prop (overlay-get (car overlays) 'eudc-image)))
+		 (if (imagep prop)
+		     (setq image prop)
+		   (setq overlays (cdr overlays)))))
+
+	     ;; Toggle that overlay's image display.
+	     (when overlays
+	       (let ((overlay (car overlays)))
+		 (overlay-put overlay 'display
+			      (if (overlay-get overlay 'display)
+				  nil image)))))))))
 
 (defun eudc-bob-display-audio (data)
-  "Display a button for audio DATA"
+  "Display a button for audio DATA."
   (eudc-bob-make-button "[Audio Sound]"
 			eudc-bob-sound-keymap
 			eudc-bob-sound-menu
 			      'end-open t
 			      'object-data data)))
 
-
 (defun eudc-bob-display-generic-binary (data)
-  "Display a button for unidentified binary DATA"
+  "Display a button for unidentified binary DATA."
   (eudc-bob-make-button "[Binary Data]"
 			eudc-bob-generic-keymap
 			eudc-bob-generic-menu
   (let (sound)
     (if (null (setq sound (eudc-bob-get-overlay-prop 'object-data)))
 	(error "No sound data available here")
-      (if (not (and (boundp 'sound-alist)
-		    sound-alist))
-	  (error "Don't know how to play sound on this Emacs version")
-	(setq sound-alist 
-	      (cons (list 'eudc-sound 
-			  :sound sound)
-		    sound-alist))
-	(condition-case nil
-	    (play-sound 'eudc-sound)
-	  (t 
-	   (setq sound-alist (cdr sound-alist))))))))
+      (cond (eudc-xemacs-p
+	     (if (not (and (boundp 'sound-alist)
+			   sound-alist))
+		 (error "Don't know how to play sound on this Emacs version")
+	       (setq sound-alist 
+		     (cons (list 'eudc-sound 
+				 :sound sound)
+			   sound-alist))
+	       (condition-case nil
+		   (play-sound 'eudc-sound)
+		 (t 
+		  (setq sound-alist (cdr sound-alist))))))
+	    (t
+	     (unless (fboundp 'play-sound)
+	       (error "Playing sounds not supported on this system"))
+	     (play-sound (list 'sound :data sound)))))))
   
 
 (defun eudc-bob-play-sound-at-mouse (event)
        (kill-buffer buffer)))))
 
 (defun eudc-bob-menu ()
-  "Retrieve the menu attached to a binary object"
+  "Retrieve the menu attached to a binary object."
   (eudc-bob-get-overlay-prop 'menu))
   
 (defun eudc-bob-popup-menu (event)
-  "Pop-up a menu of EUDC multimedia commands"
+  "Pop-up a menu of EUDC multimedia commands."
   (interactive "@e")
   (run-hooks 'activate-menubar-hook)
   (eudc-jump-to-event event)
 RECORD is an alist of (KEY . VALUE) where KEY is a directory attribute name
 symbol and VALUE is the corresponding value for the record.
 If SILENT is non-nil then the created BBDB record is not displayed."
-  ;; This function runs in a special context where lisp symbols corresponding
-  ;; to field names in record are bound to the corresponding values
   (eval 
    `(let* (,@(mapcar '(lambda (c)
 			(list (car c) (if (listp (cdr c))
 					  (list 'quote (cdr c))
 					(cdr c))))
-		     record)
+		     (cdr record))
 	     bbdb-name
 	     bbdb-company
 	     bbdb-net
 	     spec
 	     bbdb-record
 	     value
-	     (conversion-alist (symbol-value eudc-bbdb-conversion-alist)))
-
+	     conversion-alist)
+      
+      (eudc-server-protect 
+       (eudc-set-server (caar record) (cdar record))
+       (setq conversion-alist (symbol-value eudc-bbdb-conversion-alist)))
+      
       ;; BBDB standard fields
       (setq bbdb-name (eudc-parse-spec (cdr (assq 'name conversion-alist)) record nil)
 	    bbdb-company (eudc-parse-spec (cdr (assq 'company conversion-alist)) record nil)
 	    bbdb-notes (eudc-parse-spec (cdr (assq 'notes conversion-alist)) record nil))
       (setq spec (cdr (assq 'address conversion-alist)))
       (setq bbdb-address (delq nil (eudc-parse-spec (if (listp (car spec))
-						      spec
-						    (list spec))
-						  record t)))
+							spec
+						      (list spec))
+						    record t)))
       (setq spec (cdr (assq 'phone conversion-alist)))
       (setq bbdb-phones (delq nil (eudc-parse-spec (if (listp (car spec))
-						     spec
-						   (list spec))
-						 record t)))
+						       spec
+						     (list spec))
+						   record t)))
       ;; BBDB custom fields
       (setq bbdb-notes (append (list (and bbdb-notes (cons 'notes bbdb-notes)))
 			       (mapcar (function
 					      bbdb-notes))
       (or silent
 	  (bbdb-display-records (list bbdb-record))))))
-
+  
 (defun eudc-parse-spec (spec record recurse)
   "Parse the conversion SPEC using RECORD.
 If RECURSE is non-nil then SPEC may be a list of atomic specs."
 
 ;;;###autoload
 (defun eudc-edit-hotlist ()
-  "Edit the hotlist of directory servers in a specialized buffer"
+  "Edit the hotlist of directory servers in a specialized buffer."
   (interactive)
-  (let ((proto-col 0)
+  (let ((proto-col 10)
 	gap)
     (switch-to-buffer (get-buffer-create "*EUDC Servers*"))
     (setq buffer-read-only nil)
   (eudc-hotlist-mode)))
 
 (defun eudc-hotlist-add-server ()
-  "Add a new server to the list after current one"
+  "Add a new server to the list after current one."
   (interactive)
   (if (not (eq major-mode 'eudc-hotlist-mode))
       (error "Not in a EUDC hotlist edit buffer"))
     (insert protocol "\n")))
 
 (defun eudc-hotlist-delete-server ()
-  "Delete the server at point from the list"
+  "Delete the server at point from the list."
   (interactive)
   (if (not (eq major-mode 'eudc-hotlist-mode))
       (error "Not in a EUDC hotlist edit buffer"))
 	(error "No server on this line")))))
 
 (defun eudc-hotlist-quit-edit ()
-  "Quit the hotlist editing mode and save changes to the hotlist"
+  "Quit the hotlist editing mode and save changes to the hotlist."
   (interactive)
   (if (not (eq major-mode 'eudc-hotlist-mode))
       (error "Not in a EUDC hotlist edit buffer"))
     (kill-this-buffer)))
 
 (defun eudc-hotlist-select-server ()
-  "Select the server at point as the current server"
+  "Select the server at point as the current server."
   (interactive)
   (if (not (eq major-mode 'eudc-hotlist-mode))
       (error "Not in a EUDC hotlist edit buffer"))
       (error "No server on this line"))))
       
 (defun eudc-hotlist-transpose-servers ()
-  "Swap the order of the server with the previous one in the list"
+  "Swap the order of the server with the previous one in the list."
   (interactive)
   (if (not (eq major-mode 'eudc-hotlist-mode))
       (error "Not in a EUDC hotlist edit buffer"))
 ;;{{{      EUDC Main Custom Group
 
 (defgroup eudc nil 
-  "Emacs Unified Directory Client"
+  "Emacs Unified Directory Client."
   :group 'mail
   :group 'comm)
 
 (defvar eudc-supported-protocols nil
   "Protocols currently supported by EUDC.
 This variable is updated when protocol-specific libraries
-are loaded, *do not change by hand*.")
+are loaded, *do not change manually*.")
 
 (defcustom eudc-protocol nil
   "*The directory protocol to use to query the server.
 
 
 (defcustom eudc-strict-return-matches t
-  "*If non-nil, ignore entries that do not contain all requested return attributes."
+  "*Ignore or allow entries not containing all requested return attributes.
+If non-nil, such entries are ignored."
   :type  'boolean
   :group 'eudc)
 
 (defcustom eudc-default-return-attributes nil
-  "*A list of the default attributes to extract from directory entries.
-If set to the symbol `all' return all attributes.
-nil means return the default attributes as configured in the server."
+  "*A list of default attributes to extract from directory entries.
+If set to the symbol `all', return all attributes.
+A value of nil means return the default attributes as configured in the
+server."
   :type  '(choice :menu-tag "Return Attributes"
 		  (const :menu-tag "Server defaults (nil)" nil)
 		  (const :menu-tag "All" all)
 (defcustom eudc-inline-query-format '((name) 
 				      (firstname name))
   "*Format of an inline expansion query.
-This is a list of FORMATs.  A FORMAT is a itself list of one or more 
+This is a list of FORMATs.  A FORMAT is itself a list of one or more 
 EUDC attribute names.  A FORMAT applies if it contains as many attributes as
-individual words in the inline query string.
+there are individual words in the inline query string.
 If several FORMATs apply then they are tried in order until a match 
 is found.  
-If nil all the words are mapped onto the default server or protocol 
+If nil, all the words are mapped onto the default server or protocol 
 attribute name.
 
 The attribute names in FORMATs are not restricted to EUDC attribute names
-but can also be protocol/server specific names, in this case this variable
-must be set in a protocol/server local fashion, see `eudc-server-set' and
+but can also be protocol/server specific names.  In this case, this variable
+must be set in a protocol/server-local fashion, see `eudc-server-set' and
 `eudc-protocol-set'."
   :tag "Format of Inline Expansion Queries"
   :type  '(repeat
 
 (defcustom eudc-inline-expansion-format '("%s" email)
   "*A list specifying the format of the expansion of inline queries.
-This variable controls what `eudc-expand-inline' actually inserts in the buffer.
-First element is a string passed to `format'.  Remaining elements are symbols
-indicating attribute names, the corresponding values are passed
-as additional arguments to `format'."
+This variable controls what `eudc-expand-inline' actually inserts in
+the buffer.  First element is a string passed to `format'.  Remaining
+elements are symbols indicating attribute names; the corresponding values
+are passed as additional arguments to `format'."
   :type  '(list 
 	   (string :tag "Format String")
 	   (repeat :inline t
 		    (symbol :tag "Attribute name"))))
   :group 'eudc)
 
-(defcustom eudc-inline-expansion-servers 'server-then-hotlist
-  "*Which servers to contact for the expansion of inline queries.
+(defcustom eudc-multi-query-policy 'server-then-hotlist
+  "*Policy for querying multiple servers.
 Possible values are:
-  `current-server': the EUDC current server
-  `hotlist': the servers of the hotlist in the order they appear
+  `current-server': the current EUDC server.
+  `hotlist': the servers of the hotlist in the order they appear,
   `server-then-hotlist': the current server and then the servers of 
-  the hotlist"
+  the hotlist."
   :type '(choice :tag "Servers"
 		 :menu-tag "Servers"
 		 (const :menu-tag "Current server" current-server)
 
 (defcustom eudc-max-servers-to-query nil
   "*Maximum number of servers to query for an inline expansion.
-If nil query all servers available from `eudc-inline-expansion-servers'"
+If nil, query all servers available from `eudc-inline-expansion-servers'."
   :tag "Max Number of Servers to Query"
   :type '(choice :tag "Max. Servers"
 		 :menu-tag "Max. Servers"
 instead of the raw directory attribute names.
 Prompt strings for attributes that are not listed here
 are derived by splitting the attribute name
-at `_' signs and capitalizing the individual words."
+at `_' characters and capitalizing the individual words."
   :tag   "User-defined Names of Directory Attributes"
   :type  '(repeat (cons :tag "Field"
 			(symbol :tag "Directory attribute")
   :group 'eudc)
 
 (defcustom eudc-attribute-display-method-alist nil
-  "*An alist specifying methods to display attribute values.  Each member 
-of the list is of the form (NAME . FUNC) where NAME is a lowercased
+  "*An alist specifying methods to display attribute values.
+Each member of the list is of the form (NAME . FUNC) where NAME is a lowercased
 string naming a directory attribute (translated according to 
 `eudc-user-attribute-names-alist' if `eudc-use-raw-directory-names' is 
 non-nil) and FUNC a function that will be passed the corresponding 
 				   ("ShowAudio" "showaudio"))
   "*A list of viewer program specifications.
 Viewers are programs which can be piped a directory attribute value for
-display or arbitrary processing. Each specification is a list whose 
-first element is a string naming the viewer, the second element is the 
-executable program which should be invoked and following elements are
+display or arbitrary processing.  Each specification is a list whose 
+first element is a string naming the viewer.  The second element is the 
+executable program which should be invoked, and following elements are
 arguments that should be passed to the program."
   :tag "External Viewer Programs"
   :type '(repeat (list :tag "Viewer"
 ;;{{{ PH Custom Group
 
 (defgroup eudc-ph nil 
-  "Emacs Unified Directory Client - CCSO PH/QI Backend"
+  "Emacs Unified Directory Client - CCSO PH/QI Backend."
   :group 'eudc)
 
 (defcustom eudc-ph-bbdb-conversion-alist
 ;;{{{ LDAP Custom Group
 
 (defgroup eudc-ldap nil 
-  "Emacs Unified Directory Client - LDAP Backend"
+  "Emacs Unified Directory Client - LDAP Backend."
   :group 'eudc)
 
 (defcustom eudc-ldap-bbdb-conversion-alist
 ;;{{{ BBDB Custom Group
 
 (defgroup eudc-bbdb nil 
-  "Emacs Unified Directory Client - BBDB Backend"
+  "Emacs Unified Directory Client - BBDB Backend."
   :group 'eudc)
 
 (defcustom eudc-bbdb-use-locations-as-attribute-names t
   :group 'eudc-bbdb)
 
 (defcustom eudc-bbdb-enable-substring-matches t
-  "If non-nil, authorize substring matches in the same way BBDB does.
+  "If non-nil, authorize substring match in the same way BBDB does.
 Otherwise records must match queries exactly."
   :type 'boolean
   :group 'eudc-bbdb)
   (if (not (fboundp 'unless))
       (require 'cl)))
 
-(autoload 'custom-menu-create "cus-edit")
+(unless (fboundp 'custom-menu-create)
+  (autoload 'custom-menu-create "cus-edit"))
 
 (require 'eudc-vars)
 
 
 (defun eudc-lax-plist-get (plist prop &optional default)
   "Extract a value from a lax property list.
-
-LAX-PLIST is a lax property list, which is a list of the form (PROP1
-VALUE1 PROP2 VALUE2...), where comparison between properties is done
+PLIST is a lax property list, which is a list of the form (PROP1
+VALUE1 PROP2 VALUE2...), where comparisons between properties are done
 using `equal' instead of `eq'.  This function returns the value
-corresponding to the given PROP, or DEFAULT if PROP is not one of the
+corresponding to PROP, or DEFAULT if PROP is not one of the
 properties on the list."
   (if (not (= 0 (% (length plist) 2)))
       (error "Malformed plist"))
 		parts)))))
 
 (defun eudc-replace-in-string (str regexp newtext)
-  "Replace all matches in STR for REGEXP with NEWTEXT string,
- and returns the new string."
+  "Replace all matches in STR for REGEXP with NEWTEXT.
+Value is the new string."
   (let ((rtn-str "")
 	(start 0)
 	match prev-start)
 ;;{{{ Server and Protocol Variable Routines
 
 (defun eudc-server-local-variable-p (var)
-  "Return non-nil if variable has server local bindings"
+  "Return non-nil if VAR has server-local bindings."
   (eudc-plist-member (get var 'eudc-locals) 'server))
 
 (defun eudc-protocol-local-variable-p (var)
-  "Return non-nil if variable has protocol local bindings"
+  "Return non-nil if VAR has protocol-local bindings."
   (eudc-plist-member (get var 'eudc-locals) 'protocol))
 
 (defun eudc-default-set (var val)
       (setq eudc-known-protocols
 	    (cons protocol eudc-known-protocols))))
 
+;; Execute BODY restoring the server and protocol if anything goes wrong
+(defmacro eudc-server-protect (&rest body)
+  `(let ((eudc-former-server eudc-server)
+	 (eudc-former-protocol eudc-protocol))
+     (condition-case signal
+	(progn
+	  ,@body
+	  (or (and (equal eudc-server eudc-former-server)
+		   (equal eudc-protocol eudc-former-protocol))
+	      (eudc-set-server eudc-former-server eudc-former-protocol t)))
+       (t (or (and (equal eudc-server eudc-former-server)
+		   (equal eudc-protocol eudc-former-protocol))
+	      (eudc-set-server eudc-former-server eudc-former-protocol t))
+	  (signal (car signal) (cdr signal))))))
+
+(defun eudc-echo-progress (server protocol)
+  (message "Querying %s with protocol %s..." server protocol))
 
 (defun eudc-translate-query (query)
-  "Translate attribute names of QUERY according to `eudc-protocol-attributes-translation-alist'."
+  "Translate attribute names of QUERY.
+The translation is done according to 
+`eudc-protocol-attributes-translation-alist'."
   (if eudc-protocol-attributes-translation-alist
       (mapcar '(lambda (attribute)
 		 (let ((trans (assq (car attribute) 
     query)) 
 
 (defun eudc-translate-attribute-list (list)
-  "Translate a list of attribute names according to `eudc-protocol-attributes-translation-alist'."
+  "Translate a list of attribute names LIST.
+The translation is done according to
+`eudc-protocol-attributes-translation-alist'."
   (if eudc-protocol-attributes-translation-alist
       (let (trans)
 	(mapcar '(lambda (attribute)
   (setq eudc-pre-select-window-configuration nil
 	eudc-insertion-marker nil))
 
-(defun eudc-query (query &optional return-attributes no-translation)
+(defun eudc-query (query &optional return-attributes)
    "Query the current directory server with QUERY.
 QUERY is a list of cons cells (ATTR . VALUE) where ATTR is an attribute
-name and VALUE the corresponding value.  
-If NO-TRANSLATION is non nil, ATTR is translated according to 
-`eudc-protocol-attributes-translation-alist'.
+name and VALUE the corresponding value.
 RETURN-ATTRIBUTES is a list of attributes to return defaulting to 
 `eudc-default-return-attributes'."
    (unless eudc-query-function
      (error "Don't know how to perform the query"))
-   (if no-translation
-       (funcall eudc-query-function query (or return-attributes
-					      eudc-default-return-attributes))
-		
-     (funcall eudc-query-function 
-	      (eudc-translate-query query)
-	      (cond 
-	       (return-attributes
-		(eudc-translate-attribute-list return-attributes))
-	       ((listp eudc-default-return-attributes)
-		(eudc-translate-attribute-list eudc-default-return-attributes))
-	       (t
-		eudc-default-return-attributes)))))
+   (funcall eudc-query-function 
+	    (eudc-translate-query query)
+	    (cond 
+	     (return-attributes
+	      (eudc-translate-attribute-list return-attributes))
+	     ((listp eudc-default-return-attributes)
+	      (eudc-translate-attribute-list eudc-default-return-attributes))
+	     (t
+	      eudc-default-return-attributes))))
+
+
+(defun eudc-multi-query (queries 
+			 &optional sentinel return-attributes try-all)
+  "Query one or several directory servers with a list of QUERIES.
+The servers that are queried are determined by `eudc-multi-query-policy' 
+and `eudc-max-servers-to-query'.
+QUERIES is a list of individual queries. An individual query is a list
+of cons cells (ATTR . VALUE) where ATTR is an attribute name and VALUE 
+is the corresponding value.
+SENTINEL is a symbol naming a sentinel function which is called
+for each new server tried.
+RETURN-ATTRIBUTES is a list of attributes to return defaulting to 
+`eudc-default-return-attributes'.
+If TRY-ALL is non-nil then all servers are tried in order, otherwise
+search stops when at leasta match is found on a server.
+The value is a list of server matches. Each server match is itself a 
+list of the form ((SERVER .PROTO) MATCH1 MATCH2 ...) where MATCHn is
+a matching record found on this server.  A matching record is a list
+of cons cells (ATTR . VALUE) where ATTR is an attribute name and VALUE 
+is the corresponding value"
+  (if (memq eudc-multi-query-policy 
+	    '(current-server server-then-hotlist))
+      (or eudc-server
+	  (call-interactively 'eudc-set-server))
+    (or eudc-server-hotlist
+	(error "No server in the hotlist")))
+  (let (servers response found)
+    ;; Prepare the list of servers to query
+    (setq servers
+	  (cond 
+	   ((eq eudc-multi-query-policy 'hotlist)
+	    eudc-server-hotlist)
+	   ((eq eudc-multi-query-policy 'server-then-hotlist)
+	    (cons (cons eudc-server eudc-protocol)
+		  (delete (cons eudc-server eudc-protocol)
+			  (copy-sequence eudc-server-hotlist))))
+	   ((eq eudc-multi-query-policy 'current-server)
+	    (list (cons eudc-server eudc-protocol)))
+	   (t
+	    (error "Wrong value for `eudc-multi-query-policy': %S"
+		   eudc-multi-query-policy))))
+    (if (and eudc-max-servers-to-query
+	     (> (length servers) eudc-max-servers-to-query))
+	(setcdr (nthcdr (1- eudc-max-servers-to-query) servers) nil))
+    
+    (eudc-server-protect
+     (catch 'found
+       ;; Loop on the servers
+       (while servers
+	 (eudc-set-server (eudc-caar servers) (eudc-cdar servers) t)
+	 (if sentinel
+	     (funcall sentinel 
+		      (eudc-caar servers) 
+		      (eudc-cdar servers)))
+	 
+	 ;; Loop on queries
+	 (mapcar 
+	  (function 
+	   (lambda (query)
+	     ;; If the query is a simple list of strings, 
+	     ;; try to build a valid query
+	     (or (consp (car query))
+		 (setq query (eudc-build-query-with-words-on-format query)))
+	     (setq response (cons (cons (cons eudc-server eudc-protocol)
+					(eudc-query query return-attributes))
+				  response))
+	     (setq found (or found (cadr (car response))))
+	     (if (and found (null try-all))
+		 (throw 'found response))))
+	  queries)
+	 (setq servers (cdr servers)))))
+     
+     (if (null found)
+	 (error "No match")
+       response)))
 
 (defun eudc-format-attribute-name-for-display (attribute)
   "Format a directory attribute name for display.
     (indent-to (+ 2 column-width))
     (eudc-print-attribute-value field)))
 
-(defun eudc-display-records (records &optional raw-attr-names)
-  "Display the record list RECORDS in a formatted buffer. 
-If RAW-ATTR-NAMES is non-nil, the raw attribute names are displayed
-otherwise they are formatted according to `eudc-user-attribute-names-alist'."
+(defun eudc-setup-record-display-buffer ()
+  "Setup a buffer to display records."
   (let ((buffer (get-buffer-create "*Directory Query Results*"))
-	inhibit-read-only
-	precords
-	(width 0)
-	beg
-	first-record
-	attribute-name)
+	inhibit-read-only)
     (switch-to-buffer buffer)    
-    (setq buffer-read-only t)
-    (setq inhibit-read-only t)
+    (setq buffer-read-only t
+	  inhibit-read-only t)
     (erase-buffer)
     (insert "Directory Query Result\n")
-    (insert "======================\n\n\n")
-    (if (null records)
-	(insert "No match found.\n"
-		(if eudc-strict-return-matches
-		    "Try setting `eudc-strict-return-matches' to nil or change `eudc-default-return-attributes'.\n"
-		  ""))
-      ;; Replace field names with user names, compute max width
-      (setq precords
-	    (mapcar 
-	     (function
-	      (lambda (record)
-		(mapcar 
-		 (function
-		  (lambda (field)
-		    (setq attribute-name 
-			  (if raw-attr-names
-			      (symbol-name (car field))
-			    (eudc-format-attribute-name-for-display (car field))))
-		    (if (> (length attribute-name) width)
-			(setq width (length attribute-name)))
-		    (cons attribute-name (cdr field))))
-		 record)))
-	     records))
-      ;; Display the records
-      (setq first-record (point))
-      (mapcar 
-       (function
-	(lambda (record)
-	  (setq beg (point))
-	  ;; Map over the record fields to print the attribute/value pairs
-	  (mapcar (function 
-		   (lambda (field)
-		     (eudc-print-record-field field width))) 
-		  record)
-	  ;; Store the record internal format in some convenient place
-	  (overlay-put (make-overlay beg (point))
-		       'eudc-record
-		       (car records))
-	  (setq records (cdr records))
-	  (insert "\n")))
-       precords))
+    (insert "======================\n\n\n")))
+
+(defun eudc-close-record-display-buffer ()
+  "Insert the closing of a record display buffer."
+  (let ((inhibit-read-only t))
     (insert "\n")
     (widget-create 'push-button
 		   :notify (lambda (&rest ignore)
 			     (kill-this-buffer))
 		   "Quit")
     (eudc-mode)
-    (widget-setup)
-    (if first-record
-	(goto-char first-record))))
+    (widget-setup)))
+ 
+(defun eudc-display-records (records &optional raw-attr-names)
+  "Display RECORDS in a formatted buffer.
+RECORDS is a server-prefixed record list as returned by `eudc-multi-query'.
+If RAW-ATTR-NAMES is non-nil, the raw attribute names are displayed
+otherwise they are formatted according to `eudc-user-attribute-names-alist'."
+  (let ((inhibit-read-only t)
+	precords
+	(width 0)
+	beg
+	attribute-name
+	num-matches
+	server)
+
+    ;; Print the number of records in the list
+    (setq num-matches (if (cdr records)
+			  (length (cdr records))
+			0))
+    (widget-insert (format "%d match%s found on %s (%s)\n\n"
+			   num-matches
+			   (if (> num-matches 1) "es" "")
+			   (caar records)
+			   (cdar records)))
+    
+    (eudc-server-protect
+     (setq server (car records))
+     ;; We need to switch servers because value display methods depend on the server
+     (eudc-set-server (car server) (cdr server) t)
+     ;; Drop server header from the record list
+     (setq records (cdr records))
+     ;; Replace field names with user names and compute max width
+     (setq precords
+	   (mapcar 
+	    (function
+	     (lambda (record)
+	       (mapcar 
+		(function
+		 (lambda (field)
+		   (setq attribute-name 
+			 (if raw-attr-names
+			     (symbol-name (car field))
+			   (eudc-format-attribute-name-for-display (car field))))
+		   (if (> (length attribute-name) width)
+		       (setq width (length attribute-name)))
+		   (cons attribute-name (cdr field))))
+		record)))
+	    records))
+     ;; Display the records
+     (mapcar 
+      (function
+       (lambda (record)
+	 (setq beg (point))
+	 ;; Map over the record fields to print the attribute/value pairs
+	 (mapcar (function 
+		  (lambda (field)
+		    (eudc-print-record-field field width))) 
+		 record)
+	 ;; Store the record internal format in some convenient place
+	 (overlay-put (make-overlay beg (point))
+		      'eudc-record
+		      (cons server (car records)))
+	 (setq records (cdr records))
+	 (insert "\n")))
+      precords))))
+  
+(defun eudc-send-mail ()
+  "Send email to the address in the current record."
+  (interactive)
+  (unless (eq major-mode 'eudc-mode)
+    (error "This command should be called in EUDC buffers"))
+  (let ((record
+         (overlay-get (car (overlays-at (point))) 'eudc-record))
+        (mail nil))
+    (unless record (error "Not on a record"))
+    ;; Since eudc-protocol-attributes-translation-alist is server-dependent we
+    ;; need to switch servers temporarily
+    (eudc-server-protect
+     (eudc-set-server (caar record) (cdar record))
+     (setq mail (cdr (assq 
+		      (or 
+		       (cdr (assq 'email 
+				 (symbol-value eudc-protocol-attributes-translation-alist)))
+			 'email) 
+		     (cdr record)))))
+    (if mail
+	(funcall (get mail-user-agent 'composefunc) mail)
+      (error "Cannot determine email address"))))
 
 (defun eudc-process-form ()
   "Process the query form in current buffer and display the results."
-  (let (query-alist
-	value)
+  (let (query value result inhibit-read-only)
     (if (not (and (boundp 'eudc-form-widget-list)
 		  eudc-form-widget-list))
 	(error "Not in a directory query form buffer")
 	       (lambda (wid-field)
 		 (setq value (widget-value (cdr wid-field)))
 		 (if (not (string= value ""))
-		     (setq query-alist (cons (cons (car wid-field) value)
-					     query-alist)))))
+		     (setq query (cons (cons (car wid-field) value)
+				       query)))))
 	      eudc-form-widget-list)
       (kill-buffer (current-buffer))
-      (eudc-display-records (eudc-query query-alist) eudc-use-raw-directory-names))))
-         
-           
+      (setq result (eudc-multi-query (list query) 'eudc-echo-progress nil t))
+      ;; Display the query results
+      (eudc-setup-record-display-buffer)
+      (mapcar (function 
+	       (lambda (server-matches)
+		 (eudc-display-records server-matches
+				       eudc-use-raw-directory-names)))
+	      result)
+      (eudc-close-record-display-buffer))))
 
 (defun eudc-filter-duplicate-attributes (record)
   "Filter RECORD according to `eudc-duplicate-attribute-handling-method'."
 	      entries)))
     (error "The %s protocol has no support for listing attributes" eudc-protocol)))
 
-(defun eudc-format-query (words format)
-  "Use FORMAT to build a EUDC query from WORDS"
+(defun eudc-build-query-with-words-on-format (words &optional format)
+  "Use FORMAT to build a EUDC query from WORDS.
+If FORMAT id nil, use the protocol default attribute name, if any."
   (let (query
 	query-alist
 	key val cell)
 
 (defun eudc-extract-n-word-formats (format-list n)
   "Extract a list of N-long formats from FORMAT-LIST.
-If none try N-1 and so forth."
+If none try N - 1 and so forth."
   (let (formats)
     (while (and (null formats)
 		(> n 0))
 `eudc-inline-expansion-format' is inserted in the buffer at point.
 If REPLACE is non nil, then this expansion replaces the name in the buffer.
 `eudc-expansion-overwrites-query' being non nil inverts the meaning of REPLACE.
-Multiple servers can be tried with the same query until one finds a match, 
-see `eudc-inline-expansion-servers'"
+Multiple servers can be tried with the same query until a match is found, 
+see `eudc-multi-query-policy'"
   (interactive)
-  (if (memq eudc-inline-expansion-servers 
-	    '(current-server server-then-hotlist))
-      (or eudc-server
-	  (call-interactively 'eudc-set-server))
-    (or eudc-server-hotlist
-	(error "No server in the hotlist")))
   (let* ((end (point))
 	 (beg (save-excursion
 		(if (re-search-backward "\\([:,]\\|^\\)[ \t]*" 
 		(point)))
 	 (query-words (split-string (buffer-substring beg end) "[ \t]+"))
 	 query-formats
+	 queries
 	 response
 	 response-string
-	 response-strings
-	 (eudc-former-server eudc-server)
-	 (eudc-former-protocol eudc-protocol)
-	 servers)
+	 response-strings)
 
-    ;; Prepare the list of servers to query
-    (setq servers (copy-sequence eudc-server-hotlist))
-    (setq servers
-	  (cond 
-	   ((eq eudc-inline-expansion-servers 'hotlist)
-	    eudc-server-hotlist)
-	   ((eq eudc-inline-expansion-servers 'server-then-hotlist)
-	    (cons (cons eudc-server eudc-protocol)
-		  (delete (cons eudc-server eudc-protocol) servers)))
-	   ((eq eudc-inline-expansion-servers 'current-server)
-	    (list (cons eudc-server eudc-protocol)))
-	   (t
-	    (error "Wrong value for `eudc-inline-expansion-servers': %S"
-		   eudc-inline-expansion-servers))))
-    (if (and eudc-max-servers-to-query
-	     (> (length servers) eudc-max-servers-to-query))
-	(setcdr (nthcdr (1- eudc-max-servers-to-query) servers) nil))
+    ;; Determine which formats apply in the query-format list
+    (setq query-formats
+	  (eudc-extract-n-word-formats eudc-inline-query-format
+					(length query-words)))
+	
+    (setq queries 
+	  (if query-formats
+	      (mapcar '(lambda (format)
+			 (eudc-build-query-with-words-on-format query-words format))
+		      query-formats)
+	    query-words))
+				
+    (setq response
+	  (car (eudc-multi-query queries nil (cdr eudc-inline-expansion-format))))
+	    
+    ;; Process response through eudc-inline-expansion-format. We need to switch
+    ;; to the context of the server where a match was found
+    (if response
+	(eudc-server-protect
+	  ;; Switch to the context of the server where a match was found
+	 (eudc-set-server (caar response) (cdar response))
+	 (setq response (cdr response))	; Drop the server/protocol part
 
-    (condition-case signal
-	(progn
-	  (setq response 
-		(catch 'found
-		  ;; Loop on the servers
-		  (while servers
-		    (eudc-set-server (eudc-caar servers) (eudc-cdar servers) t)
-		    
-		    ;; Determine which formats apply in the query-format list
-		    (setq query-formats
-			  (or 
-			   (eudc-extract-n-word-formats eudc-inline-query-format
-							(length query-words))
-			   (if (null eudc-protocol-has-default-query-attributes)
-			       '(name))))
-		    
-		    ;; Loop on query-formats
-		    (while query-formats
-		      (setq response
-			    (eudc-query
-			     (eudc-format-query query-words (car query-formats))
-			     (eudc-translate-attribute-list
-			      (cdr eudc-inline-expansion-format))))
-		      (if response
-			  (throw 'found response))
-		      (setq query-formats (cdr query-formats)))
-		    (setq servers (cdr servers)))
-		  ;; No more servers to try... no match found
-		  nil))
+	 ;; Loop over the matches found on the server
+	 (while response
+	   (setq response-string (apply 'format 
+					(car eudc-inline-expansion-format)
+					(mapcar (function 
+						 (lambda (field)
+						   (or (cdr (assq field (car response))) 
+						       "")))
+						(eudc-translate-attribute-list
+						 (cdr eudc-inline-expansion-format)))))
+	   (if (> (length response-string) 0)
+	       (setq response-strings
+		     (cons response-string response-strings)))
+	   (setq response (cdr response)))
+    
+	 (if (or
+	      (and replace (not eudc-expansion-overwrites-query))
+	      (and (not replace) eudc-expansion-overwrites-query))
+	     (delete-region beg end))
+	 (cond 
+	  ((or (= (length response-strings) 1)
+	       (null eudc-multiple-match-handling-method)
+	       (eq eudc-multiple-match-handling-method 'first))
+	   (insert (car response-strings)))
+	  ((eq eudc-multiple-match-handling-method 'select)
+	   (eudc-select response-strings))
+	  ((eq eudc-multiple-match-handling-method 'all)
+	   (insert (mapconcat 'identity response-strings ", ")))
+	  ((eq eudc-multiple-match-handling-method 'abort)
+	   (error "There is more than one match for the query")))))))
 
-
-	  (if (null response)
-	      (error "No match")
-	    
-	    ;; Process response through eudc-inline-expansion-format
-	    (while response
-	      (setq response-string (apply 'format 
-					   (car eudc-inline-expansion-format)
-					   (mapcar (function 
-						    (lambda (field)
-						      (or (cdr (assq field (car response))) 
-							  "")))
-						   (eudc-translate-attribute-list
-						    (cdr eudc-inline-expansion-format)))))
-	      (if (> (length response-string) 0)
-		  (setq response-strings
-			(cons response-string response-strings)))
-	      (setq response (cdr response)))
-	    
-	    (if (or
-		 (and replace (not eudc-expansion-overwrites-query))
-		 (and (not replace) eudc-expansion-overwrites-query))
-		(delete-region beg end))
-	    (cond 
-	     ((or (= (length response-strings) 1)
-		  (null eudc-multiple-match-handling-method)
-		  (eq eudc-multiple-match-handling-method 'first))
-	      (insert (car response-strings)))
-	     ((eq eudc-multiple-match-handling-method 'select)
-	      (eudc-select response-strings))
-	     ((eq eudc-multiple-match-handling-method 'all)
-	      (insert (mapconcat 'identity response-strings ", ")))
-	     ((eq eudc-multiple-match-handling-method 'abort)
-	      (error "There is more than one match for the query"))
-	     ))
-	  (or (and (equal eudc-server eudc-former-server)
-		   (equal eudc-protocol eudc-former-protocol))
-	      (eudc-set-server eudc-former-server eudc-former-protocol t)))
-      (t
-       (or (and (equal eudc-server eudc-former-server)
-		(equal eudc-protocol eudc-former-protocol))
-	   (eudc-set-server eudc-former-server eudc-former-protocol t))
-       (signal (car signal) (cdr signal))))))
-  
 ;;;###autoload
 (defun eudc-query-form (&optional get-fields-from-server)
-  "Display a form to query the directory server.
-If given a non-nil argument the function first queries the server 
-for the existing fields and displays a corresponding form."
+  "Display a form to query directory servers.
+If given a non-nil argument GET-FIELDS-FROM-SERVER, the function first
+queries the server for the existing fields and displays a corresponding form."
   (interactive "P")
   (let ((fields (or (and get-fields-from-server
 			 (eudc-get-attribute-list))
     (make-local-variable 'eudc-form-widget-list)
     (widget-insert "Directory Query Form\n")
     (widget-insert "====================\n\n")
-    (widget-insert "Current server is: " (or eudc-server
+    (widget-insert "Multi-query policy: "
+		   (cond
+		    ((eq eudc-multi-query-policy 'current-server)
+		     "current server only\n")
+		    ((eq eudc-multi-query-policy 'hotlist)
+		     (if (or (null eudc-max-servers-to-query)
+			     (>= eudc-max-servers-to-query
+				 (length eudc-server-hotlist)))
+			 "hotlist servers\n"
+		       (concat "First " 
+			       eudc-max-servers-to-query
+			       " servers of the hotlist\n")))
+		    ((eq eudc-multi-query-policy 'server-then-hotlist)
+		     (if (or (null eudc-max-servers-to-query)
+			     (> eudc-max-servers-to-query
+				(length eudc-server-hotlist)))
+			 "current server then hotlist\n"
+		       (format "current server then first %d servers of the hotlist\n"
+			       (1- eudc-max-servers-to-query))))))
+    (widget-insert "Current server is : " (or eudc-server
 					     (progn 
 					       (call-interactively 'eudc-set-server)
 					       eudc-server))
 					     "\n")
-    (widget-insert "Protocol         : " (symbol-name eudc-protocol) "\n")
+    (widget-insert "Protocol          : " (symbol-name eudc-protocol) "\n")
     ;; Build the list of prompts
     (setq prompts (if eudc-use-raw-directory-names
 		      (mapcar 'symbol-name (eudc-translate-attribute-list fields))
   )
 
 (defun eudc-bookmark-server (server protocol)
-  "Add SERVER to the EUDC `servers' hotlist."
+  "Add SERVER using PROTOCOL to the EUDC `servers' hotlist."
   (interactive "sDirectory server: \nsProtocol: ")
   (if (member (cons server protocol) eudc-server-hotlist)
       (error "%s:%s is already in the hotlist" protocol server)
 (defconst eudc-custom-generated-menu (cdr (custom-menu-create 'eudc)))
 
 (defconst eudc-tail-menu 
-  `(["---" nil nil]
+  `("---"
     ["Query with Form" eudc-query-form t]
     ["Expand Inline Query" eudc-expand-inline t]
+    ["Send mail to this address" eudc-send-mail
+     (and (overlays-at (point))
+	  (overlay-get (car (overlays-at (point))) 'eudc-record))]
     ["Insert Record into BBDB" eudc-insert-record-at-point-into-bbdb 
      (and (or (featurep 'bbdb)
 	      (prog1 (locate-library "bbdb") (message "")))
      (and (eq major-mode 'eudc-mode)
 	  (or (featurep 'bbdb)
 	      (prog1 (locate-library "bbdb") (message ""))))]
-    ["---" nil nil]
+    "---"
     ["Get Email" eudc-get-email t]
     ["Get Phone" eudc-get-phone t]
     ["List Valid Attribute Names" eudc-get-attribute-list t]
-    ["---" nil nil]
+    "---"
     ,(cons "Customize" eudc-custom-generated-menu)))
     
 
 (defconst eudc-server-menu 
-  '(["---" nil nil]
+  '("---"
     ["Bookmark Current Server" eudc-bookmark-current-server t]
     ["Edit Server List" eudc-edit-hotlist t]
     ["New Server" eudc-set-server t]))
   (interactive)
   nil)
 
+;;}}}
+
 ;;;###autoload
-(let ((menu  '("Directory Search"
-	       ["Load Hotlist of Servers" eudc-load-eudc t]
-	       ["New Server" eudc-set-server t]
-	       ["---" nil nil]
-	       ["Query with Form" eudc-query-form t]
-	       ["Expand Inline Query" eudc-expand-inline t]
-	       ["---" nil nil]
-	       ["Get Email" eudc-get-email t]
-	       ["Get Phone" eudc-get-phone t])))
-  (if (not (featurep 'eudc-autoloads))
-      (if (string-match "XEmacs" emacs-version)
-	  (if (and (featurep 'menubar)
-		   (not (featurep 'infodock)))
-	      (add-submenu '("Tools") menu))
-	(require 'easymenu)
-	(cond 
-	 ((fboundp 'easy-menu-add-item)
-	  (easy-menu-add-item nil '("tools") (easy-menu-create-menu (car menu)
-								    (cdr menu))))
-	 ((fboundp 'easy-menu-create-keymaps)
-	  (define-key 
-	    global-map
-	    [menu-bar tools eudc] 
-	    (cons "Directory Search"
-		  (easy-menu-create-keymaps "Directory Search" (cdr menu)))))))))
+(cond ((not (string-match "XEmacs" emacs-version))
+       (defvar eudc-tools-menu (make-sparse-keymap "Directory Search"))
+       (fset 'eudc-tools-menu (symbol-value 'eudc-tools-menu))
+       
+       (define-key eudc-tools-menu [phone]
+	 '("Get Phone" . eudc-get-phone))
+       (define-key eudc-tools-menu [email]
+	 '("Get Email" . eudc-get-email))
+       (define-key eudc-tools-menu [separator-eudc-email]
+	 '("---"))
+       (define-key eudc-tools-menu [expand-inline]
+	 '("Expand Inline Query" . eudc-expand-inline))
+       (define-key eudc-tools-menu [query]
+	 '("Query with Form" . eudc-query-form))
+       (define-key eudc-tools-menu [separator-eudc-query]
+	 '("---"))
+       (define-key eudc-tools-menu [new]
+	 '("New Server" . eudc-set-server))
+       (define-key eudc-tools-menu [load]
+	 '("Load Hotlist of Servers" . eudc-load-eudc)))
+      
+      (t
+       (let ((menu  '("Directory Search"
+		      ["Load Hotlist of Servers" eudc-load-eudc t]
+		      ["New Server" eudc-set-server t]
+		      "---"
+		      ["Query with Form" eudc-query-form t]
+		      ["Expand Inline Query" eudc-expand-inline t]
+		      "---"
+		      ["Get Email" eudc-get-email t]
+		      ["Get Phone" eudc-get-phone t])))
+	 (if (not (featurep 'eudc-autoloads))
+	     (if (string-match "XEmacs" emacs-version)
+		 (if (and (featurep 'menubar)
+			  (not (featurep 'infodock)))
+		     (add-submenu '("Tools") menu))
+	       (require 'easymenu)
+	       (cond 
+		((fboundp 'easy-menu-add-item)
+		 (easy-menu-add-item nil '("tools")
+				     (easy-menu-create-menu (car menu)
+							    (cdr menu))))
+		((fboundp 'easy-menu-create-keymaps)
+		 (define-key 
+		   global-map
+		   [menu-bar tools eudc] 
+		   (cons "Directory Search"
+			 (easy-menu-create-keymaps "Directory Search"
+						   (cdr menu)))))))))))
         
 ;;}}}
 
 @footnotestyle end
 
 @ifinfo
+@dircategory Editors
 @direntry
-* EUDC::   A client for directory servers (LDAP, PH)
+* EUDC: (eudc).   A client for directory servers (LDAP, PH)
 @end direntry
 
-This file documents EUDC v1.29
+This file documents EUDC v1.32
 
 EUDC is part of XEmacs.
 
-EUDC is the Emacs Unified Directory Client, a common interface
-interface to directory servers using various protocols such as LDAP or
-the CCSO white pages directory system (PH/QI)
+EUDC is the Emacs Unified Directory Client, a common interface to
+directory servers using various protocols such as LDAP or the CCSO white
+pages directory system (PH/QI)
 
-Copyright @copyright{} 1998 Free Software Foundation, Inc.
+Copyright @copyright{} 1998, 2000 Free Software Foundation, Inc.
 
 Permission is granted to make and distribute verbatim
 copies of this manual provided the copyright notice and
 @title{EUDC Manual}
 @subtitle{The Emacs Unified Directory Client}
 @author by Oscar Figueiredo
-@code{1.29}
+@code{1.32}
 
 @page
 @vskip 0pt plus 1fill
-     Copyright @copyright{} 1998 Free Software Foundation, Inc.
+     Copyright @copyright{} 1998, 2000 Free Software Foundation, Inc.
 
      Permission is granted to make and distribute verbatim
      copies of this manual provided the copyright notice and
 @comment  node-name,  next,         previous, up
 
 
-This manual documents EUDC v1.29, the Emacs Unified Directory Client.
+This manual documents EUDC v1.32, the Emacs Unified Directory Client.
 
-A common interface interface to directory servers using various
-protocols such as LDAP or the CCSO white pages directory system (PH/QI)
+A common interface to directory servers using various protocols such as
+LDAP or the CCSO white pages directory system (PH/QI)
 
 @end ifinfo
 
 Queries using a customizable form
 @item
 Inline query expansion (for instance you can expand a name
-to an e-mail address in a mail message buffer using a server as an
+to an email address in a mail message buffer using a server as an
 address book)
 @item
-Multiple servers can be tried in turn until a match is found for an
-inline query
+Multiple servers can automatically be tried in turn
 @item
-Fast minibuffer queries for e-mail addresses and phone numbers
+Fast minibuffer queries for email addresses and phone numbers
 @item
 Interface to BBDB to let you insert server records into your own BBDB database
 (@pxref{Top,,BBDB,bbdb,BBDB Manual})
 
 Quoted from RFC 1777:
 
-   [LDAP] is designed to provide access to the X.500 Directory while not
-   incurring the resource requirements of the Directory Access Protocol
-   (DAP). This protocol is specifically targeted at simple management
-   applications and browser applications that provide simple read/write
-   interactive access to the X.500 Directory, and is intended to be a
-   complement to the DAP itself.
+@quotation
+[LDAP] is designed to provide access to the X.500 Directory while not
+incurring the resource requirements of the Directory Access Protocol
+(DAP). This protocol is specifically targeted at simple management
+applications and browser applications that provide simple read/write
+interactive access to the X.500 Directory, and is intended to be a
+complement to the DAP itself.
+@end quotation
 
 LDAP servers usually store (but are not limited to) information about
-people such as their name, phone number, e-mail address, office
+people such as their name, phone number, email address, office
 location, etc@enddots{} More information about LDAP can be found at
 @url{http://www.openldap.org/}
 
 The Central Computing Services Office (CCSO) of the University of
 Illinois at Urbana Champaign (UIUC) created and freely distributes a
 directory system that is currently in use in more than 300 organizations
-around the world. The system records information about people such as
-their address, phone number, e-mail, academic information or any other
+around the world.  The system records information about people such as
+their address, phone number, email, academic information or any other
 details it was configured to.
 
 The system consists of two parts: a database server traditionally called
-@code{qi} and a command-line client called
-@code{ph}. @url{ftp://uiarchive.cso.uiuc.edu/pub/packages/ph} is the
-main distribution site.
-@url{http://www.uiuc.edu/cgi-bin/ph/lookup?Query=.} provides a listing
-of the active @code{qi} servers.
+@samp{qi} and a command-line client called @samp{ph}.
+@url{ftp://uiarchive.cso.uiuc.edu/pub/packages/ph} is the main
+distribution site.  @url{http://www.uiuc.edu/cgi-bin/ph/lookup?Query=.}
+provides a listing of the active @samp{qi} servers.
 
-The original command-line @code{ph} client that comes with the
-@code{ph/qi} distribution provides additional features like the
-possibility to communicate with the server in login mode which makes it
-possible to change records in the database. This is not implemented in
+The original command-line @samp{ph} client that comes with the
+@samp{ph/qi} distribution provides additional features like the
+possibility to communicate with the server in login-mode which makes it
+possible to change records in the database.  This is not implemented in
 EUDC.
 
 
 @section BBDB
 
 BBDB is the Big Brother's Insiduous Database, a package for Emacs
-originally written by Jamie Zawinski and which provides rolodex-like
-database functionality with tight integration with the Emacs mail and
-news readers.
+originally written by Jamie Zawinski which provides rolodex-like
+database functionality featuring tight integration with the Emacs mail
+and news readers.
 
-It is often used as an enhanced e-mail address book.
+It is often used as an enhanced email address book.
 
 EUDC considers BBDB as a directory server backend just like LDAP or
 PH/QI servers though BBDB has no client/server protocol and thus always
-resides locally on your machine. The point in this is not to offer an
+resides locally on your machine.  The point in this is not to offer an
 alternate way to query your BBDB database (BBDB itself provides much
 more flexible ways to do that) but rather to offer an interface to your
 local directory that is consistent with the interface to external
-directories (LDAP, PH/QI).  This is particularly interesting to perform
-queries on multiple servers.
+directories (LDAP, PH/QI).  This is particularly interesting when
+performing queries on multiple servers.
 
 EUDC also offers a means to insert results from directory queries into
 your own local BBDB (@pxref{Creating BBDB Records})
 @comment  node-name,  next,  previous,  up
 @chapter Installation
 
-The installation procedure depends on the Emacs flavor you are running.
-
-On XEmacs, EUDC is distributed as an XEmacs package.  Follow the rules
-for the installation of XEmacs packages (@pxref{Packages,,XEmacs
+EUDC is distributed as an XEmacs package.  Follow the rules for the
+installation of XEmacs packages (@pxref{Packages,,XEmacs
 Packages,xemacs,XEmacs Manual}).
 
-On GNU Emacs simply copy the @code{*.el} files to some directory in your
-@code{load-path}. Add the following to your @code{.emacs} init file:
-@lisp
-(require 'eudc)
-@end lisp
-This will install EUDC at startup.
+After installing EUDC you will find (the next time you launch XEmacs) a
+new @samp{Directory Search} submenu in the @samp{Tools} menu that will
+give you access to EUDC.
 
-After installing EUDC you will find (the next time you launch Emacs) a
-new @code{Directory Search} submenu in the @code{Tools} menu that will give you
-access to EUDC.
-
-You may also find useful to add the following to your @code{.emacs}
-initialization file to add a shortcut for e-mail address expansion in
-e-mail composition buffers (@pxref{Inline Query Expansion})
+You may also find it useful to add the following to your @file{.emacs}
+initialization file to add a shortcut for email address expansion in
+email composition buffers (@pxref{Inline Query Expansion})
 
 @lisp
 (eval-after-load 
 @comment  node-name,  next,  previous,  up
 @section LDAP Requirements
 
-EUDC needs external support to query LDAP servers.  If LDAP support is
-not available you will get that error message: @samp{Cannot open load
-file: ldap}
+For EUDC to be able to query LDAP servers, LDAP support must be compiled
+into the XEmacs binary otherwise you will get that error message:
+@samp{Cannot open load file: ldap}
 
-In XEmacs LDAP support can be compiled into the XEmacs binary.  LDAP
-support is automatically compiled in when you build XEmacs provided
+LDAP support is automatically compiled in when you build XEmacs provided
 appropriate LDAP libraries are installed on your system.  As of this
 writing you can use either (URLs are subject to change):
 
 @item
 University of Michigan's LDAP Client software
 (@url{http://www.umich.edu/~dirsvcs/ldap/})
-@item
-Netscape's LDAP SDK (@url{http://developer.netscape.com/one/directory/})
 @end itemize
 
 
-In GNU Emacs, LDAP support is added by means of @code{ldap.el} available 
-from the same place you downloaded EUDC.  @code{ldap.el} needs an
-external command line utility named @code{ldapsearch} which is available 
-in the LDAP toolkits mentioned above.  
-
-
-
-
 @node Usage, Credits, Installation, Top
 @comment  node-name,  next,  previous,  up
 @chapter Usage
 
-This chapter describes the usage of EUDC. Most functions and
-customization options are available through the @code{Directory Search}
-sub-menu of the @code{Tools} sub-menu.
+This chapter describes the usage of EUDC.  Most functions and
+customization options are available through the @samp{Directory Search}
+submenu of the @samp{Tools} submenu.
 
 @menu
 * Querying Servers::            How queries are performed and handled 
 @comment  node-name,  next,  previous,  up
 @section Querying Servers
 
-EUDC's basic functionality is to let you query a directory server
-and return the results back to you. There are several things you may
-want to customize in this process.
+EUDC's basic functionality is to let you query a directory server and
+return the results back to you.  There are several things you may want
+to customize in this process.
 
 
 @menu
 (@pxref{The Server Hotlist}) available in the @samp{Server} submenu or
 by selecting @samp{New Server} in that same menu.
 
-LDAP servers generally require some configuration before you can perform 
-queries on them.  In particular, the Search Base must be configured.  If 
-the server you select has no configured search base then EUDC will
-propose you to configure it at this point.  A customization buffer will
-be displayed where you can edit the search base and other parameters for 
-the server.
+LDAP servers generally require some configuration before you can perform
+queries on them.  In particular, the @dfn{search base} must be
+configured.  If the server you select has no configured search base then
+EUDC will propose you to configure it at this point.  A customization
+buffer will be displayed where you can edit the search base and other
+parameters for the server.
 
 @defvar eudc-server
 The name or IP address of the remote directory server. A TCP port number
 
 @defvar eudc-protocol
 The directory protocol to use to query the server.  Currently supported
-protocols in this version of EUDC are @samp{ph}, @samp{ldap} and @samp{bbdb}.
+protocols in this version of EUDC are @code{ph}, @code{ldap} and @code{bbdb}.
 @end defvar
 
 @deffn Command eudc-set-server
 @node Return Attributes, Duplicate Attributes, Selecting a Server, Querying Servers
 @subsection Return Attributes
 
-Directory servers may be configured to return a default set of attributes for
-each record matching a query if the query specifies none. The variable
-@code{eudc-default-return-attributes} controls the return attributes you want to 
-see, if different from the server defaults.
+Directory servers may be configured to return a default set of
+attributes for each record matching a query if the query specifies none.
+The variable @code{eudc-default-return-attributes} controls the return
+attributes you want to see, if different from the server defaults.
 
 @defvar eudc-default-return-attributes
 A list of the default attributes to extract from directory entries.  If
-set to the symbol @code{all} then all available attributes are returned. @code{nil}
-returns the default attributes as configured in the server. Default is
-@code{nil}
+set to the symbol @code{all} then all available attributes are
+returned. A value of @code{nil}, the default, means to return the
+default attributes as configured in the server.
 @end defvar
 
 The server may return several matching records to a query. Some of the
 
 Directory standards may authorize different instances of the same
 attribute in a record. For instance the record of a person may contain
-several e-mail fields containing different e-mail addresses. When using
+several email fields containing different email addresses. When using
 a QI directory server this is difficult to distinguish from attributes
 having multi-line values such as the postal address that may contain a
 line for the street and another one for the zip code and city name. In
-both cases, EUDC will consider the attribute be duplicated.
+both cases, EUDC will consider the attribute duplicated.
 
 EUDC has several methods to deal with duplicated attributes. The
 available methods are:
 Discards all the duplicate values of the field keeping only the first
 one.
 @item concat
-Concatenates the different values using @code{\n} as a separator. The
+Concatenates the different values using a newline as a separator. The
 record keeps only one instance of the field the value of which is a
 single multi-line string.
 @item duplicate
-Duplicates the whole record into as many instances as there are different
-values for the field. This is the default for the e-mail field. Thus a
-record containing 3 different e-mail addresses is duplicated into three
-different records each having a single e-mail address. This is
-particularly useful in combination with @code{select} as the method to
-handle multiple matches in inline expansion queries (@pxref{Inline Query
-Expansion}) because you are presented with the 3 addresses in a
-selection buffer
+Duplicates the whole record into as many instances as there are
+different values for the field.  This is the default for the email
+field.  Thus a record containing 3 different email addresses is
+duplicated into three different records each having a single email
+address.  This is particularly useful in combination with @code{select}
+as the method to handle multiple matches in inline expansion queries
+(@pxref{Inline Query Expansion}) because you are presented with the 3
+addresses in a selection buffer
 @end table
 
 Because a method may not be applicable to all fields, the variable
 
 @defvar eudc-duplicate-attribute-handling-method
 A method to handle entries containing duplicate attributes.  This is
-either an alist (@var{attr} . @var{method}) or a symbol @var{method}.
-The alist form of the variable associates a method to an individual
-attribute name, the second form specifies a method applicable to all
-attribute names. Available methods are: @code{list}, @code{first}, @code{concat},
-@code{duplicate} (see above).  Defaults to @code{list}.
+either an alist @code{(@var{attr} . @var{method})} or a symbol
+@var{method}.  The alist form of the variable associates a method to an
+individual attribute name, the second form specifies a method applicable
+to all attribute names. Available methods are: @code{list},
+@code{first}, @code{concat}, @code{duplicate} (see above).  Defaults to
+@code{list}.
 @end defvar
 
 
 @section Query Form
 
 The simplest way to query your directory server is to use the query
-form. You display the query form with the @code{Query with Form} menu
-item or by invoking the command @kbd{eudc-query-form}. The attribute
+form. You display the query form with the @samp{Query with Form} menu
+item or by invoking the command @kbd{M-x eudc-query-form}. The attribute
 names presented in this form are defined by the
 @code{eudc-query-form-attributes} variable (unless a non-@code{nil}
 argument is supplied to @code{eudc-query-form}).
 of attribute names and a mapping between these names and their
 protocol-specific equivalent through the variable
 @code{eudc-protocol-attributes-translation-alist}.  Names currently
-defined by EUDC are @samp{name}, @samp{firstname}, @samp{email} and
-@samp{phone}.
+defined by EUDC are @code{name}, @code{firstname}, @code{email} and
+@code{phone}.
 
 @defvar eudc-query-form-attributes
 A list of attributes presented in the query form.  Attribute names in
 this list should be either EUDC attribute names or valid attribute
 names.  You can get a list of valid attribute names for the current
-protocol with the @code{List Valid Attribute Names} menu item or the
-@kbd{eudc-get-attribute-list} command. Defaults to @code{name},
+protocol with the @samp{List Valid Attribute Names} menu item or the
+@kbd{M-x eudc-get-attribute-list} command. Defaults to @code{name},
 @code{email} and @code{phone}.
 @end defvar
 
 @deffn Command eudc-query-form get-fields-from-server
 Display a form to query the directory server.  If given a non-@code{nil}
 argument the function first queries the server for the existing fields
-and displays a corresponding form.  All protocols may not support a
+and displays a corresponding form.  Not all protocols may support a
 non-@code{nil} argument here.
 @end deffn
 
 
 @defvar eudc-attribute-display-method-alist
 An alist specifying methods to display attribute values.  Each member of
-the list is of the form (@var{name} . @var{func}) where @var{name} is a
-lowercased string naming a directory attribute (translated according to
-@code{eudc-user-attribute-names-alist} if
-@code{eudc-use-raw-directory-names} is non-nil) and @var{func} a
+the list is of the form @code{(@var{name} . @var{func})} where
+@var{name} is a lowercased string naming a directory attribute
+(translated according to @code{eudc-user-attribute-names-alist} if
+@code{eudc-use-raw-directory-names} is non-@code{nil}) and @var{func} a
 function that will be passed the corresponding attribute values for
 display.
 @end defvar
 @section Inline Query Expansion
 
 Inline query expansion is a powerful method to get completion from your
-directory server. The most common usage is for expanding names to e-mail
+directory server. The most common usage is for expanding names to email
 addresses in mail message buffers. The expansion is performed by the
-command @code{eudc-expand-inline} which is available from the
+command @kbd{M-x eudc-expand-inline} which is available from the
 @samp{Directory Search} menu but can also be conveniently bound to a key
 shortcut (@pxref{Installation})  The operation is controlled by the
 variables @code{eudc-inline-expansion-format},
 name and the remaining words are all considered as surname constituents.
 
 @var{format}s are in fact not limited to EUDC attribute names, you can
-use server or protocol specific names in them.  It may be safer if you
-do so, to set the variable @code{eudc-inline-query-format} in a protocol
-or server local fashion (see @pxref{Server/Protocol Locals}).
+use server or protocol specific names in them.  If you do so it is
+highly recommended to set the variable @code{eudc-inline-query-format}
+in a protocol or server local fashion (see @pxref{Server/Protocol
+Locals}).
 
 For instance you could use the following to match up to three words
 against the @code{cn} attribute of LDAP servers:
 This variable lets you control exactly what is inserted into the buffer
 upon an inline expansion request. It is a list whose first element is a
 string passed to @code{format}. Remaining elements are symbols
-corresponding to directory attribute names.  
-The corresponding attribute values
-are passed as additional arguments to format. Default is @code{("%s"
-email)} but you may want to consider a value like @code{("%s <%s>" name
-email)}
+corresponding to directory attribute names.  The corresponding attribute
+values are passed as additional arguments to @code{format}. Default is
+@code{("%s" email)} but you may want to consider a value like @code{("%s
+<%s>" name email)}
 @end defvar
 
 @defvar eudc-multiple-match-handling-method
 
 EUDC lets you maintain a list of frequently used servers so that you 
 can easily switch from one to another. This hotlist appears in the
-@code{Server} sub-menu. You select a server in this list by clicking on
+@samp{Server} submenu. You select a server in this list by clicking on
 its name. You can add the current server to the list with the command
-@code{eudc-bookmark-current-server}. The list is contained in the variable
+@kbd{M-x eudc-bookmark-current-server}. The list is contained in the variable
 @code{eudc-server-hotlist} which is stored in and retrieved from the file
 designated by @code{eudc-options-file}.  EUDC also provides a facility to
 edit the hotlist interactively (@pxref{The Hotlist Edit Buffer}).
 @deffn Command eudc-hotlist-quit-edit
 Bound to @kbd{q}.
 Save the changes and quit the hotlist edit buffer.  Use @kbd{x} or
-@code{kill-buffer} to exit without saving.
+@kbd{M-x kill-buffer} to exit without saving.
 @end deffn
 
 
 @comment  node-name,  next,  previous,  up
 @section Multi-server Queries
 
-When using inline query expansion (@pxref{Inline Query Expansion}), EUDC
-can try to query successively a sequence of directory servers until one
-of them successfully finds a match for the query.
+When performing inline or form queries, EUDC can try to contact a
+sequence of directory servers.  When performing form queries EUDC tries
+all the servers specified by the variable @code{eudc-multi-query-policy}
+and displays all the matching records.  When performing inline expansion
+queries however, EUDC stops trying different servers as soon as a match
+has been found on one of them.
 
-@defvar eudc-inline-expansion-servers
-This variable controls which servers are tried and in which order when
-trying to perform an inline query. Possible values are:
+@defvar eudc-multi-query-policy
+This variable the policy for querying multiple servers. Possible values are:
 @table @code
 @item current-server
 Only the current directory server is tried
 @item hotlist
-The servers in the hotlist are tried in order until one finds a match
-for the query or `eudc-max-servers-to-query' is reached
+Up to @code{eudc-max-servers-to-query} servers in the hotlist are tried
+in order
 @item server-then-hotlist
-The current server then the servers in the hotlist are tried in the
-order they appear in the hotlist until one of them finds a match or
-`eudc-max-servers-to-query' is reached.  This is the default.
+The current server then Up to @code{eudc-max-servers-to-query}-1 servers
+in the hotlist are tried.  This is the default.
 @end table
 @end defvar
 
 
 With EUDC, you can automatically create BBDB records
 (@pxref{Top,,BBDB,bbdb,BBDB Manual}) from records you get from a
-directory server. You do this by moving the point to the appropriate
+directory server. You do this by moving point to the appropriate
 record in a query result display buffer and invoking the command
-@code{eudc-insert-record-at-point-into-bbdb} with the
+@kbd{M-x eudc-insert-record-at-point-into-bbdb} with the
 keyboard binding @kbd{b} @footnote{This keybinding does not actually
 call @code{eudc-insert-record-at-point-into-bbdb} but uses
 @code{eudc-try-bbdb-insert} instead.}, or with the menu. EUDC
 
 It is also possible to export to BBDB the whole batch of records
 contained in the directory query result with the command
-@code{eudc-batch-export-records-to-bbdb}.
+@kbd{M-x eudc-batch-export-records-to-bbdb}.
 
 Because directory systems may not enforce a strict record format, local
 server installations may use different attribute names and have
 mapping between BBDB field names onto directory attribute names records.
 This is a protocol-local variable and is initialized upon protocol
 switch (@pxref{Server/Protocol Locals})  The alist is made of cells of the
-form @code{(}@var{bbdb-field} . @var{spec-or-list}@code{)}. 
+form @code{(@var{bbdb-field} . @var{spec-or-list})}. 
 @var{bbdb-field} is the name of a field
 that must be defined in your BBDB environment (standard field names are
 @code{name}, @code{company}, @code{net}, @code{phone}, @code{address}
 @code{eudc-bbdbify-address}
 @item
 two @code{phone} fields are created (when possible) in the BBDB record.
-The first one has "Phone" for location and its value is obtained by
+The first one has @cite{Phone} for location and its value is obtained by
 parsing the @code{phone} attribute of the PH/QI record with the function
-@code{eudc-bbdbify-phone}. The second one has "Office Phone" for location
+@code{eudc-bbdbify-phone}. The second one has @cite{Office Phone} for location
 its value is obtained by parsing the @code{office_phone} attribute of the
 PH/QI record with the function @code{eudc-bbdbify-phone}.
 @end itemize
 server/protocol local bindings for a particular variable.
 
 @defun eudc-server-local-variable-p var
-Return non-nil if variable has server local bindings
+Return non-@code{nil} if @var{var} has server-local bindings
 @end defun
 
 @defun eudc-protocol-local-variable-p var
-Return non-nil if variable has protocol local bindings
+Return non-@code{nil} if @var{var} has protocol-local bindings
 @end defun
 
 The following functions allow you to set the value of a variable with
 protocol) is not changed.
 @end defun
 
-@defun eudc-protocol-set var val [protocol]
-Set the binding of @var{var} local to @var{protocol} to @var{val}.
-If omitted @var{protocol} defaults to the current value of @code{eudc-protocol}.
-The current binding of @var{var} is changed only if @var{protocol} is
-omitted.
+@defun eudc-protocol-set var val &optional protocol
+Set the binding of @var{var} local to @var{protocol} to @var{val}.  If
+omitted, @var{protocol} defaults to the current value of
+@code{eudc-protocol}.  The current binding of @var{var} is changed only
+if @var{protocol} is omitted.
 @end defun
 
-@defun eudc-server-set var val [server]
-Set the binding of @var{var} local to @var{server} to @var{val}.
-If omitted @var{server} defaults to the current value of @code{eudc-server}.
-The current binding of @var{var} is changed only if @var{server} is
-omitted.
+@defun eudc-server-set var val &optional server
+Set the binding of @var{var} local to @var{server} to @var{val}.  If
+omitted, @var{server} defaults to the current value of
+@code{eudc-server}.  The current binding of @var{var} is changed only if
+@var{server} is omitted.
 @end defun
 
 @defun eudc-set var val
-Set the most local (server, protocol or default) binding of @var{var} to @var{val}.
-The current binding of @var{var} is also set to @var{val}.
+Set the most local (server, protocol or default) binding of @var{var} to
+@var{val}.  The current binding of @var{var} is also set to @var{val}.
 @end defun
 
 The following variables allow you to query the various bindings of a
 Return @code{unbound} if @var{var} has no EUDC default value.
 @end defun
 
-@defun eudc-variable-protocol-value var [protocol]
-Return the value of @var{var} local to @var{protocol}.
-Return `unbound' if @var{var} has no value local to @var{protocol}.
+@defun eudc-variable-protocol-value var &optional protocol
+Return the value of @var{var} local to @var{protocol}.  Return
+@code{unbound} if @var{var} has no value local to @var{protocol}.
 @var{protocol} defaults to @code{eudc-protocol}.
 @end defun
 
-@defun eudc-variable-server-value var [server]
-Return the value of @var{var} local to @var{server}.  
-Return `unbound' if @var{var} has no value local to @var{server}.
+@defun eudc-variable-server-value var &optional server
+Return the value of @var{var} local to @var{server}.  Return
+@code{unbound} if @var{var} has no value local to @var{server}.
 @var{server} defaults to @code{eudc-server}.
 @end defun
 
 
-Changing a protocol or server local value of a variable has no effect on
-its current value.  The following command is used to synchronize the
-current values of variables with their local values given the current
-@code{eudc-server} and @code{eudc-protocol}:
+Changing a protocol-local or server-local value of a variable has no
+effect on its current value.  The following command is used to
+synchronize the current values of variables with their local values
+given the current @code{eudc-server} and @code{eudc-protocol}:
 
 @defun eudc-update-local-variables
 Update all EUDC variables according to their local settings.
 @comment  node-name,  next,  previous,  up
 @chapter Credits
 
-EUDC was written by Oscar Figueiredo based on @code{ph.el} by the 
+EUDC was written by Oscar Figueiredo based on @file{ph.el} by the 
 same author.
 
 Thanks to Soren Dayton for his suggestions, his enthusiasm and his help
-in testing and proofreading the code and docs of @code{ph.el}.
+in testing and proofreading the code and docs of @file{ph.el}.
 
 @node Variables Index,  , Credits, Top
 @comment  node-name,  next,  previous,  up
 ;;    This library provides an interface to use BBDB as a backend of 
 ;;    the Emacs Unified Directory Client.
 
-;;; Installation:
-;;    Install EUDC first. See EUDC documentation.
-
-;;    This library runs under XEmacs 20 and under Emacs 19.34 and above
-
-;;; Usage:
-
 ;;; Code:
 
 (require 'eudc)
-(if (not (featurep 'bbdb))
-    (load-library "bbdb"))
-(if (not (featurep 'bbdb-com))
-    (load-library "bbdb-com"))
+(require 'bbdb)
+(require 'bbdb-com)
 
 ;;{{{      Internal cooking
 
 		   'ldap)
 
 (defun eudc-ldap-cleanup-record-simple (record)
-  "Do some cleanup in a record to make it suitable for EUDC."
+  "Do some cleanup in a RECORD to make it suitable for EUDC."
   (mapcar 
    (function 
     (lambda (field)
 	     eudc-server nil t))))
 
 (defun eudc-ldap-escape-query-special-chars (string)
-  "Escape characters forbidden in LDAP queries"
+  "Value is STRING with characters forbidden in LDAP queries escaped."
 ;; Note that * should also be escaped but in most situations I suppose 
 ;; the user doesn't want this
   (eudc-replace-in-string
 ;;    This library provides specific CCSO PH/QI protocol support for the 
 ;;    Emacs Unified Directory Client package
 
-;;; Installation:
-;;    Install EUDC first. See EUDC documentation.
-
 ;;; Code:
 
 (require 'eudc)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.