/emacsweblogs

To get this branch, use:
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