From 0a45afa30fae6543fd21f3102ae259f02c1b9042 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Sun, 6 Dec 2015 19:33:24 -0500 Subject: Make eudcb-ph.el obsolete * doc/misc/eudc.texi: Bump version to 1.40.0. Remove PH/QI sections and mentions. * lisp/obsolete/eudcb-ph.el: Make obsolete. * lisp/net/eudc-vars.el (eudc-known-protocols): Remove ph. (eudc-ph-bbdb-conversion-alist): Make obsolete. * etc/NEWS: Mention this. (Bug#21191) --- doc/misc/eudc.texi | 92 +++-------------- etc/NEWS | 2 + lisp/net/eudc-vars.el | 6 +- lisp/net/eudcb-ph.el | 244 ---------------------------------------------- lisp/obsolete/eudcb-ph.el | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 265 insertions(+), 323 deletions(-) delete mode 100644 lisp/net/eudcb-ph.el create mode 100644 lisp/obsolete/eudcb-ph.el diff --git a/doc/misc/eudc.texi b/doc/misc/eudc.texi index 33c9a0eb3a..8d59e97b44 100644 --- a/doc/misc/eudc.texi +++ b/doc/misc/eudc.texi @@ -9,11 +9,10 @@ @c %**end of header @copying -This file documents EUDC v1.30b. +This file documents EUDC version 1.40.0. 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) +directory servers and contact information. Copyright @copyright{} 1998, 2000--2015 Free Software Foundation, Inc. @@ -32,7 +31,7 @@ modify this GNU manual.'' @dircategory Emacs network features @direntry -* EUDC: (eudc). Emacs client for directory servers (LDAP, PH). +* EUDC: (eudc). Emacs client for directory servers (LDAP, BBDB). @end direntry @footnotestyle end @@ -41,7 +40,7 @@ modify this GNU manual.'' @title EUDC Manual @subtitle The Emacs Unified Directory Client @author by Oscar Figueiredo -@code{1.30b} +@code{1.40.0} @page @vskip 0pt plus 1fill @@ -83,8 +82,6 @@ Currently supported back-ends are: @item LDAP, Lightweight Directory Access Protocol @item -CCSO PH/QI -@item BBDB, Big Brother's Insidious Database @end itemize @@ -109,7 +106,6 @@ Interface to BBDB to let you insert server records into your own BBDB database @menu * LDAP:: What is LDAP ? -* CCSO PH/QI:: What is CCSO, PH, QI ? * BBDB:: What is BBDB ? @end menu @@ -141,30 +137,6 @@ EUDC requires external support to access LDAP directory servers (@pxref{LDAP Configuration}) -@node CCSO PH/QI -@section CCSO PH/QI - -The Central Computing Services Office (CCSO) of the University of -Illinois at Urbana Champaign created and freely distributed a -directory system that was used by many organizations in the 1990s. -The system records information about people such as their address, -phone number, email, academic information or any other details it was -configured to. Nowadays this system is not widely used. - -The system consists of two parts: a database server traditionally called -@samp{qi} and a command-line client called @samp{ph}. -@ignore -Until 2010, the code could be downloaded from -@url{http://www-dev.cites.uiuc.edu/ph/}. -@end ignore - -The original command-line @samp{ph} client that came with the -@samp{ph/qi} distribution provided additional features that are -not implemented in EUDC, like the possibility to communicate with the -server in login-mode, which made it possible to change records in the -database. - - @node BBDB @section BBDB @@ -175,14 +147,14 @@ and news readers. It is often used as an enhanced email address book. -EUDC considers BBDB as a directory server back end 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 +EUDC considers BBDB as a directory server back end just like LDAP, +though BBDB has no client/server protocol and thus always 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 when -performing queries on multiple servers. +more flexible ways to do that), but rather to offer an interface to +your local directory that is consistent with the interface to external +LDAP directories. 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}) @@ -473,7 +445,7 @@ it will be ignored anyway. @defvar eudc-protocol The directory protocol to use to query the server. Currently supported -protocols in this version of EUDC are @code{ph}, @code{ldap} and @code{bbdb}. +protocols in this version of EUDC are @code{ldap} and @code{bbdb}. @end defvar @deffn Command eudc-set-server @@ -510,11 +482,8 @@ attributes are ignored. Default is @code{t}. Directory standards may authorize different instances of the same attribute in a record. For instance the record of a person may contain -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 duplicated. +several email fields containing different email addresses, in which +case EUDC will consider the attribute duplicated. EUDC has several methods to deal with duplicated attributes. The available methods are: @@ -956,39 +925,6 @@ convenience functions to parse phones and addresses. @end table @end defvar -The default value of the PH-specific value of that variable is -@code{eudc-ph-bbdb-conversion-alist}: - -@lisp -((name . name) - (net . email) - (address . (eudc-bbdbify-address address "Address")) - (phone . ((eudc-bbdbify-phone phone "Phone") - (eudc-bbdbify-phone office_phone "Office Phone")))) -@end lisp - -This means that: - -@itemize @bullet -@item -the @code{name} field of the BBDB record gets its value -from the @code{name} attribute of the directory record -@item -the @code{net} field of the BBDB record gets its value -from the @code{email} attribute of the directory record -@item -the @code{address} field of the BBDB record is obtained by parsing the -@code{address} attribute of the directory record with the function -@code{eudc-bbdbify-address} -@item -two @code{phone} fields are created (when possible) in the BBDB record. -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 @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 - @defun eudc-bbdbify-phone phone location This is a convenience function provided for use in @code{eudc-bbdb-conversion-alist}. It parses @var{phone} into a vector diff --git a/etc/NEWS b/etc/NEWS index 4e81c89388..4bcf32658c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -845,6 +845,8 @@ command line's password prompt. EUDC's BBDB backend now supports BBDB 3. +EUDC's PH backend (eudcb-ph.el) is obsolete. + ** Eshell +++ diff --git a/lisp/net/eudc-vars.el b/lisp/net/eudc-vars.el index a08d175fd6..de7e25a66a 100644 --- a/lisp/net/eudc-vars.el +++ b/lisp/net/eudc-vars.el @@ -50,7 +50,7 @@ instead." ;; Known protocols (used in completion) ;; Not to be mistaken with `eudc-supported-protocols' -(defvar eudc-known-protocols '(bbdb ph ldap)) +(defvar eudc-known-protocols '(bbdb ldap)) (defcustom eudc-server-hotlist nil "Directory servers to query. @@ -357,6 +357,10 @@ BBDB fields. SPECs are sexps which are evaluated: (symbol :tag "BBDB Field") (sexp :tag "Conversion Spec")))) +(make-obsolete-variable 'eudc-ph-bbdb-conversion-alist + "the EUDC PH/QI backend is obsolete." + "25.1") + ;;}}} ;;{{{ LDAP Custom Group diff --git a/lisp/net/eudcb-ph.el b/lisp/net/eudcb-ph.el deleted file mode 100644 index f144bf695f..0000000000 --- a/lisp/net/eudcb-ph.el +++ /dev/null @@ -1,244 +0,0 @@ -;;; eudcb-ph.el --- Emacs Unified Directory Client - CCSO PH/QI Backend - -;; Copyright (C) 1998-2015 Free Software Foundation, Inc. - -;; Author: Oscar Figueiredo -;; Pavel Janík -;; Maintainer: Thomas Fitzsimmons -;; Keywords: comm -;; Package: eudc - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This library provides specific CCSO PH/QI protocol support for the -;; Emacs Unified Directory Client package. - -;;; Code: - -(require 'eudc) - -;;{{{ Internal cooking - -(eudc-protocol-set 'eudc-bbdb-conversion-alist 'eudc-ph-bbdb-conversion-alist 'ph) -(eudc-protocol-set 'eudc-query-function 'eudc-ph-query-internal 'ph) -(eudc-protocol-set 'eudc-list-attributes-function 'eudc-ph-get-field-list 'ph) -(eudc-protocol-set 'eudc-protocol-has-default-query-attributes t 'ph) - -(defvar eudc-ph-process-buffer nil) -(defvar eudc-ph-read-point) - -(defconst eudc-ph-default-server-port 105 - "Default TCP port for CCSO PH/QI directory services.") - -(defun eudc-ph-query-internal (query &optional return-fields) - "Query the PH/QI server with QUERY. -QUERY can be a string NAME or a list made of strings NAME -and/or cons cells (KEY . VALUE) where KEYs should be valid -CCSO database keys. NAME is equivalent to (DEFAULT . NAME), -where DEFAULT is the default key of the database. -RETURN-FIELDS is a list of database fields to return, -defaulting to `eudc-default-return-attributes'." - (let (request) - (if (null return-fields) - (setq return-fields eudc-default-return-attributes)) - (if (eq 'all return-fields) - (setq return-fields '(all))) - (setq request - (concat "query " - (if (stringp query) - query - (mapconcat (function (lambda (elt) - (if (stringp elt) elt) - (format "%s=%s" (car elt) (cdr elt)))) - query - " ")) - (if return-fields - (concat " return " (mapconcat 'symbol-name return-fields " "))))) - (and (> (length request) 6) - (eudc-ph-do-request request) - (eudc-ph-parse-query-result return-fields)))) - -(defun eudc-ph-get-field-list (full-records) - "Return a list of valid field names for the current server. -If FULL-RECORDS is non-nil, full records including field description -are returned" - (interactive) - (eudc-ph-do-request "fields") - (if full-records - (eudc-ph-parse-query-result) - (mapcar #'caar (eudc-ph-parse-query-result)))) - -(defun eudc-ph-parse-query-result (&optional fields) - "Return a list of alists of key/values from in `eudc-ph-process-buffer'. -Fields not in FIELDS are discarded." - (let (record - records - line-regexp - current-key - key - value - ignore) - (save-excursion - (message "Parsing results...") - (set-buffer eudc-ph-process-buffer) - (goto-char (point-min)) - (while (re-search-forward "^\\(-[0-9]+\\):\\([0-9]+\\):" nil t) - (catch 'ignore - (setq line-regexp (concat "^\\(-[0-9]+\\):" (match-string 2) ":[ \t]*\\([-a-zA-Z_]*\\)?:[ \t]*\\(.*\\)$")) - (beginning-of-line) - (setq record nil - ignore nil - current-key nil) - (while (re-search-forward line-regexp nil t) - (catch 'skip-line - (if (string= "-508" (match-string 1)) - ;; A field is missing in this entry. Skip it or skip the - ;; whole record (see `eudc-strict-return-matches') - (if (not eudc-strict-return-matches) - (throw 'skip-line t) - (while (re-search-forward line-regexp nil t)) - (setq ignore t) - (throw 'ignore t))) - (setq key (and (not (string= (match-string 2) "")) - (intern (match-string 2))) - value (match-string 3)) - (if (and current-key - (eq key current-key)) - (setq key nil) - (setq current-key key)) - (if (or (null fields) - (eq 'all fields) - (memq current-key fields)) - (if key - (setq record (cons (cons key value) record)) ; New key - (setcdr (car record) (if (listp (cdar record)) - (append (cdar record) (list value)) - (list (cdar record) value)))))))) - (and (not ignore) - (or (null fields) - (eq 'all fields) - (setq record (nreverse record))) - (setq record (if (not (eq 'list eudc-duplicate-attribute-handling-method)) - (eudc-filter-duplicate-attributes record) - (list record))) - (setq records (append record records))))) - (message "Done") - records)) - -(defun eudc-ph-do-request (request) - "Send REQUEST to the server. -Wait for response and return the buffer containing it." - (let (process - buffer) - (unwind-protect - (progn - (message "Contacting server...") - (setq process (eudc-ph-open-session)) - (if process - (with-current-buffer (setq buffer (process-buffer process)) - (eudc-ph-send-command process request) - (message "Request sent, waiting for reply...") - (eudc-ph-read-response process)))) - (if process - (eudc-ph-close-session process))) - buffer)) - -(defun eudc-ph-open-session (&optional server) - "Open a connection to the given CCSO/QI SERVER. -SERVER is either a string naming the server or a list (NAME PORT)." - (let (process - host - port) - (catch 'done - (if (null server) - (setq server (or eudc-server - (call-interactively 'eudc-ph-set-server)))) - (string-match "\\(.*\\)\\(:\\(.*\\)\\)?" server) - (setq host (match-string 1 server)) - (setq port (or (match-string 3 server) - eudc-ph-default-server-port)) - (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" host))) - (with-current-buffer eudc-ph-process-buffer - (erase-buffer) - (setq eudc-ph-read-point (point)) - (and (featurep 'xemacs) (featurep 'mule) - (set-buffer-file-coding-system 'binary t))) - (setq process (open-network-stream "ph" eudc-ph-process-buffer host port)) - (if (null process) - (throw 'done nil)) - (set-process-query-on-exit-flag process t) - process))) - -(defun eudc-ph-close-session (process) - (with-current-buffer (process-buffer process) - (eudc-ph-send-command process "quit") - (eudc-ph-read-response process) - (run-at-time 2 nil 'delete-process process))) - -(defun eudc-ph-send-command (process command) - (goto-char (point-max)) - (process-send-string process command) - (process-send-string process "\r\n") - ) - -(defun eudc-ph-read-response (process &optional return-response) - "Read a response from the PH/QI query process PROCESS. -Returns nil if response starts with an error code. If the -response is successful the return code or the response itself is returned -depending on RETURN-RESPONSE." - (let ((case-fold-search nil) - return-code - match-end) - (goto-char eudc-ph-read-point) - ;; CCSO protocol : response complete if status >= 200 - (while (not (re-search-forward "^\\(^[2-5].*\\):.*\n" nil t)) - (accept-process-output process) - (goto-char eudc-ph-read-point)) - (setq match-end (point)) - (goto-char eudc-ph-read-point) - (if (and (setq return-code (match-string 1)) - (setq return-code (string-to-number return-code)) - (>= (abs return-code) 300)) - (progn (setq eudc-ph-read-point match-end) nil) - (setq eudc-ph-read-point match-end) - (if return-response - (buffer-substring (point) match-end) - return-code)))) - -;;}}} - -;;{{{ High-level interfaces (interactive functions) - -(defun eudc-ph-customize () - "Customize the EUDC PH support." - (interactive) - (customize-group 'eudc-ph)) - -(defun eudc-ph-set-server (server) - "Set the PH server to SERVER." - (interactive "sNew PH/QI Server: ") - (message "Selected PH/QI server is now %s" server) - (eudc-set-server server 'ph)) - -;;}}} - -(eudc-register-protocol 'ph) - -(provide 'eudcb-ph) - -;;; eudcb-ph.el ends here diff --git a/lisp/obsolete/eudcb-ph.el b/lisp/obsolete/eudcb-ph.el new file mode 100644 index 0000000000..f144bf695f --- /dev/null +++ b/lisp/obsolete/eudcb-ph.el @@ -0,0 +1,244 @@ +;;; eudcb-ph.el --- Emacs Unified Directory Client - CCSO PH/QI Backend + +;; Copyright (C) 1998-2015 Free Software Foundation, Inc. + +;; Author: Oscar Figueiredo +;; Pavel Janík +;; Maintainer: Thomas Fitzsimmons +;; Keywords: comm +;; Package: eudc + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This library provides specific CCSO PH/QI protocol support for the +;; Emacs Unified Directory Client package. + +;;; Code: + +(require 'eudc) + +;;{{{ Internal cooking + +(eudc-protocol-set 'eudc-bbdb-conversion-alist 'eudc-ph-bbdb-conversion-alist 'ph) +(eudc-protocol-set 'eudc-query-function 'eudc-ph-query-internal 'ph) +(eudc-protocol-set 'eudc-list-attributes-function 'eudc-ph-get-field-list 'ph) +(eudc-protocol-set 'eudc-protocol-has-default-query-attributes t 'ph) + +(defvar eudc-ph-process-buffer nil) +(defvar eudc-ph-read-point) + +(defconst eudc-ph-default-server-port 105 + "Default TCP port for CCSO PH/QI directory services.") + +(defun eudc-ph-query-internal (query &optional return-fields) + "Query the PH/QI server with QUERY. +QUERY can be a string NAME or a list made of strings NAME +and/or cons cells (KEY . VALUE) where KEYs should be valid +CCSO database keys. NAME is equivalent to (DEFAULT . NAME), +where DEFAULT is the default key of the database. +RETURN-FIELDS is a list of database fields to return, +defaulting to `eudc-default-return-attributes'." + (let (request) + (if (null return-fields) + (setq return-fields eudc-default-return-attributes)) + (if (eq 'all return-fields) + (setq return-fields '(all))) + (setq request + (concat "query " + (if (stringp query) + query + (mapconcat (function (lambda (elt) + (if (stringp elt) elt) + (format "%s=%s" (car elt) (cdr elt)))) + query + " ")) + (if return-fields + (concat " return " (mapconcat 'symbol-name return-fields " "))))) + (and (> (length request) 6) + (eudc-ph-do-request request) + (eudc-ph-parse-query-result return-fields)))) + +(defun eudc-ph-get-field-list (full-records) + "Return a list of valid field names for the current server. +If FULL-RECORDS is non-nil, full records including field description +are returned" + (interactive) + (eudc-ph-do-request "fields") + (if full-records + (eudc-ph-parse-query-result) + (mapcar #'caar (eudc-ph-parse-query-result)))) + +(defun eudc-ph-parse-query-result (&optional fields) + "Return a list of alists of key/values from in `eudc-ph-process-buffer'. +Fields not in FIELDS are discarded." + (let (record + records + line-regexp + current-key + key + value + ignore) + (save-excursion + (message "Parsing results...") + (set-buffer eudc-ph-process-buffer) + (goto-char (point-min)) + (while (re-search-forward "^\\(-[0-9]+\\):\\([0-9]+\\):" nil t) + (catch 'ignore + (setq line-regexp (concat "^\\(-[0-9]+\\):" (match-string 2) ":[ \t]*\\([-a-zA-Z_]*\\)?:[ \t]*\\(.*\\)$")) + (beginning-of-line) + (setq record nil + ignore nil + current-key nil) + (while (re-search-forward line-regexp nil t) + (catch 'skip-line + (if (string= "-508" (match-string 1)) + ;; A field is missing in this entry. Skip it or skip the + ;; whole record (see `eudc-strict-return-matches') + (if (not eudc-strict-return-matches) + (throw 'skip-line t) + (while (re-search-forward line-regexp nil t)) + (setq ignore t) + (throw 'ignore t))) + (setq key (and (not (string= (match-string 2) "")) + (intern (match-string 2))) + value (match-string 3)) + (if (and current-key + (eq key current-key)) + (setq key nil) + (setq current-key key)) + (if (or (null fields) + (eq 'all fields) + (memq current-key fields)) + (if key + (setq record (cons (cons key value) record)) ; New key + (setcdr (car record) (if (listp (cdar record)) + (append (cdar record) (list value)) + (list (cdar record) value)))))))) + (and (not ignore) + (or (null fields) + (eq 'all fields) + (setq record (nreverse record))) + (setq record (if (not (eq 'list eudc-duplicate-attribute-handling-method)) + (eudc-filter-duplicate-attributes record) + (list record))) + (setq records (append record records))))) + (message "Done") + records)) + +(defun eudc-ph-do-request (request) + "Send REQUEST to the server. +Wait for response and return the buffer containing it." + (let (process + buffer) + (unwind-protect + (progn + (message "Contacting server...") + (setq process (eudc-ph-open-session)) + (if process + (with-current-buffer (setq buffer (process-buffer process)) + (eudc-ph-send-command process request) + (message "Request sent, waiting for reply...") + (eudc-ph-read-response process)))) + (if process + (eudc-ph-close-session process))) + buffer)) + +(defun eudc-ph-open-session (&optional server) + "Open a connection to the given CCSO/QI SERVER. +SERVER is either a string naming the server or a list (NAME PORT)." + (let (process + host + port) + (catch 'done + (if (null server) + (setq server (or eudc-server + (call-interactively 'eudc-ph-set-server)))) + (string-match "\\(.*\\)\\(:\\(.*\\)\\)?" server) + (setq host (match-string 1 server)) + (setq port (or (match-string 3 server) + eudc-ph-default-server-port)) + (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" host))) + (with-current-buffer eudc-ph-process-buffer + (erase-buffer) + (setq eudc-ph-read-point (point)) + (and (featurep 'xemacs) (featurep 'mule) + (set-buffer-file-coding-system 'binary t))) + (setq process (open-network-stream "ph" eudc-ph-process-buffer host port)) + (if (null process) + (throw 'done nil)) + (set-process-query-on-exit-flag process t) + process))) + +(defun eudc-ph-close-session (process) + (with-current-buffer (process-buffer process) + (eudc-ph-send-command process "quit") + (eudc-ph-read-response process) + (run-at-time 2 nil 'delete-process process))) + +(defun eudc-ph-send-command (process command) + (goto-char (point-max)) + (process-send-string process command) + (process-send-string process "\r\n") + ) + +(defun eudc-ph-read-response (process &optional return-response) + "Read a response from the PH/QI query process PROCESS. +Returns nil if response starts with an error code. If the +response is successful the return code or the response itself is returned +depending on RETURN-RESPONSE." + (let ((case-fold-search nil) + return-code + match-end) + (goto-char eudc-ph-read-point) + ;; CCSO protocol : response complete if status >= 200 + (while (not (re-search-forward "^\\(^[2-5].*\\):.*\n" nil t)) + (accept-process-output process) + (goto-char eudc-ph-read-point)) + (setq match-end (point)) + (goto-char eudc-ph-read-point) + (if (and (setq return-code (match-string 1)) + (setq return-code (string-to-number return-code)) + (>= (abs return-code) 300)) + (progn (setq eudc-ph-read-point match-end) nil) + (setq eudc-ph-read-point match-end) + (if return-response + (buffer-substring (point) match-end) + return-code)))) + +;;}}} + +;;{{{ High-level interfaces (interactive functions) + +(defun eudc-ph-customize () + "Customize the EUDC PH support." + (interactive) + (customize-group 'eudc-ph)) + +(defun eudc-ph-set-server (server) + "Set the PH server to SERVER." + (interactive "sNew PH/QI Server: ") + (message "Selected PH/QI server is now %s" server) + (eudc-set-server server 'ph)) + +;;}}} + +(eudc-register-protocol 'ph) + +(provide 'eudcb-ph) + +;;; eudcb-ph.el ends here -- cgit v1.2.3