]> code.delx.au - gnu-emacs/blobdiff - lisp/net/soap-client.el
; Merge from origin/emacs-25
[gnu-emacs] / lisp / net / soap-client.el
index 008bbf4e534a882338271aba39c138daa1428665..f8973a3a5376be43275493f1077b79b3f9347a5a 100644 (file)
@@ -1,14 +1,15 @@
-;;;; soap-client.el -- Access SOAP web services       -*- lexical-binding: t -*-
+;;; soap-client.el --- Access SOAP web services       -*- lexical-binding: t -*-
 
-;; Copyright (C) 2009-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2016 Free Software Foundation, Inc.
 
 ;; Author: Alexandru Harsanyi <AlexHarsanyi@gmail.com>
 ;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
 ;; Created: December, 2009
-;; Version: 3.0.0
+;; Version: 3.1.1
 ;; Keywords: soap, web-services, comm, hypermedia
 ;; Package: soap-client
-;; Homepage: http://code.google.com/p/emacs-soap-client
+;; Homepage: https://github.com/alex-hhh/emacs-soap-client
+;; Package-Requires: ((cl-lib "0.5"))
 
 ;; This file is part of GNU Emacs.
 
@@ -43,6 +44,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (require 'xml)
 (require 'xsd-regexp)
@@ -56,9 +58,9 @@
 (require 'mm-decode)
 
 (defsubst soap-warning (message &rest args)
-  "Display a warning MESSAGE with ARGS, using the 'soap-client warning type."
-  (display-warning 'soap-client (apply #'format-message message args)
-                   :warning))
+  "Display a warning MESSAGE with ARGS, using the `soap-client' warning type."
+  ;; Do not use #'format-message, to support older Emacs versions.
+  (display-warning 'soap-client (apply #'format message args) :warning))
 
 (defgroup soap-client nil
   "Access SOAP web services from Emacs."
@@ -390,7 +392,7 @@ binding) but the same name."
 
 ;; SOAP WSDL documents use XML Schema to define the types that are part of the
 ;; message exchange.  We include here an XML schema model with a parser and
