*** empty log message ***
[emacs.git] / lisp / net / eudcb-ph.el
blob5466aaa1493a4bc540d55e9e56c00ade536b26c1
1 ;;; eudcb-ph.el --- Emacs Unified Directory Client - CCSO PH/QI Backend
3 ;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
5 ;; Author: Oscar Figueiredo <oscar@xemacs.org>
6 ;; Maintainer: Oscar Figueiredo <oscar@xemacs.org>
7 ;; Keywords: help
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
26 ;;; Commentary:
27 ;; This library provides specific CCSO PH/QI protocol support for the
28 ;; Emacs Unified Directory Client package
30 ;;; Code:
32 (require 'eudc)
35 ;;{{{ Internal cooking
37 (eudc-protocol-set 'eudc-bbdb-conversion-alist 'eudc-ph-bbdb-conversion-alist 'ph)
38 (eudc-protocol-set 'eudc-query-function 'eudc-ph-query-internal 'ph)
39 (eudc-protocol-set 'eudc-list-attributes-function 'eudc-ph-get-field-list 'ph)
40 (eudc-protocol-set 'eudc-protocol-has-default-query-attributes t 'ph)
42 (defvar eudc-ph-process-buffer nil)
43 (defvar eudc-ph-read-point)
45 (defconst eudc-ph-default-server-port 105
46 "Default TCP port for CCSO PH/QI directory services.")
51 (defun eudc-ph-query-internal (query &optional return-fields)
52 "Query the PH/QI server with QUERY.
53 QUERY can be a string NAME or a list made of strings NAME
54 and/or cons cells (KEY . VALUE) where KEYs should be valid
55 CCSO database keys. NAME is equivalent to (DEFAULT . NAME),
56 where DEFAULT is the default key of the database.
57 RETURN-FIELDS is a list of database fields to return,
58 defaulting to `eudc-default-return-attributes'."
59 (let (request)
60 (if (null return-fields)
61 (setq return-fields eudc-default-return-attributes))
62 (if (eq 'all return-fields)
63 (setq return-fields '(all)))
64 (setq request
65 (concat "query "
66 (if (stringp query)
67 query
68 (mapconcat (function (lambda (elt)
69 (if (stringp elt) elt)
70 (format "%s=%s" (car elt) (cdr elt))))
71 query
72 " "))
73 (if return-fields
74 (concat " return " (mapconcat 'symbol-name return-fields " ")))))
75 (and (> (length request) 6)
76 (eudc-ph-do-request request)
77 (eudc-ph-parse-query-result return-fields))))
79 (defun eudc-ph-get-field-list (full-records)
80 "Return a list of valid field names for the current server.
81 If FULL-RECORDS is non-nil, full records including field description
82 are returned"
83 (interactive)
84 (eudc-ph-do-request "fields")
85 (if full-records
86 (eudc-ph-parse-query-result)
87 (mapcar 'eudc-caar (eudc-ph-parse-query-result))))
90 (defun eudc-ph-parse-query-result (&optional fields)
91 "Return a list of alists of key/values from in `eudc-ph-process-buffer'.
92 Fields not in FIELDS are discarded."
93 (let (record
94 records
95 line-regexp
96 current-key
97 key
98 value
99 ignore)
100 (save-excursion
101 (message "Parsing results...")
102 (set-buffer eudc-ph-process-buffer)
103 (goto-char (point-min))
104 (while (re-search-forward "^\\(-[0-9]+\\):\\([0-9]+\\):" nil t)
105 (catch 'ignore
106 (setq line-regexp (concat "^\\(-[0-9]+\\):" (match-string 2) ":[ \t]*\\([-a-zA-Z_]*\\)?:[ \t]*\\(.*\\)$"))
107 (beginning-of-line)
108 (setq record nil
109 ignore nil
110 current-key nil)
111 (while (re-search-forward line-regexp nil t)
112 (catch 'skip-line
113 (if (string= "-508" (match-string 1))
114 ;; A field is missing in this entry. Skip it or skip the
115 ;; whole record (see `eudc-strict-return-matches')
116 (if (not eudc-strict-return-matches)
117 (throw 'skip-line t)
118 (while (re-search-forward line-regexp nil t))
119 (setq ignore t)
120 (throw 'ignore t)))
121 (setq key (and (not (string= (match-string 2) ""))
122 (intern (match-string 2)))
123 value (match-string 3))
124 (if (and current-key
125 (eq key current-key))
126 (setq key nil)
127 (setq current-key key))
128 (if (or (null fields)
129 (eq 'all fields)
130 (memq current-key fields))
131 (if key
132 (setq record (cons (cons key value) record)) ; New key
133 (setcdr (car record) (if (listp (eudc-cdar record))
134 (append (eudc-cdar record) (list value))
135 (list (eudc-cdar record) value))))))))
136 (and (not ignore)
137 (or (null fields)
138 (eq 'all fields)
139 (setq record (nreverse record)))
140 (setq record (if (not (eq 'list eudc-duplicate-attribute-handling-method))
141 (eudc-filter-duplicate-attributes record)
142 (list record)))
143 (setq records (append record records))))
145 (message "Done")
146 records)
149 (defun eudc-ph-do-request (request)
150 "Send REQUEST to the server.
151 Wait for response and return the buffer containing it."
152 (let (process
153 buffer)
154 (unwind-protect
155 (progn
156 (message "Contacting server...")
157 (setq process (eudc-ph-open-session))
158 (if process
159 (save-excursion
160 (set-buffer (setq buffer (process-buffer process)))
161 (eudc-ph-send-command process request)
162 (message "Request sent, waiting for reply...")
163 (eudc-ph-read-response process))))
164 (if process
165 (eudc-ph-close-session process)))
166 buffer))
168 (defun eudc-ph-open-session (&optional server)
169 "Open a connection to the given CCSO/QI SERVER.
170 SERVER is either a string naming the server or a list (NAME PORT)."
171 (let (process
172 host
173 port)
174 (catch 'done
175 (if (null server)
176 (setq server (or eudc-server
177 (call-interactively 'eudc-ph-set-server))))
178 (string-match "\\(.*\\)\\(:\\(.*\\)\\)?" server)
179 (setq host (match-string 1 server))
180 (setq port (or (match-string 3 server)
181 eudc-ph-default-server-port))
182 (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" host)))
183 (save-excursion
184 (set-buffer eudc-ph-process-buffer)
185 (erase-buffer)
186 (setq eudc-ph-read-point (point))
187 (and eudc-xemacs-mule-p
188 (set-buffer-file-coding-system 'binary t)))
189 (setq process (open-network-stream "ph" eudc-ph-process-buffer host port))
190 (if (null process)
191 (throw 'done nil))
192 (process-kill-without-query process)
193 process)))
196 (defun eudc-ph-close-session (process)
197 (save-excursion
198 (set-buffer (process-buffer process))
199 (eudc-ph-send-command process "quit")
200 (eudc-ph-read-response process)
201 (if (fboundp 'add-async-timeout)
202 (add-async-timeout 10 'delete-process process)
203 (run-at-time 2 nil 'delete-process process))))
205 (defun eudc-ph-send-command (process command)
206 (goto-char (point-max))
207 (process-send-string process command)
208 (process-send-string process "\r\n")
211 (defun eudc-ph-read-response (process &optional return-response)
212 "Read a response from the PH/QI query process PROCESS.
213 Returns nil if response starts with an error code. If the
214 response is successful the return code or the response itself is returned
215 depending on RETURN-RESPONSE."
216 (let ((case-fold-search nil)
217 return-code
218 match-end)
219 (goto-char eudc-ph-read-point)
220 ;; CCSO protocol : response complete if status >= 200
221 (while (not (re-search-forward "^\\(^[2-5].*\\):.*\n" nil t))
222 (accept-process-output process)
223 (goto-char eudc-ph-read-point))
224 (setq match-end (point))
225 (goto-char eudc-ph-read-point)
226 (if (and (setq return-code (match-string 1))
227 (setq return-code (string-to-number return-code))
228 (>= (abs return-code) 300))
229 (progn (setq eudc-ph-read-point match-end) nil)
230 (setq eudc-ph-read-point match-end)
231 (if return-response
232 (buffer-substring (point) match-end)
233 return-code))))
235 ;;}}}
237 ;;{{{ High-level interfaces (interactive functions)
239 (defun eudc-ph-customize ()
240 "Customize the EUDC PH support."
241 (interactive)
242 (customize-group 'eudc-ph))
244 (defun eudc-ph-set-server (server)
245 "Set the PH server to SERVER."
246 (interactive "sNew PH/QI Server: ")
247 (message "Selected PH/QI server is now %s" server)
248 (eudc-set-server server 'ph))
250 ;;}}}
253 (eudc-register-protocol 'ph)
255 (provide 'eudcb-ph)
257 ;;; eudcb-ph.el ends here