Merge from emacs--rel--22
[bpt/emacs.git] / lisp / net / eudcb-ph.el
1 ;;; eudcb-ph.el --- Emacs Unified Directory Client - CCSO PH/QI Backend
2
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
6 ;; Author: Oscar Figueiredo <oscar@cpe.fr>
7 ;; Maintainer: Pavel Janík <Pavel@Janik.cz>
8 ;; Keywords: comm
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;; This library provides specific CCSO PH/QI protocol support for the
30 ;; Emacs Unified Directory Client package.
31
32 ;;; Code:
33
34 (require 'eudc)
35
36 ;;{{{ Internal cooking
37
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)
42
43 (defvar eudc-ph-process-buffer nil)
44 (defvar eudc-ph-read-point)
45
46 (defconst eudc-ph-default-server-port 105
47 "Default TCP port for CCSO PH/QI directory services.")
48
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'."
57 (let (request)
58 (if (null return-fields)
59 (setq return-fields eudc-default-return-attributes))
60 (if (eq 'all return-fields)
61 (setq return-fields '(all)))
62 (setq request
63 (concat "query "
64 (if (stringp query)
65 query
66 (mapconcat (function (lambda (elt)
67 (if (stringp elt) elt)
68 (format "%s=%s" (car elt) (cdr elt))))
69 query
70 " "))
71 (if return-fields
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))))
76
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
80 are returned"
81 (interactive)
82 (eudc-ph-do-request "fields")
83 (if full-records
84 (eudc-ph-parse-query-result)
85 (mapcar 'eudc-caar (eudc-ph-parse-query-result))))
86
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."
90 (let (record
91 records
92 line-regexp
93 current-key
94 key
95 value
96 ignore)
97 (save-excursion
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)
102 (catch 'ignore
103 (setq line-regexp (concat "^\\(-[0-9]+\\):" (match-string 2) ":[ \t]*\\([-a-zA-Z_]*\\)?:[ \t]*\\(.*\\)$"))
104 (beginning-of-line)
105 (setq record nil
106 ignore nil
107 current-key nil)
108 (while (re-search-forward line-regexp nil t)
109 (catch 'skip-line
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)
114 (throw 'skip-line t)
115 (while (re-search-forward line-regexp nil t))
116 (setq ignore t)
117 (throw 'ignore t)))
118 (setq key (and (not (string= (match-string 2) ""))
119 (intern (match-string 2)))
120 value (match-string 3))
121 (if (and current-key
122 (eq key current-key))
123 (setq key nil)
124 (setq current-key key))
125 (if (or (null fields)
126 (eq 'all fields)
127 (memq current-key fields))
128 (if key
129 (setq record (cons (cons key value) record)) ; New key
130 (setcdr (car record) (if (listp (eudc-cdar record))
131 (append (eudc-cdar record) (list value))
132 (list (eudc-cdar record) value))))))))
133 (and (not ignore)
134 (or (null fields)
135 (eq 'all fields)
136 (setq record (nreverse record)))
137 (setq record (if (not (eq 'list eudc-duplicate-attribute-handling-method))
138 (eudc-filter-duplicate-attributes record)
139 (list record)))
140 (setq records (append record records)))))
141 (message "Done")
142 records))
143
144 (defun eudc-ph-do-request (request)
145 "Send REQUEST to the server.
146 Wait for response and return the buffer containing it."
147 (let (process
148 buffer)
149 (unwind-protect
150 (progn
151 (message "Contacting server...")
152 (setq process (eudc-ph-open-session))
153 (if process
154 (save-excursion
155 (set-buffer (setq buffer (process-buffer process)))
156 (eudc-ph-send-command process request)
157 (message "Request sent, waiting for reply...")
158 (eudc-ph-read-response process))))
159 (if process
160 (eudc-ph-close-session process)))
161 buffer))
162
163 (defun eudc-ph-open-session (&optional server)
164 "Open a connection to the given CCSO/QI SERVER.
165 SERVER is either a string naming the server or a list (NAME PORT)."
166 (let (process
167 host
168 port)
169 (catch 'done
170 (if (null server)
171 (setq server (or eudc-server
172 (call-interactively 'eudc-ph-set-server))))
173 (string-match "\\(.*\\)\\(:\\(.*\\)\\)?" server)
174 (setq host (match-string 1 server))
175 (setq port (or (match-string 3 server)
176 eudc-ph-default-server-port))
177 (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" host)))
178 (save-excursion
179 (set-buffer eudc-ph-process-buffer)
180 (erase-buffer)
181 (setq eudc-ph-read-point (point))
182 (and (featurep 'xemacs) (featurep 'mule)
183 (set-buffer-file-coding-system 'binary t)))
184 (setq process (open-network-stream "ph" eudc-ph-process-buffer host port))
185 (if (null process)
186 (throw 'done nil))
187 (set-process-query-on-exit-flag process t)
188 process)))
189
190 (defun eudc-ph-close-session (process)
191 (save-excursion
192 (set-buffer (process-buffer process))
193 (eudc-ph-send-command process "quit")
194 (eudc-ph-read-response process)
195 (run-at-time 2 nil 'delete-process process)))
196
197 (defun eudc-ph-send-command (process command)
198 (goto-char (point-max))
199 (process-send-string process command)
200 (process-send-string process "\r\n")
201 )
202
203 (defun eudc-ph-read-response (process &optional return-response)
204 "Read a response from the PH/QI query process PROCESS.
205 Returns nil if response starts with an error code. If the
206 response is successful the return code or the response itself is returned
207 depending on RETURN-RESPONSE."
208 (let ((case-fold-search nil)
209 return-code
210 match-end)
211 (goto-char eudc-ph-read-point)
212 ;; CCSO protocol : response complete if status >= 200
213 (while (not (re-search-forward "^\\(^[2-5].*\\):.*\n" nil t))
214 (accept-process-output process)
215 (goto-char eudc-ph-read-point))
216 (setq match-end (point))
217 (goto-char eudc-ph-read-point)
218 (if (and (setq return-code (match-string 1))
219 (setq return-code (string-to-number return-code))
220 (>= (abs return-code) 300))
221 (progn (setq eudc-ph-read-point match-end) nil)
222 (setq eudc-ph-read-point match-end)
223 (if return-response
224 (buffer-substring (point) match-end)
225 return-code))))
226
227 ;;}}}
228
229 ;;{{{ High-level interfaces (interactive functions)
230
231 (defun eudc-ph-customize ()
232 "Customize the EUDC PH support."
233 (interactive)
234 (customize-group 'eudc-ph))
235
236 (defun eudc-ph-set-server (server)
237 "Set the PH server to SERVER."
238 (interactive "sNew PH/QI Server: ")
239 (message "Selected PH/QI server is now %s" server)
240 (eudc-set-server server 'ph))
241
242 ;;}}}
243
244 (eudc-register-protocol 'ph)
245
246 (provide 'eudcb-ph)
247
248 ;;; arch-tag: 4365bbf5-af20-453e-b5b6-2e7118ebfcdb
249 ;;; eudcb-ph.el ends here