-;; serializer/deserialiser.
+;; serializer/deserializer.
 
 (defstruct (soap-xs-type (:include soap-element))
   id
@@ -560,7 +562,7 @@ fractional seconds, and the DST (daylight savings time) field is
 replaced with DATATYPE, a symbol representing the XSD primitive
 datatype.  This symbol can be used to determine which fields
 apply and which don't when it's not already clear from context.
-For example a datatype of 'time means the year, month and day
+For example a datatype of `time' means the year, month and day
 fields should be ignored.
 
 This function will throw an error if DATE-TIME-STRING represents
@@ -710,7 +712,7 @@ This is a specialization of `soap-decode-type' for
 (defun soap-xs-element-type (element)
   "Retrieve the type of ELEMENT.
 This is normally stored in the TYPE^ slot, but if this element
-contains a reference, we retrive the type of the reference."
+contains a reference, retrieve the type of the reference."
   (if (soap-xs-element-reference element)
       (soap-xs-element-type (soap-xs-element-reference element))
     (soap-xs-element-type^ element)))
@@ -1246,9 +1248,9 @@ See also `soap-wsdl-resolve-references'."
               (error (push (cadr error-object) messages))))
           (when messages
             (error (mapconcat 'identity (nreverse messages) "; and: "))))
-      (cl-flet ((fail-with-message (format value)
-                                   (push (format format value) messages)
-                                   (throw 'invalid nil)))
+      (cl-labels ((fail-with-message (format value)
+                                     (push (format format value) messages)
+                                     (throw 'invalid nil)))
         (catch 'invalid
           (let ((enumeration (soap-xs-simple-type-enumeration type)))
             (when (and (> (length enumeration) 1)
@@ -1628,7 +1630,7 @@ This is a specialization of `soap-encode-value' for
 `soap-xs-complex-type' objects."
   (case (soap-xs-complex-type-indicator type)
     (array
-     (error "soap-encode-xs-complex-type arrays are handled elsewhere"))
+     (error "Arrays of type soap-encode-xs-complex-type are handled elsewhere"))
     ((sequence choice all nil)
      (let ((type-list (list type)))
 
@@ -1989,7 +1991,7 @@ This is a specialization of `soap-decode-type' for
   )
 
 (defun soap-make-wsdl (origin)
-  "Create a new WSDL document, loaded from ORIGIN, and intialize it."
+  "Create a new WSDL document, loaded from ORIGIN, and initialize it."
   (let ((wsdl (soap-make-wsdl^ :origin origin)))
 
     ;; Add the XSD types to the wsdl document
@@ -2753,7 +2755,14 @@ decode function to perform the actual decoding."
 
 ;;;; Soap Envelope parsing
 
-(define-error 'soap-error "SOAP error")
+(if (fboundp 'define-error)
+    (define-error 'soap-error "SOAP error")
+  ;; Support older Emacs versions that do not have define-error, so
+  ;; that soap-client can remain unchanged in GNU ELPA.
+  (put 'soap-error
+       'error-conditions
+       '(error soap-error))
+  (put 'soap-error 'error-message "SOAP error"))
 
 (defun soap-parse-envelope (node operation wsdl)
   "Parse the SOAP envelope in NODE and return the response.
@@ -2990,6 +2999,33 @@ http://schemas.xmlsoap.org/soap/encoding/\"\n"))
   :type 'boolean
   :group 'soap-client)
 
+(defun soap-find-port (wsdl service)
+  "Return the WSDL port having SERVICE name.
+Signal an error if not found."
+  (or (catch 'found
+        (dolist (p (soap-wsdl-ports wsdl))
+          (when (equal service (soap-element-name p))
+            (throw 'found p))))
+      (error "Unknown SOAP service: %s" service)))
+
+(defun soap-find-operation (port operation-name)
+  "Inside PORT, find OPERATION-NAME, a `soap-port-type'.
+Signal an error if not found."
+  (let* ((binding (soap-port-binding port))
+         (op (gethash operation-name (soap-binding-operations binding))))
+    (or op
+        (error "No operation %s for SOAP service %s"
+               operation-name (soap-element-name port)))))
+
+(defun soap-operation-arity (wsdl service operation-name)
+  "Return the number of arguments required by a soap operation.
+WSDL, SERVICE, OPERATION-NAME and PARAMETERS are as described in
+`soap-invoke'."
+  (let* ((port (soap-find-port wsdl service))
+         (op (soap-find-operation port operation-name))
+         (bop (soap-bound-operation-operation op)))
+    (length (soap-operation-parameter-order bop))))
+
 (defun soap-invoke-internal (callback cbargs wsdl service operation-name
                                       &rest parameters)
   "Implement `soap-invoke' and `soap-invoke-async'.
@@ -2997,54 +3033,43 @@ If CALLBACK is non-nil, operate asynchronously, then call CALLBACK as (apply
 CALLBACK RESPONSE CBARGS), where RESPONSE is the SOAP invocation result.
 If CALLBACK is nil, operate synchronously.  WSDL, SERVICE,
 OPERATION-NAME and PARAMETERS are as described in `soap-invoke'."
-  (let ((port (catch 'found
-                (dolist (p (soap-wsdl-ports wsdl))
-                  (when (equal service (soap-element-name p))
-                    (throw 'found p))))))
-    (unless port
-      (error "Unknown SOAP service: %s" service))
-
-    (let* ((binding (soap-port-binding port))
-           (operation (gethash operation-name
-                               (soap-binding-operations binding))))
-      (unless operation
-        (error "No operation %s for SOAP service %s" operation-name service))
-
-      (let ((url-request-method "POST")
-            (url-package-name "soap-client.el")
-            (url-package-version "1.0")
-            (url-request-data
-             ;; url-request-data expects a unibyte string already encoded...
-             (encode-coding-string
-              (soap-create-envelope operation parameters wsdl
-                                    (soap-port-service-url port))
-              'utf-8))
-            (url-mime-charset-string "utf-8;q=1, iso-8859-1;q=0.5")
-            (url-http-attempt-keepalives t)
-            (url-request-extra-headers
-             (list
-              (cons "SOAPAction"
-                    (concat "\"" (soap-bound-operation-soap-action
-                                  operation) "\""))
-              (cons "Content-Type"
-                    "text/xml; charset=utf-8"))))
-        (if callback
-            (url-retrieve
-             (soap-port-service-url port)
-             (lambda (status)
-               (let ((data-buffer (current-buffer)))
-                 (unwind-protect
-                     (let ((error-status (plist-get status :error)))
-                       (if error-status
-                           (signal (car error-status) (cdr error-status))
-                         (apply callback
-                                (soap-parse-envelope
-                                 (soap-parse-server-response)
-                                 operation wsdl)
-                                cbargs)))
-                   ;; Ensure the url-retrieve buffer is not leaked.
-                   (and (buffer-live-p data-buffer)
-                        (kill-buffer data-buffer))))))
+  (let* ((port (soap-find-port wsdl service))
+         (operation (soap-find-operation port operation-name)))
+    (let ((url-request-method "POST")
+          (url-package-name "soap-client.el")
+          (url-package-version "1.0")
+          (url-request-data
+           ;; url-request-data expects a unibyte string already encoded...
+           (encode-coding-string
+            (soap-create-envelope operation parameters wsdl
+                                  (soap-port-service-url port))
+            'utf-8))
+          (url-mime-charset-string "utf-8;q=1, iso-8859-1;q=0.5")
+          (url-http-attempt-keepalives t)
+          (url-request-extra-headers
+           (list
+            (cons "SOAPAction"
+                  (concat "\"" (soap-bound-operation-soap-action
+                                operation) "\""))
+            (cons "Content-Type"
+                  "text/xml; charset=utf-8"))))
+      (if callback
+          (url-retrieve
+           (soap-port-service-url port)
+           (lambda (status)
+             (let ((data-buffer (current-buffer)))
+               (unwind-protect
+                    (let ((error-status (plist-get status :error)))
+                      (if error-status
+                          (signal (car error-status) (cdr error-status))
+                          (apply callback
+                                 (soap-parse-envelope
+                                  (soap-parse-server-response)
+                                  operation wsdl)
+                                 cbargs)))
+                 ;; Ensure the url-retrieve buffer is not leaked.
+                 (and (buffer-live-p data-buffer)
+                      (kill-buffer data-buffer))))))
           (let ((buffer (url-retrieve-synchronously
                          (soap-port-service-url port))))
             (condition-case err
@@ -3068,7 +3093,7 @@ OPERATION-NAME and PARAMETERS are as described in `soap-invoke'."
               (error
                (when soap-debug
                  (pop-to-buffer buffer))
-               (error (error-message-string err))))))))))
+               (error (error-message-string err)))))))))
 
 (defun soap-invoke (wsdl service operation-name &rest parameters)
   "Invoke a SOAP operation and return the result.
@@ -3087,7 +3112,11 @@ the SOAP request.
 NOTE: The SOAP service provider should document the available
 operations and their parameters for the service.  You can also
 use the `soap-inspect' function to browse the available
-operations in a WSDL document."
+operations in a WSDL document.
+
+NOTE: `soap-invoke' base64-decodes xsd:base64Binary return values
+into unibyte strings; these byte-strings require further
+interpretation by the caller."
   (apply #'soap-invoke-internal nil nil wsdl service operation-name parameters))
 
 (defun soap-invoke-async (callback cbargs wsdl service operation-name