1 ;;; eudcb-ph.el --- Emacs Unified Directory Client - CCSO PH/QI Backend
3 ;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
5 ;; Author: Oscar Figueiredo <oscar@cpe.fr>
6 ;; Pavel JanÃk <Pavel@Janik.cz>
7 ;; Maintainer: Thomas Fitzsimmons <fitzsim@fitzsim.org>
10 ;; Obsolete-since: 25.1
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software: you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation, either version 3 of the License, or
17 ;; (at your option) any later version.
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
29 ;; This library provides specific CCSO PH/QI protocol support for the
30 ;; Emacs Unified Directory Client package.
36 ;;{{{ Internal cooking
38 (eudc-protocol-set 'eudc-bbdb-conversion-alist
'eudc-ph-bbdb-conversion-alist
'ph
)
39 (eudc-protocol-set 'eudc-query-function
'eudc-ph-query-internal
'ph
)
40 (eudc-protocol-set 'eudc-list-attributes-function
'eudc-ph-get-field-list
'ph
)
41 (eudc-protocol-set 'eudc-protocol-has-default-query-attributes t
'ph
)
43 (defvar eudc-ph-process-buffer nil
)
44 (defvar eudc-ph-read-point
)
46 (defconst eudc-ph-default-server-port
105
47 "Default TCP port for CCSO PH/QI directory services.")
49 (defun eudc-ph-query-internal (query &optional return-fields
)
50 "Query the PH/QI server with QUERY.
51 QUERY can be a string NAME or a list made of strings NAME
52 and/or cons cells (KEY . VALUE) where KEYs should be valid
53 CCSO database keys. NAME is equivalent to (DEFAULT . NAME),
54 where DEFAULT is the default key of the database.
55 RETURN-FIELDS is a list of database fields to return,
56 defaulting to `eudc-default-return-attributes'."
58 (if (null return-fields
)
59 (setq return-fields eudc-default-return-attributes
))
60 (if (eq 'all return-fields
)
61 (setq return-fields
'(all)))
66 (mapconcat (function (lambda (elt)
67 (if (stringp elt
) elt
)
68 (format "%s=%s" (car elt
) (cdr elt
))))
72 (concat " return " (mapconcat 'symbol-name return-fields
" ")))))
73 (and (> (length request
) 6)
74 (eudc-ph-do-request request
)
75 (eudc-ph-parse-query-result return-fields
))))
77 (defun eudc-ph-get-field-list (full-records)
78 "Return a list of valid field names for the current server.
79 If FULL-RECORDS is non-nil, full records including field description
82 (eudc-ph-do-request "fields")
84 (eudc-ph-parse-query-result)
85 (mapcar #'caar
(eudc-ph-parse-query-result))))
87 (defun eudc-ph-parse-query-result (&optional fields
)
88 "Return a list of alists of key/values from in `eudc-ph-process-buffer'.
89 Fields not in FIELDS are discarded."
98 (message "Parsing results...")
99 (set-buffer eudc-ph-process-buffer
)
100 (goto-char (point-min))
101 (while (re-search-forward "^\\(-[0-9]+\\):\\([0-9]+\\):" nil t
)
103 (setq line-regexp
(concat "^\\(-[0-9]+\\):" (match-string 2) ":[ \t]*\\([-a-zA-Z_]*\\)?:[ \t]*\\(.*\\)$"))
108 (while (re-search-forward line-regexp nil t
)
110 (if (string= "-508" (match-string 1))
111 ;; A field is missing in this entry. Skip it or skip the
112 ;; whole record (see `eudc-strict-return-matches')
113 (if (not eudc-strict-return-matches
)
115 (while (re-search-forward line-regexp nil t
))
118 (setq key
(and (not (string= (match-string 2) ""))
119 (intern (match-string 2)))
120 value
(match-string 3))
122 (eq key current-key
))
124 (setq current-key key
))
125 (if (or (null fields
)
127 (memq current-key fields
))
129 (setq record
(cons (cons key value
) record
)) ; New key
130 (setcdr (car record
) (if (listp (cdar record
))
131 (append (cdar record
) (list value
))
132 (list (cdar record
) value
))))))))
136 (setq record
(nreverse record
)))
137 (setq record
(if (not (eq 'list eudc-duplicate-attribute-handling-method
))
138 (eudc-filter-duplicate-attributes record
)
140 (setq records
(append record records
)))))
144 (defun eudc-ph-do-request (request)
145 "Send REQUEST to the server.
146 Wait for response and return the buffer containing it."
151 (message "Contacting server...")
152 (setq process
(eudc-ph-open-session))
154 (with-current-buffer (setq buffer
(process-buffer process
))
155 (eudc-ph-send-command process request
)
156 (message "Request sent, waiting for reply...")
157 (eudc-ph-read-response process
))))
159 (eudc-ph-close-session process
)))
162 (defun eudc-ph-open-session (&optional server
)
163 "Open a connection to the given CCSO/QI SERVER.
164 SERVER is either a string naming the server or a list (NAME PORT)."
170 (setq server
(or eudc-server
171 (call-interactively 'eudc-ph-set-server
))))
172 (string-match "\\(.*\\)\\(:\\(.*\\)\\)?" server
)
173 (setq host
(match-string 1 server
))
174 (setq port
(or (match-string 3 server
)
175 eudc-ph-default-server-port
))
176 (setq eudc-ph-process-buffer
(get-buffer-create (format " *PH-%s*" host
)))
177 (with-current-buffer eudc-ph-process-buffer
179 (setq eudc-ph-read-point
(point))
180 (and (featurep 'xemacs
) (featurep 'mule
)
181 (set-buffer-file-coding-system 'binary t
)))
182 (setq process
(open-network-stream "ph" eudc-ph-process-buffer host port
))
185 (set-process-query-on-exit-flag process t
)
188 (defun eudc-ph-close-session (process)
189 (with-current-buffer (process-buffer process
)
190 (eudc-ph-send-command process
"quit")
191 (eudc-ph-read-response process
)
192 (run-at-time 2 nil
'delete-process process
)))
194 (defun eudc-ph-send-command (process command
)
195 (goto-char (point-max))
196 (process-send-string process command
)
197 (process-send-string process
"\r\n")
200 (defun eudc-ph-read-response (process &optional return-response
)
201 "Read a response from the PH/QI query process PROCESS.
202 Returns nil if response starts with an error code. If the
203 response is successful the return code or the response itself is returned
204 depending on RETURN-RESPONSE."
205 (let ((case-fold-search nil
)
208 (goto-char eudc-ph-read-point
)
209 ;; CCSO protocol : response complete if status >= 200
210 (while (not (re-search-forward "^\\(^[2-5].*\\):.*\n" nil t
))
211 (accept-process-output process
)
212 (goto-char eudc-ph-read-point
))
213 (setq match-end
(point))
214 (goto-char eudc-ph-read-point
)
215 (if (and (setq return-code
(match-string 1))
216 (setq return-code
(string-to-number return-code
))
217 (>= (abs return-code
) 300))
218 (progn (setq eudc-ph-read-point match-end
) nil
)
219 (setq eudc-ph-read-point match-end
)
221 (buffer-substring (point) match-end
)
226 ;;{{{ High-level interfaces (interactive functions)
228 (defun eudc-ph-customize ()
229 "Customize the EUDC PH support."
231 (customize-group 'eudc-ph
))
233 (defun eudc-ph-set-server (server)
234 "Set the PH server to SERVER."
235 (interactive "sNew PH/QI Server: ")
236 (message "Selected PH/QI server is now %s" server
)
237 (eudc-set-server server
'ph
))
241 (eudc-register-protocol 'ph
)
245 ;;; eudcb-ph.el ends here