bzr branch
/lh/emacsweblogs
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
1 |
;;; xml-rpc.el --- An elisp implementation of clientside XML-RPC
|
1
by Mark A. Hershberger
initial commit |
2 |
|
32
by Mark A. Hershberger
Apply Leo's patches |
3 |
;; Copyright (C) 2002-2010 Mark A. Hershberger
|
1
by Mark A. Hershberger
initial commit |
4 |
;; Copyright (C) 2001 CodeFactory AB.
|
5 |
;; Copyright (C) 2001 Daniel Lundin.
|
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
6 |
;; Copyright (C) 2006 Shun-ichi Goto
|
7 |
;; Modified for non-ASCII character handling.
|
|
8 |
||
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
9 |
;; Author: Mark A. Hershberger <mah@everybody.org>
|
10 |
;; Original Author: Daniel Lundin <daniel@codefactory.se>
|
|
29
by Mark A. Hershberger
Some minor housekeeping, bump xml-rpc.el version. |
11 |
;; Version: 1.6.8
|
1
by Mark A. Hershberger
initial commit |
12 |
;; Created: May 13 2001
|
13 |
;; Keywords: xml rpc network
|
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
14 |
;; URL: http://emacswiki.org/emacs/xml-rpc.el
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
15 |
;; Maintained-at: http://savannah.nongnu.org/bzr/?group=emacsweblogs
|
32
by Mark A. Hershberger
Apply Leo's patches |
16 |
;; Last Modified: <2010-02-25 17:07:43 mah>
|
29
by Mark A. Hershberger
Some minor housekeeping, bump xml-rpc.el version. |
17 |
|
18 |
(defconst xml-rpc-version "1.6.8" |
|
19 |
"Current version of xml-rpc.el") |
|
1
by Mark A. Hershberger
initial commit |
20 |
|
21 |
;; This file is NOT (yet) part of GNU Emacs.
|
|
22 |
||
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
23 |
;; This program is free software: you can redistribute it and/or modify
|
24 |
;; it under the terms of the GNU General Public License as published by
|
|
25 |
;; the Free Software Foundation, either version 3 of the License, or
|
|
26 |
;; (at your option) any later version.
|
|
1
by Mark A. Hershberger
initial commit |
27 |
|
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
28 |
;; This program is distributed in the hope that it will be useful,
|
1
by Mark A. Hershberger
initial commit |
29 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
30 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
31 |
;; GNU General Public License for more details.
|
|
1
by Mark A. Hershberger
initial commit |
32 |
|
33 |
;; You should have received a copy of the GNU General Public License
|
|
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
34 |
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
1
by Mark A. Hershberger
initial commit |
35 |
|
36 |
;;; Commentary:
|
|
37 |
||
38 |
;; This is an XML-RPC client implementation in elisp, capable of both
|
|
39 |
;; synchronous and asynchronous method calls (using the url package's async
|
|
40 |
;; retrieval functionality).
|
|
41 |
;; XML-RPC is remote procedure calls over HTTP using XML to describe the
|
|
42 |
;; function call and return values.
|
|
43 |
||
44 |
;; xml-rpc.el represents XML-RPC datatypes as lisp values, automatically
|
|
45 |
;; converting to and from the XML datastructures as needed, both for method
|
|
46 |
;; parameters and return values, making using XML-RPC methods fairly
|
|
47 |
;; transparent to the lisp code.
|
|
48 |
||
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
49 |
;;; Installation:
|
50 |
||
51 |
;; If you use ELPA (http://tromey.com/elpa), you can install via the
|
|
52 |
;; M-x package-list-packages interface. This is preferrable as you
|
|
53 |
;; will have access to updates automatically.
|
|
54 |
||
55 |
;; Otherwise, just make sure this file in your load-path (usually
|
|
56 |
;; ~/.emacs.d is included) and put (require 'xml-rpc) in your
|
|
57 |
;; ~/.emacs or ~/.emacs.d/init.el file.
|
|
58 |
||
59 |
;;; Requirements
|
|
1
by Mark A. Hershberger
initial commit |
60 |
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
61 |
;; xml-rpc.el uses the url package for http handling and xml.el for
|
62 |
;; XML parsing. url is a part of the W3 browser package. The url
|
|
63 |
;; package that is part of Emacs 22+ works great.
|
|
64 |
;;
|
|
1
by Mark A. Hershberger
initial commit |
65 |
;; xml.el is a part of GNU Emacs 21, but can also be downloaded from
|
66 |
;; here: <URL:ftp://ftp.codefactory.se/pub/people/daniel/elisp/xml.el>
|
|
67 |
||
30
by Mark A. Hershberger
update bug reporting function. |
68 |
;;; Bug reports
|
69 |
||
70 |
;; Please use M-x xml-rpc-submit-bug-report to report bugs.
|
|
1
by Mark A. Hershberger
initial commit |
71 |
|
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
72 |
;;; XML-RPC datatypes are represented as follows
|
1
by Mark A. Hershberger
initial commit |
73 |
|
74 |
;; int: 42
|
|
75 |
;; float/double: 42.0
|
|
76 |
;; string: "foo"
|
|
77 |
;; array: '(1 2 3 4) '(1 2 3 (4.1 4.2))
|
|
78 |
;; struct: '(("name" . "daniel") ("height" . 6.1))
|
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
79 |
;; dateTime: (:datetime (1234 124))
|
1
by Mark A. Hershberger
initial commit |
80 |
|
81 |
||
27
by Mark A. Hershberger
Update copyright to GPL 3, add installation instructions. |
82 |
;;; Examples
|
83 |
||
1
by Mark A. Hershberger
initial commit |
84 |
;; Here follows some examples demonstrating the use of xml-rpc.el
|
85 |
||
86 |
;; Normal synchronous operation
|
|
87 |
;; ----------------------------
|
|
88 |
||
89 |
;; (xml-rpc-method-call "http://localhost:80/RPC" 'foo-method foo bar zoo)
|
|
90 |
||
91 |
;; Asynchronous example (cb-foo will be called when the methods returns)
|
|
92 |
;; ---------------------------------------------------------------------
|
|
93 |
||
94 |
;; (defun cb-foo (foo)
|
|
95 |
;; (print (format "%s" foo)))
|
|
96 |
||
97 |
;; (xml-rpc-method-call-async 'cb-foo "http://localhost:80/RPC"
|
|
98 |
;; 'foo-method foo bar zoo)
|
|
99 |
||
100 |
||
101 |
;; Some real world working examples for fun and play
|
|
102 |
;; -------------------------------------------------
|
|
103 |
||
104 |
;; Check the temperature (celsius) outside jonas@codefactory.se's apartment
|
|
105 |
||
106 |
;; (xml-rpc-method-call
|
|
107 |
;; "http://flint.bengburken.net:80/xmlrpc/onewire_temp.php"
|
|
108 |
;; 'onewire.getTemp)
|
|
109 |
||
110 |
||
111 |
;; Fetch the latest NetBSD news the past 5 days from O'reillynet
|
|
112 |
||
113 |
;; (xml-rpc-method-call "http://www.oreillynet.com/meerkat/xml-rpc/server.php"
|
|
32
by Mark A. Hershberger
Apply Leo's patches |
114 |
;; 'meerkat.getItems
|
115 |
;; '(("channel" . 1024)
|
|
116 |
;; ("search" . "/NetBSD/")
|
|
117 |
;; ("time_period" . "5DAY")
|
|
118 |
;; ("ids" . 0)
|
|
119 |
;; ("descriptions" . 200)
|
|
120 |
;; ("categories" . 0)
|
|
121 |
;; ("channels" . 0)
|
|
122 |
;; ("dates" . 0)
|
|
123 |
;; ("num_items" . 5)))
|
|
1
by Mark A. Hershberger
initial commit |
124 |
|
125 |
||
126 |
;;; History:
|
|
127 |
||
29
by Mark A. Hershberger
Some minor housekeeping, bump xml-rpc.el version. |
128 |
;; 1.6.8 - Add a report-xml-rpc-bug function
|
129 |
||
130 |
;; 1.6.7 - Skipped version
|
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
131 |
|
21
by Mark A. Hershberger
2009-09-13 Mark A. Hershberger <mah@everybody.org> |
132 |
;; 1.6.6 - Use the correct dateTime elements. Fix bug in parsing null int.
|
133 |
||
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
134 |
;; 1.6.5.1 - Fix compile time warnings.
|
135 |
||
136 |
;; 1.6.5 - Made handling of dateTime elements more robust.
|
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
137 |
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
138 |
;; 1.6.4.1 - Updated to work with both Emacs22 and Emacs23.
|
139 |
||
140 |
;; 1.6.2.2 - Modified to allow non-ASCII string again.
|
|
141 |
;; It can handle non-ASCII page name and comment
|
|
142 |
;; on Emacs 21 also.
|
|
143 |
||
144 |
;; 1.6.2.1 - Modified to allow non-ASCII string.
|
|
145 |
;; If xml-rpc-allow-unicode-string is non-nil,
|
|
146 |
;; make 'value' object instead of 'base64' object.
|
|
147 |
;; This is good for WikiRPC.
|
|
148 |
||
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
149 |
;; 1.6.2 - Fix whitespace issues to work better with new xml.el
|
150 |
;; Fix bug in string handling.
|
|
151 |
;; Add support for gzip-encoding when needed.
|
|
152 |
||
153 |
;; 1.6.1 - base64 support added.
|
|
154 |
;; url-insert-entities-in-string done on string types now.
|
|
155 |
||
156 |
;; 1.6 - Fixed dependencies (remove w3, add cl).
|
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
157 |
;; Move string-to-boolean and boolean-to-string into xml-rpc
|
158 |
;; namespace.
|
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
159 |
;; Fix bug in xml-rpc-xml-to-response where non-existent var was.
|
160 |
;; More tweaking of "Connection: close" header.
|
|
161 |
;; Fix bug in xml-rpc-request-process-buffer so that this works with
|
|
162 |
;; different mixes of the url.el code.
|
|
163 |
||
164 |
;; 1.5.1 - Added Andrew J Cosgriff's patch to make the
|
|
165 |
;; xml-rpc-clean-string function work in XEmacs.
|
|
166 |
||
167 |
;; 1.5 - Added headers to the outgoing url-retreive-synchronously
|
|
168 |
;; so that it would close connections immediately on completion.
|
|
169 |
||
170 |
;; 1.4 - Added conditional debugging code. Added version tag.
|
|
171 |
||
172 |
;; 1.2 - Better error handling. The documentation didn't match
|
|
173 |
;; the code. That was changed so that an error was
|
|
174 |
;; signaled. Also, better handling of various and
|
|
175 |
;; different combinations of xml.el and url.el.
|
|
176 |
||
177 |
;; 1.1 - Added support for boolean types. If the type of a
|
|
178 |
;; returned value is not specified, string is assumed
|
|
179 |
||
180 |
;; 1.0 - First version
|
|
1
by Mark A. Hershberger
initial commit |
181 |
|
182 |
||
183 |
;;; Code:
|
|
184 |
||
185 |
(require 'xml) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
186 |
(require 'url-http) |
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
187 |
(require 'timezone) |
1
by Mark A. Hershberger
initial commit |
188 |
(eval-when-compile |
189 |
(require 'cl)) |
|
190 |
||
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
191 |
(defconst xml-rpc-maintainer-address "mah@everybody.org" |
192 |
"The address where bug reports should be sent.") |
|
193 |
||
1
by Mark A. Hershberger
initial commit |
194 |
(defcustom xml-rpc-load-hook nil |
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
195 |
"*Hook run after loading xml-rpc."
|
1
by Mark A. Hershberger
initial commit |
196 |
:type 'hook :group 'xml-rpc) |
197 |
||
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
198 |
(defcustom xml-rpc-use-coding-system |
199 |
(if (coding-system-p 'utf-8) 'utf-8 'iso-8859-1) |
|
200 |
"The coding system to use."
|
|
201 |
:type 'symbol :group 'xml-rpc) |
|
202 |
||
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
203 |
(defcustom xml-rpc-allow-unicode-string (coding-system-p 'utf-8) |
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
204 |
"If non-nil, non-ASCII data is composed as 'value' instead of 'base64'.
|
205 |
And this option overrides `xml-rpc-base64-encode-unicode' and |
|
206 |
`xml-rpc-base64-decode-unicode' if set as non-nil." |
|
207 |
:type 'boolean :group 'xml-rpc) |
|
208 |
||
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
209 |
(defcustom xml-rpc-base64-encode-unicode (coding-system-p 'utf-8) |
1
by Mark A. Hershberger
initial commit |
210 |
"If non-nil, then strings with non-ascii characters will be turned
|
211 |
into Base64."
|
|
212 |
:type 'boolean :group 'xml-rpc) |
|
213 |
||
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
214 |
(defcustom xml-rpc-base64-decode-unicode (coding-system-p 'utf-8) |
6
by Mark A. Hershberger
2007-12-27 Mark A. Hershberger <mah@everybody.org> |
215 |
"If non-nil, then base64 strings will be decoded using the
|
216 |
utf-8 coding system."
|
|
217 |
:type 'boolean :group 'xml-rpc) |
|
218 |
||
1
by Mark A. Hershberger
initial commit |
219 |
(defcustom xml-rpc-debug 0 |
220 |
"Set this to 1 or greater to avoid killing temporary buffers.
|
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
221 |
Set it higher to get some info in the *Messages* buffer"
|
222 |
:type 'integerp :group 'xml-rpc) |
|
223 |
||
224 |
(defvar xml-rpc-fault-string nil |
|
225 |
"Contains the fault string if a fault is returned") |
|
226 |
||
227 |
(defvar xml-rpc-fault-code nil |
|
228 |
"Contains the fault code if a fault is returned") |
|
1
by Mark A. Hershberger
initial commit |
229 |
|
230 |
;;
|
|
231 |
;; Value type handling functions
|
|
232 |
;;
|
|
233 |
||
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
234 |
(defsubst xml-rpc-value-intp (value) |
1
by Mark A. Hershberger
initial commit |
235 |
"Return t if VALUE is an integer."
|
236 |
(integerp value)) |
|
237 |
||
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
238 |
(defsubst xml-rpc-value-doublep (value) |
1
by Mark A. Hershberger
initial commit |
239 |
"Return t if VALUE is a double precision number."
|
240 |
(floatp value)) |
|
241 |
||
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
242 |
(defsubst xml-rpc-value-stringp (value) |
1
by Mark A. Hershberger
initial commit |
243 |
"Return t if VALUE is a string."
|
244 |
(stringp value)) |
|
245 |
||
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
246 |
;; An XML-RPC struct is a list where every car is cons or a list of
|
247 |
;; length 1 or 2 and has a string for car.
|
|
1
by Mark A. Hershberger
initial commit |
248 |
(defsubst xml-rpc-value-structp (value) |
249 |
"Return t if VALUE is an XML-RPC struct."
|
|
250 |
(and (listp value) |
|
251 |
(let ((vals value) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
252 |
(result t) |
253 |
curval) |
|
254 |
(while (and vals result) |
|
255 |
(setq result (and |
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
256 |
(setq curval (car-safe vals)) |
257 |
(consp curval) |
|
258 |
(stringp (car-safe curval)))) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
259 |
(setq vals (cdr-safe vals))) |
260 |
result))) |
|
1
by Mark A. Hershberger
initial commit |
261 |
|
262 |
;; A somewhat lazy predicate for arrays
|
|
263 |
(defsubst xml-rpc-value-arrayp (value) |
|
264 |
"Return t if VALUE is an XML-RPC struct."
|
|
265 |
(and (listp value) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
266 |
(not (xml-rpc-value-datetimep value)) |
1
by Mark A. Hershberger
initial commit |
267 |
(not (xml-rpc-value-structp value)))) |
268 |
||
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
269 |
(defun xml-rpc-submit-bug-report () |
270 |
"Submit a bug report on xml-rpc."
|
|
271 |
(interactive) |
|
272 |
(require 'reporter) |
|
273 |
(let ((xml-rpc-tz-pd-defined-in |
|
274 |
(if (fboundp 'find-lisp-object-file-name) |
|
275 |
(find-lisp-object-file-name |
|
276 |
'timezone-parse-date (symbol-function 'timezone-parse-date)) |
|
30
by Mark A. Hershberger
update bug reporting function. |
277 |
(symbol-file 'timezone-parse-date))) |
278 |
(date-parses-as (timezone-parse-date "20091130T00:52:53"))) |
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
279 |
(reporter-submit-bug-report |
280 |
xml-rpc-maintainer-address
|
|
281 |
(concat "xml-rpc.el " xml-rpc-version) |
|
282 |
(list 'xml-rpc-tz-pd-defined-in |
|
30
by Mark A. Hershberger
update bug reporting function. |
283 |
'date-parses-as
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
284 |
'xml-rpc-load-hook
|
285 |
'xml-rpc-use-coding-system
|
|
286 |
'xml-rpc-allow-unicode-string
|
|
287 |
'xml-rpc-base64-encode-unicode
|
|
288 |
'xml-rpc-base64-decode-unicode)))) |
|
289 |
||
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
290 |
(defun xml-rpc-value-booleanp (value) |
291 |
"Return t if VALUE is a boolean."
|
|
292 |
(or (eq value nil) |
|
293 |
(eq value t))) |
|
294 |
||
295 |
(defun xml-rpc-value-datetimep (value) |
|
296 |
"Return t if VALUE is a datetime. For Emacs XML-RPC
|
|
297 |
implementation, you must put time keyword :datetime before the
|
|
298 |
time, or it will be confused for a list."
|
|
299 |
(and (listp value) |
|
300 |
(eq (car value) :datetime))) |
|
301 |
||
302 |
(defun xml-rpc-string-to-boolean (value) |
|
303 |
"Return t if VALUE is a boolean"
|
|
304 |
(or (string-equal value "true") (string-equal value "1"))) |
|
305 |
||
306 |
(defun xml-rpc-caddar-safe (list) |
|
307 |
(car-safe (cdr-safe (cdr-safe (car-safe list))))) |
|
308 |
||
1
by Mark A. Hershberger
initial commit |
309 |
(defun xml-rpc-xml-list-to-value (xml-list) |
310 |
"Convert an XML-RPC structure in an xml.el style XML-LIST to an elisp list, \
|
|
311 |
interpreting and simplifying it while retaining its structure."
|
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
312 |
(let (valtype valvalue) |
2
by Mark A. Hershberger
reorg & capability update |
313 |
(cond |
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
314 |
((and (xml-rpc-caddar-safe xml-list) |
315 |
(listp (car-safe (cdr-safe (cdr-safe (car-safe xml-list)))))) |
|
316 |
||
317 |
(setq valtype (car (caddar xml-list)) |
|
318 |
valvalue (caddr (caddar xml-list))) |
|
319 |
(cond |
|
320 |
;; Base64
|
|
321 |
((eq valtype 'base64) |
|
322 |
(if xml-rpc-base64-decode-unicode |
|
323 |
(decode-coding-string (base64-decode-string valvalue) 'utf-8) |
|
324 |
(base64-decode-string valvalue))) |
|
325 |
;; Boolean
|
|
326 |
((eq valtype 'boolean) |
|
327 |
(xml-rpc-string-to-boolean valvalue)) |
|
328 |
;; String
|
|
329 |
((eq valtype 'string) |
|
330 |
valvalue) |
|
331 |
;; Integer
|
|
332 |
((or (eq valtype 'int) (eq valtype 'i4)) |
|
21
by Mark A. Hershberger
2009-09-13 Mark A. Hershberger <mah@everybody.org> |
333 |
(string-to-number (or valvalue "0"))) |
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
334 |
;; Double/float
|
335 |
((eq valtype 'double) |
|
336 |
(string-to-number valvalue)) |
|
337 |
;; Struct
|
|
338 |
((eq valtype 'struct) |
|
339 |
(mapcar (lambda (member) |
|
340 |
(let ((membername (cadr (cdaddr member))) |
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
341 |
(membervalue (xml-rpc-xml-list-to-value |
32
by Mark A. Hershberger
Apply Leo's patches |
342 |
(cdddr member)))) |
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
343 |
(cons membername membervalue))) |
344 |
(cddr (caddar xml-list)))) |
|
345 |
;; Fault
|
|
346 |
((eq valtype 'fault) |
|
347 |
(let* ((struct (xml-rpc-xml-list-to-value (list valvalue))) |
|
348 |
(fault-string (cdr (assoc "faultString" struct))) |
|
349 |
(fault-code (cdr (assoc "faultCode" struct)))) |
|
350 |
(list 'fault fault-code fault-string))) |
|
351 |
;; DateTime
|
|
21
by Mark A. Hershberger
2009-09-13 Mark A. Hershberger <mah@everybody.org> |
352 |
((or (eq valtype 'dateTime.iso8601) |
353 |
(eq valtype 'dateTime)) |
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
354 |
(list :datetime (date-to-time valvalue))) |
355 |
;; Array
|
|
356 |
((eq valtype 'array) |
|
357 |
(mapcar (lambda (arrval) |
|
358 |
(xml-rpc-xml-list-to-value (list arrval))) |
|
359 |
(cddr valvalue))))) |
|
360 |
((xml-rpc-caddar-safe xml-list))))) |
|
1
by Mark A. Hershberger
initial commit |
361 |
|
362 |
(defun xml-rpc-boolean-to-string (value) |
|
363 |
"Convert a boolean value to a string"
|
|
364 |
(if value |
|
365 |
"1"
|
|
366 |
"0")) |
|
367 |
||
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
368 |
(defun xml-rpc-datetime-to-string (value) |
369 |
"Convert a date time to a valid XML-RPC date"
|
|
21
by Mark A. Hershberger
2009-09-13 Mark A. Hershberger <mah@everybody.org> |
370 |
(format-time-string "%Y%m%dT%H:%M:%S" (cadr value))) |
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
371 |
|
1
by Mark A. Hershberger
initial commit |
372 |
(defun xml-rpc-value-to-xml-list (value) |
373 |
"Return XML representation of VALUE properly formatted for use with the \
|
|
374 |
functions in xml.el."
|
|
375 |
(cond |
|
32
by Mark A. Hershberger
Apply Leo's patches |
376 |
;; ((not value)
|
377 |
;; nil)
|
|
1
by Mark A. Hershberger
initial commit |
378 |
((xml-rpc-value-booleanp value) |
379 |
`((value nil (boolean nil ,(xml-rpc-boolean-to-string value))))) |
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
380 |
;; Date
|
381 |
((xml-rpc-value-datetimep value) |
|
21
by Mark A. Hershberger
2009-09-13 Mark A. Hershberger <mah@everybody.org> |
382 |
`((value nil (dateTime.iso8601 nil ,(xml-rpc-datetime-to-string value))))) |
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
383 |
;; list
|
384 |
((xml-rpc-value-arrayp value) |
|
1
by Mark A. Hershberger
initial commit |
385 |
(let ((result nil) |
32
by Mark A. Hershberger
Apply Leo's patches |
386 |
(xmlval nil)) |
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
387 |
(while (setq xmlval (xml-rpc-value-to-xml-list (car value)) |
388 |
result (if result (append result xmlval) |
|
389 |
xmlval) |
|
390 |
value (cdr value))) |
|
391 |
`((value nil (array nil ,(append '(data nil) result)))))) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
392 |
;; struct
|
393 |
((xml-rpc-value-structp value) |
|
394 |
(let ((result nil) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
395 |
(xmlval nil)) |
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
396 |
(while (setq xmlval `((member nil (name nil ,(caar value)) |
32
by Mark A. Hershberger
Apply Leo's patches |
397 |
,(car (xml-rpc-value-to-xml-list |
398 |
(cdar value))))) |
|
399 |
result (append result xmlval) |
|
400 |
value (cdr value))) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
401 |
`((value nil ,(append '(struct nil) result))))) |
1
by Mark A. Hershberger
initial commit |
402 |
;; Value is a scalar
|
403 |
((xml-rpc-value-intp value) |
|
404 |
`((value nil (int nil ,(int-to-string value))))) |
|
405 |
((xml-rpc-value-stringp value) |
|
406 |
(let ((charset-list (find-charset-string value))) |
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
407 |
(if (or xml-rpc-allow-unicode-string |
32
by Mark A. Hershberger
Apply Leo's patches |
408 |
(and (eq 1 (length charset-list)) |
409 |
(eq 'ascii (car charset-list))) |
|
410 |
(not xml-rpc-base64-encode-unicode)) |
|
411 |
`((value nil (string nil ,value))) |
|
412 |
`((value nil (base64 nil ,(if xml-rpc-base64-encode-unicode |
|
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
413 |
(base64-encode-string |
414 |
(encode-coding-string |
|
415 |
value xml-rpc-use-coding-system)) |
|
416 |
(base64-encode-string value)))))))) |
|
1
by Mark A. Hershberger
initial commit |
417 |
((xml-rpc-value-doublep value) |
418 |
`((value nil (double nil ,(number-to-string value))))) |
|
419 |
(t |
|
420 |
`((value nil (base64 nil ,(base64-encode-string value))))))) |
|
421 |
||
422 |
(defun xml-rpc-xml-to-string (xml) |
|
423 |
"Return a string representation of the XML tree as valid XML markup."
|
|
424 |
(let ((tree (xml-node-children xml)) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
425 |
(result (concat "<" (symbol-name (xml-node-name xml)) ">"))) |
1
by Mark A. Hershberger
initial commit |
426 |
(while tree |
427 |
(cond |
|
428 |
((listp (car tree)) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
429 |
(setq result (concat result (xml-rpc-xml-to-string (car tree))))) |
1
by Mark A. Hershberger
initial commit |
430 |
((stringp (car tree)) |
32
by Mark A. Hershberger
Apply Leo's patches |
431 |
(setq result (concat result (car tree)))) |
1
by Mark A. Hershberger
initial commit |
432 |
(t |
32
by Mark A. Hershberger
Apply Leo's patches |
433 |
(error "Invalid XML tree"))) |
1
by Mark A. Hershberger
initial commit |
434 |
(setq tree (cdr tree))) |
435 |
(setq result (concat result "</" (symbol-name (xml-node-name xml)) ">")) |
|
436 |
result)) |
|
437 |
||
438 |
;;
|
|
439 |
;; Response handling
|
|
440 |
;;
|
|
441 |
||
442 |
(defsubst xml-rpc-response-errorp (response) |
|
443 |
"An 'xml-rpc-method-call' result value is always a list, where the first \
|
|
444 |
element in RESPONSE is either nil or if an error occured, a cons pair \
|
|
445 |
according to (errnum . \"Error string\"),"
|
|
5
by Mark A. Hershberger
2007-11-23 Mark A. Hershberger <mah@everybody.org> |
446 |
(eq 'fault (car-safe (caddar response)))) |
1
by Mark A. Hershberger
initial commit |
447 |
|
448 |
(defsubst xml-rpc-response-error-code (response) |
|
449 |
"Return the error code from RESPONSE."
|
|
450 |
(and (xml-rpc-response-errorp response) |
|
451 |
(nth 1 (xml-rpc-xml-list-to-value response)))) |
|
452 |
||
453 |
(defsubst xml-rpc-response-error-string (response) |
|
454 |
"Return the error code from RESPONSE."
|
|
455 |
(and (xml-rpc-response-errorp response) |
|
456 |
(nth 2 (xml-rpc-xml-list-to-value response)))) |
|
457 |
||
458 |
(defun xml-rpc-xml-to-response (xml) |
|
459 |
"Convert an XML list to a method response list. An error is
|
|
460 |
signaled if there is a fault or if the response does not appear
|
|
461 |
to be an XML-RPC response (i.e. no methodResponse). Otherwise,
|
|
462 |
the parsed XML response is returned."
|
|
463 |
;; Check if we have a methodResponse
|
|
464 |
(cond |
|
465 |
((not (eq (car-safe (car-safe xml)) 'methodResponse)) |
|
466 |
(error "No methodResponse found")) |
|
467 |
||
468 |
;; Did we get a fault response
|
|
469 |
((xml-rpc-response-errorp xml) |
|
470 |
(let ((resp (xml-rpc-xml-list-to-value xml))) |
|
471 |
(setq xml-rpc-fault-string (nth 2 resp)) |
|
472 |
(setq xml-rpc-fault-code (nth 1 resp)) |
|
473 |
(error "XML-RPC fault `%s'" xml-rpc-fault-string))) |
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
474 |
|
1
by Mark A. Hershberger
initial commit |
475 |
;; Interpret the XML list and produce a more useful data structure
|
476 |
(t |
|
477 |
(let ((valpart (cdr (cdaddr (caddar xml))))) |
|
478 |
(xml-rpc-xml-list-to-value valpart))))) |
|
479 |
||
480 |
;;
|
|
481 |
;; Method handling
|
|
482 |
;;
|
|
483 |
||
484 |
(defun xml-rpc-request (server-url xml &optional async-callback-function) |
|
485 |
"Perform http post request to SERVER-URL using XML.
|
|
486 |
||
487 |
If ASYNC-CALLBACK-FUNCTION is non-nil, the request will be performed
|
|
488 |
asynchronously and ASYNC-CALLBACK-FUNCTION should be a callback function to
|
|
489 |
be called when the reuest is finished. ASYNC-CALLBACK-FUNCTION is called with
|
|
490 |
a single argument being an xml.el style XML list.
|
|
491 |
||
492 |
It returns an XML list containing the method response from the XML-RPC server,
|
|
493 |
or nil if called with ASYNC-CALLBACK-FUNCTION."
|
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
494 |
(declare (special url-current-callback-data |
495 |
url-current-callback-func
|
|
496 |
url-http-response-status)) |
|
1
by Mark A. Hershberger
initial commit |
497 |
(unwind-protect |
498 |
(save-excursion |
|
32
by Mark A. Hershberger
Apply Leo's patches |
499 |
(let ((url-request-method "POST") |
500 |
(url-package-name "xml-rpc.el") |
|
501 |
(url-package-version xml-rpc-version) |
|
502 |
(url-request-data (concat "<?xml version=\"1.0\"" |
|
9
by Mark A. Hershberger
Clean up long lines, address bugs, use string-to-number instead of |
503 |
" encoding=\"UTF-8\"?>\n"
|
32
by Mark A. Hershberger
Apply Leo's patches |
504 |
(with-temp-buffer |
505 |
(xml-print xml) |
|
506 |
(when xml-rpc-allow-unicode-string |
|
507 |
(encode-coding-region |
|
508 |
(point-min) (point-max) 'utf-8)) |
|
509 |
(buffer-string)) |
|
510 |
"\n")) |
|
511 |
(url-mime-charset-string "utf-8;q=1, iso-8859-1;q=0.5") |
|
512 |
(url-request-coding-system xml-rpc-use-coding-system) |
|
513 |
(url-http-attempt-keepalives t) |
|
514 |
(url-request-extra-headers (list |
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
515 |
(cons "Connection" "keep-alive") |
32
by Mark A. Hershberger
Apply Leo's patches |
516 |
(cons "Content-Type" |
9
by Mark A. Hershberger
Clean up long lines, address bugs, use string-to-number instead of |
517 |
"text/xml; charset=utf-8")))) |
32
by Mark A. Hershberger
Apply Leo's patches |
518 |
(when (> xml-rpc-debug 1) |
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
519 |
(print url-request-data (create-file-buffer "request-data"))) |
1
by Mark A. Hershberger
initial commit |
520 |
|
32
by Mark A. Hershberger
Apply Leo's patches |
521 |
(cond ((boundp 'url-be-asynchronous) ; Sniff for w3 lib capability |
522 |
(if async-callback-function |
|
523 |
(setq url-be-asynchronous t |
|
524 |
url-current-callback-data (list |
|
525 |
async-callback-function
|
|
526 |
(current-buffer)) |
|
527 |
url-current-callback-func
|
|
9
by Mark A. Hershberger
Clean up long lines, address bugs, use string-to-number instead of |
528 |
'xml-rpc-request-callback-handler) |
32
by Mark A. Hershberger
Apply Leo's patches |
529 |
(setq url-be-asynchronous nil)) |
530 |
(url-retrieve server-url t) |
|
1
by Mark A. Hershberger
initial commit |
531 |
|
32
by Mark A. Hershberger
Apply Leo's patches |
532 |
(when (not url-be-asynchronous) |
533 |
(let ((result (xml-rpc-request-process-buffer |
|
534 |
(current-buffer)))) |
|
535 |
(when (> xml-rpc-debug 1) |
|
28
by Mark A. Hershberger
fix new warnings that pop up courtesy of Leo |
536 |
(with-current-buffer (create-file-buffer "result-data") |
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
537 |
(insert result))) |
32
by Mark A. Hershberger
Apply Leo's patches |
538 |
result))) |
539 |
(t ; Post emacs20 w3-el |
|
540 |
(if async-callback-function |
|
541 |
(url-retrieve server-url async-callback-function) |
|
542 |
(let ((buffer (url-retrieve-synchronously server-url)) |
|
543 |
result) |
|
544 |
(with-current-buffer buffer |
|
545 |
(when (not (numberp url-http-response-status)) |
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
546 |
;; this error may occur when keep-alive bug
|
547 |
;; of url-http.el is not cleared.
|
|
548 |
(error "Why? url-http-response-status is %s" |
|
549 |
url-http-response-status)) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
550 |
(when (> url-http-response-status 299) |
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
551 |
(error "Error during request: %s" |
552 |
url-http-response-status))) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
553 |
(xml-rpc-request-process-buffer buffer))))))))) |
1
by Mark A. Hershberger
initial commit |
554 |
|
555 |
||
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
556 |
(defun xml-rpc-clean-string (s) |
557 |
(if (string-match "\\`[ \t\n\r]*\\'" s) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
558 |
;;"^[ \t\n]*$" s)
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
559 |
nil
|
560 |
s)) |
|
561 |
||
1
by Mark A. Hershberger
initial commit |
562 |
(defun xml-rpc-clean (l) |
563 |
(cond |
|
564 |
((listp l) |
|
565 |
(let ((remain l) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
566 |
elem
|
567 |
(result nil)) |
|
1
by Mark A. Hershberger
initial commit |
568 |
(while l |
32
by Mark A. Hershberger
Apply Leo's patches |
569 |
;; iterate
|
570 |
(setq elem (car l) |
|
571 |
l (cdr l)) |
|
572 |
;; test the head
|
|
573 |
(cond |
|
574 |
;; a string, so clean it.
|
|
575 |
((stringp elem) |
|
576 |
(let ((tmp (xml-rpc-clean-string elem))) |
|
577 |
(when (and tmp xml-rpc-allow-unicode-string) |
|
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
578 |
(setq tmp (decode-coding-string tmp xml-rpc-use-coding-system))) |
32
by Mark A. Hershberger
Apply Leo's patches |
579 |
(if tmp |
580 |
(setq result (append result (list tmp))) |
|
581 |
result))) |
|
582 |
;; a list, so recurse.
|
|
583 |
((listp elem) |
|
584 |
(setq result (append result (list (xml-rpc-clean elem))))) |
|
1
by Mark A. Hershberger
initial commit |
585 |
|
32
by Mark A. Hershberger
Apply Leo's patches |
586 |
;; everthing else, as is.
|
587 |
(t |
|
588 |
(setq result (append result (list elem)))))) |
|
1
by Mark A. Hershberger
initial commit |
589 |
result)) |
590 |
||
32
by Mark A. Hershberger
Apply Leo's patches |
591 |
((stringp l) ; will returning nil be acceptable ? |
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
592 |
nil) |
1
by Mark A. Hershberger
initial commit |
593 |
|
18
by Mark A. Hershberger
2009-09-09 Mark A. Hershberger <mah@everybody.org> |
594 |
(t l))) |
1
by Mark A. Hershberger
initial commit |
595 |
|
596 |
(defun xml-rpc-request-process-buffer (xml-buffer) |
|
597 |
"Process buffer XML-BUFFER."
|
|
598 |
(unwind-protect |
|
28
by Mark A. Hershberger
fix new warnings that pop up courtesy of Leo |
599 |
(with-current-buffer xml-buffer |
32
by Mark A. Hershberger
Apply Leo's patches |
600 |
(when (fboundp 'url-uncompress) |
15
by Mark A. Hershberger
2009-08-12 Mark A. Hershberger <mah@everybody.org> |
601 |
(let ((url-working-buffer xml-buffer)) |
602 |
(url-uncompress))) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
603 |
(goto-char (point-min)) |
604 |
(search-forward-regexp "<\\?xml" nil t) |
|
605 |
(move-to-column 0) |
|
606 |
;; Gather the results
|
|
607 |
(let* ((status (if (boundp 'url-http-response-status) |
|
608 |
;; Old URL lib doesn't save the result.
|
|
23
by Mark A. Hershberger
Add submit-bug function and mode toggling functionality. |
609 |
url-http-response-status 200)) |
32
by Mark A. Hershberger
Apply Leo's patches |
610 |
(result (cond |
611 |
;; A probable XML response
|
|
612 |
((looking-at "<\\?xml ") |
|
613 |
(xml-rpc-clean (xml-parse-region (point-min) |
|
614 |
(point-max)))) |
|
615 |
||
616 |
;; No HTTP status returned
|
|
617 |
((not status) |
|
618 |
(let ((errstart |
|
619 |
(search-forward "\n---- Error was: ----\n"))) |
|
620 |
(and errstart |
|
621 |
(buffer-substring errstart (point-max))))) |
|
622 |
||
623 |
;; Maybe they just gave us an the XML w/o PI?
|
|
624 |
((search-forward "<methodResponse>" nil t) |
|
625 |
(xml-rpc-clean (xml-parse-region (match-beginning 0) |
|
626 |
(point-max)))) |
|
627 |
||
628 |
;; Valid HTTP status
|
|
629 |
(t |
|
630 |
(int-to-string status))))) |
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
631 |
(when (< xml-rpc-debug 3) |
632 |
(kill-buffer (current-buffer))) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
633 |
result)))) |
1
by Mark A. Hershberger
initial commit |
634 |
|
635 |
||
636 |
(defun xml-rpc-request-callback-handler (callback-fun xml-buffer) |
|
637 |
"Marshall a callback function request to CALLBACK-FUN with the results \
|
|
638 |
handled from XML-BUFFER."
|
|
639 |
(let ((xml-response (xml-rpc-request-process-buffer xml-buffer))) |
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
640 |
(when (< xml-rpc-debug 1) |
641 |
(kill-buffer xml-buffer)) |
|
1
by Mark A. Hershberger
initial commit |
642 |
(funcall callback-fun (xml-rpc-xml-to-response xml-response)))) |
29
by Mark A. Hershberger
Some minor housekeeping, bump xml-rpc.el version. |
643 |
|
1
by Mark A. Hershberger
initial commit |
644 |
|
645 |
(defun xml-rpc-method-call-async (async-callback-func server-url method |
|
32
by Mark A. Hershberger
Apply Leo's patches |
646 |
&rest params) |
1
by Mark A. Hershberger
initial commit |
647 |
"Call an XML-RPC method asynchronously at SERVER-URL named METHOD with \
|
648 |
PARAMS as parameters. When the method returns, ASYNC-CALLBACK-FUNC will be \
|
|
649 |
called with the result as parameter."
|
|
650 |
(let* ((m-name (if (stringp method) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
651 |
method
|
652 |
(symbol-name method))) |
|
653 |
(m-params (mapcar '(lambda (p) |
|
654 |
`(param nil ,(car (xml-rpc-value-to-xml-list |
|
655 |
p)))) |
|
656 |
(if async-callback-func |
|
657 |
params
|
|
658 |
(car-safe params)))) |
|
659 |
(m-func-call `((methodCall nil (methodName nil ,m-name) |
|
660 |
,(append '(params nil) m-params))))) |
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
661 |
(when (> xml-rpc-debug 1) |
662 |
(print m-func-call (create-file-buffer "func-call"))) |
|
1
by Mark A. Hershberger
initial commit |
663 |
(xml-rpc-request server-url m-func-call async-callback-func))) |
664 |
||
665 |
(defun xml-rpc-method-call (server-url method &rest params) |
|
666 |
"Call an XML-RPC method at SERVER-URL named METHOD with PARAMS as \
|
|
667 |
parameters."
|
|
668 |
(let ((response |
|
32
by Mark A. Hershberger
Apply Leo's patches |
669 |
(xml-rpc-method-call-async nil server-url method params))) |
1
by Mark A. Hershberger
initial commit |
670 |
(cond ((stringp response) |
32
by Mark A. Hershberger
Apply Leo's patches |
671 |
(list (cons nil (concat "URL/HTTP Error: " response)))) |
672 |
(t |
|
673 |
(xml-rpc-xml-to-response response))))) |
|
1
by Mark A. Hershberger
initial commit |
674 |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
675 |
(unless (fboundp 'xml-escape-string) |
676 |
(defun xml-debug-print (xml &optional indent-string) |
|
677 |
"Outputs the XML in the current buffer.
|
|
2
by Mark A. Hershberger
reorg & capability update |
678 |
XML can be a tree or a list of nodes.
|
679 |
The first line is indented with the optional INDENT-STRING."
|
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
680 |
(setq indent-string (or indent-string "")) |
681 |
(dolist (node xml) |
|
682 |
(xml-debug-print-internal node indent-string))) |
|
683 |
||
684 |
(defalias 'xml-print 'xml-debug-print) |
|
685 |
||
686 |
(when (not (boundp 'xml-entity-alist)) |
|
687 |
(defvar xml-entity-alist |
|
688 |
'(("lt" . "<") |
|
32
by Mark A. Hershberger
Apply Leo's patches |
689 |
("gt" . ">") |
690 |
("apos" . "'") |
|
691 |
("quot" . "\"") |
|
692 |
("amp" . "&")))) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
693 |
|
694 |
(defun xml-escape-string (string) |
|
695 |
"Return the string with entity substitutions made from
|
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
696 |
xml-entity-alist."
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
697 |
(mapconcat (lambda (byte) |
32
by Mark A. Hershberger
Apply Leo's patches |
698 |
(let ((char (char-to-string byte))) |
699 |
(if (rassoc char xml-entity-alist) |
|
700 |
(concat "&" (car (rassoc char xml-entity-alist)) ";") |
|
701 |
char))) |
|
702 |
;; This differs from the non-unicode branch. Just
|
|
703 |
;; grabbing the string works here.
|
|
704 |
string "")) |
|
7
by Mark A. Hershberger
2009-08-01 Mark A. Hershberger <mah@everybody.org> |
705 |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
706 |
(defun xml-debug-print-internal (xml indent-string) |
707 |
"Outputs the XML tree in the current buffer.
|
|
2
by Mark A. Hershberger
reorg & capability update |
708 |
The first line is indented with INDENT-STRING."
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
709 |
(let ((tree xml) |
32
by Mark A. Hershberger
Apply Leo's patches |
710 |
attlist) |
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
711 |
(insert indent-string ?< (symbol-name (xml-node-name tree))) |
712 |
||
713 |
;; output the attribute list
|
|
714 |
(setq attlist (xml-node-attributes tree)) |
|
715 |
(while attlist |
|
32
by Mark A. Hershberger
Apply Leo's patches |
716 |
(insert ?\ (symbol-name (caar attlist)) "=\"" |
717 |
(xml-escape-string (cdar attlist)) ?\") |
|
718 |
(setq attlist (cdr attlist))) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
719 |
|
720 |
(setq tree (xml-node-children tree)) |
|
721 |
||
722 |
(if (null tree) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
723 |
(insert ?/ ?>) |
724 |
(insert ?>) |
|
725 |
||
726 |
;; output the children
|
|
727 |
(dolist (node tree) |
|
728 |
(cond |
|
729 |
((listp node) |
|
730 |
(insert ?\n) |
|
731 |
(xml-debug-print-internal node (concat indent-string " "))) |
|
732 |
((stringp node) |
|
733 |
(insert (xml-escape-string node))) |
|
734 |
(t |
|
735 |
(error "Invalid XML tree")))) |
|
736 |
||
737 |
(when (not (and (null (cdr tree)) |
|
738 |
(stringp (car tree)))) |
|
739 |
(insert ?\n indent-string)) |
|
740 |
(insert ?< ?/ (symbol-name (xml-node-name xml)) ?>))))) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
741 |
|
742 |
(let ((tdate (timezone-parse-date "20090101T010101Z"))) |
|
743 |
(when (not (string-equal (aref tdate 0) "2009")) |
|
744 |
(defun timezone-parse-date (date) |
|
745 |
"Parse DATE and return a vector [YEAR MONTH DAY TIME TIMEZONE].
|
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
746 |
Two-digit dates are `windowed'. Those <69 have 2000 added; otherwise 1900 |
747 |
is added. Three-digit dates have 1900 added.
|
|
748 |
TIMEZONE is nil for DATEs without a zone field.
|
|
749 |
||
750 |
Understands the following styles:
|
|
751 |
(1) 14 Apr 89 03:20[:12] [GMT]
|
|
752 |
(2) Fri, 17 Mar 89 4:01[:33] [GMT]
|
|
753 |
(3) Mon Jan 16 16:12[:37] [GMT] 1989
|
|
754 |
(4) 6 May 1992 1641-JST (Wednesday)
|
|
755 |
(5) 22-AUG-1993 10:59:12.82
|
|
756 |
(6) Thu, 11 Apr 16:17:12 91 [MET]
|
|
757 |
(7) Mon, 6 Jul 16:47:20 T 1992 [MET]
|
|
758 |
(8) 1996-06-24 21:13:12 [GMT]
|
|
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
759 |
(9) 1996-06-24 21:13-ZONE
|
760 |
(10) 19960624T211312"
|
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
761 |
;; Get rid of any text properties.
|
762 |
(and (stringp date) |
|
32
by Mark A. Hershberger
Apply Leo's patches |
763 |
(or (text-properties-at 0 date) |
764 |
(next-property-change 0 date)) |
|
765 |
(setq date (copy-sequence date)) |
|
766 |
(set-text-properties 0 (length date) nil date)) |
|
22
by Mark A. Hershberger
2009-09-16 Mark A. Hershberger <mah@everybody.org> |
767 |
(let ((date (or date "")) |
32
by Mark A. Hershberger
Apply Leo's patches |
768 |
(year nil) |
769 |
(month nil) |
|
770 |
(day nil) |
|
771 |
(time nil) |
|
772 |
(zone nil)) ;This may be nil. |
|
773 |
(cond ((string-match |
|
774 |
"\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)" date) |
|
775 |
;; Styles: (1) and (2) with timezone and buggy timezone
|
|
776 |
;; This is most common in mail and news,
|
|
777 |
;; so it is worth trying first.
|
|
778 |
(setq year 3 month 2 day 1 time 4 zone 5)) |
|
779 |
((string-match |
|
780 |
"\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]*\\'" date) |
|
781 |
;; Styles: (1) and (2) without timezone
|
|
782 |
(setq year 3 month 2 day 1 time 4 zone nil)) |
|
783 |
((string-match |
|
784 |
"\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\'" date) |
|
785 |
;; Styles: (6) and (7) without timezone
|
|
786 |
(setq year 6 month 3 day 2 time 4 zone nil)) |
|
787 |
((string-match |
|
788 |
"\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) |
|
789 |
;; Styles: (6) and (7) with timezone and buggy timezone
|
|
790 |
(setq year 6 month 3 day 2 time 4 zone 7)) |
|
791 |
((string-match |
|
792 |
"\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([0-9]+\\)" date) |
|
793 |
;; Styles: (3) without timezone
|
|
794 |
(setq year 4 month 1 day 2 time 3 zone nil)) |
|
795 |
((string-match |
|
796 |
"\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)[ \t]+\\([0-9]+\\)" date) |
|
797 |
;; Styles: (3) with timezone
|
|
798 |
(setq year 5 month 1 day 2 time 3 zone 4)) |
|
799 |
((string-match |
|
800 |
"\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) |
|
801 |
;; Styles: (4) with timezone
|
|
802 |
(setq year 3 month 2 day 1 time 4 zone 5)) |
|
803 |
((string-match |
|
804 |
"\\([0-9]+\\)-\\([A-Za-z]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)\\(\\.[0-9]+\\)?[ \t]+\\([-+a-zA-Z0-9]+\\)" date) |
|
805 |
;; Styles: (5) with timezone.
|
|
806 |
(setq year 3 month 2 day 1 time 4 zone 6)) |
|
807 |
((string-match |
|
808 |
"\\([0-9]+\\)-\\([A-Za-z]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)\\(\\.[0-9]+\\)?" date) |
|
809 |
;; Styles: (5) without timezone.
|
|
810 |
(setq year 3 month 2 day 1 time 4 zone nil)) |
|
811 |
((string-match |
|
812 |
"\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)" date) |
|
813 |
;; Styles: (8) with timezone.
|
|
814 |
(setq year 1 month 2 day 3 time 4 zone 5)) |
|
815 |
((string-match |
|
816 |
"\\([0-9]\\{4\\}\\)-?\\([0-9]\\{0,2\\}\\)-?\\([0-9]\\{0,2\\}\\)[T \t]+\\([0-9]\\{0,2\\}:?[0-9]\\{0,2\\}:?[0-9]\\{0,2\\}\\)[ \t]*\\([-+a-zA-Z]+[0-9:]*\\)" date) |
|
817 |
;; Styles: (8) with timezone with a colon in it.
|
|
818 |
(setq year 1 month 2 day 3 time 4 zone 5)) |
|
819 |
((string-match |
|
820 |
"\\([0-9]\\{4\\}\\)-?\\([0-9]\\{0,2\\}\\)-?\\([0-9]\\{0,2\\}\\)[T \t]+\\([0-9]+:?[0-9]+:?[0-9]+\\)" date) |
|
821 |
;; Styles: (8) without timezone.
|
|
822 |
(setq year 1 month 2 day 3 time 4 zone nil))) |
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
823 |
|
32
by Mark A. Hershberger
Apply Leo's patches |
824 |
(when year |
825 |
(setq year (match-string year date)) |
|
826 |
;; Guess ambiguous years. Assume years < 69 don't predate the
|
|
827 |
;; Unix Epoch, so are 2000+. Three-digit years are assumed to
|
|
828 |
;; be relative to 1900.
|
|
829 |
(when (< (length year) 4) |
|
830 |
(let ((y (string-to-number year))) |
|
831 |
(when (< y 69) |
|
832 |
(setq y (+ y 100))) |
|
833 |
(setq year (int-to-string (+ 1900 y))))) |
|
834 |
(setq month |
|
835 |
(if (or (= (aref date (+ (match-beginning month) 2)) ?-) |
|
836 |
(let ((n (string-to-number |
|
837 |
(char-to-string |
|
838 |
(aref date (+ (match-beginning month) 2)))))) |
|
839 |
(= (aref (number-to-string n) 0) |
|
840 |
(aref date (+ (match-beginning month) 2))))) |
|
841 |
;; Handle numeric months, spanning exactly two digits.
|
|
842 |
(substring date |
|
843 |
(match-beginning month) |
|
844 |
(+ (match-beginning month) 2)) |
|
845 |
(let* ((string (substring date |
|
846 |
(match-beginning month) |
|
847 |
(+ (match-beginning month) 3))) |
|
848 |
(monthnum |
|
849 |
(cdr (assoc (upcase string) timezone-months-assoc)))) |
|
850 |
(when monthnum |
|
851 |
(int-to-string monthnum))))) |
|
852 |
(setq day (match-string day date)) |
|
853 |
(setq time (match-string time date))) |
|
854 |
(when zone (setq zone (match-string zone date))) |
|
855 |
;; Return a vector.
|
|
856 |
(if (and year month) |
|
857 |
(vector year month day time zone) |
|
858 |
(vector "0" "0" "0" "0" nil)))))) |
|
11
by Mark A. Hershberger
2009-08-03 Mark A. Hershberger <mah@everybody.org> |
859 |
|
1
by Mark A. Hershberger
initial commit |
860 |
(provide 'xml-rpc) |
861 |
||
12
by Mark A. Hershberger
2009-08-04 Mark A. Hershberger <mah@everybody.org> |
862 |
;; Local Variables:
|
863 |
;; time-stamp-pattern: "20/^;; Last Modified: <%%>$"
|
|
864 |
;; End:
|
|
865 |
||
1
by Mark A. Hershberger
initial commit |
866 |
;;; xml-rpc.el ends here
|