;; @module xmlrpc-client.lsp ;; @description XMLRPC protocol client routines ;; @version 0.3 - comments redone for automatic documentation ;; @version 0.4 - multiple indices with nth redone to be compatible with future versions ;; @version 0.5 - doc changes ;; @version 0.6 - fixed bug in error handler ;; @version 0.61 - fixed doc typo ;; @version 0.7 - check for valid list type in (get-value expr) thanks Kosh ;; @version 0.8 - changed references to /usr/ to /usr/local/ ;; @version 0.9 - make system.listMethods more flexible for no of args - thanks Ofoe ;; @author Lutz Mueller 2005-2011, Kosh 2012, Oofoe 2016 ;; ;;

Functions for XML-RPC client

;; To use this module include a 'load' statement at the beginning of the program: ;;
;; (load "/usr/local/share/newlisp/modules/xmlrpc-client.lsp")
;; ; or shorter
;; (module "xmlrpc-client.lsp")
;; 
;; The script 'xmlrpc.cgi' implements a method 'newLISP.evalString'. This module contains ;; a client side function for this method for testing purposes. The file 'xmlrpc.cgi' ;; can be found in the 'example' directory of the newLISP source distribution. ;; ;; For further information on XML-RPC consult ;; @link http://www.xmlrpc.com/ http://www.xmlrpc.com/ . ;; ;; Whenever a connection could be made, method functions will return a response ;; formatted by the XML-RPC server in XML. If a connection failed the function will ;; return 'nil' and a call to '(XMLRPC:error)' will return an error text. ;; ;; If the XML received cannot be parsed into SXML, the function returns 'nil' ;; and '(XMLRPC:error)' will return an XML error. SXML is XML transformed into ;; LISP S-expressions. ;; If the XML received is syntactically correct but not correctly formatted, ;; XML garbage is returned or 'nil' is returned and an error message in ;; '(XMLRPC:error)'. ;; @syntax (XMLRPC:system.listMethods ) ;; @param The URL of the XML-RPC server ;; @return A list of methods supported. ;; The server at returns a list of methods supported. ;; @syntax (XMLRPC:system.methodHelp ) ;; @param The URL of the XML-RPC server. ;; @param The name of the method to get help for. ;; @return Help for ;; The server at returns help for the method in ;; @syntax (XMLRPC:system.methodSignatures ) ;; @param The URL of the XML-RPC server. ;; @param The name of the method to get the signature for. ;; @return The signature for a server method. ;; Gets the calling parameter conventions (signature) for a method ;; at . ;; @syntax (XMLRPC:execute ) ;; @param The URL of the XML-RPC server. ;; @param A XML formatted request. ;; @return XML formatted server response ;; This is a generic method for making XML-RPC requests. ;; The request must be XML formatted correctly by the sender (client). ;; @syntax (XMLRPC:newLISP.evalString ) ;; @param The URL of the XML-RPC server. ;; @param The expresssion to be evaluated in a string. ;; @return The result of the expression evaluation. ;; The expression in is encoded in base64 and then ;; transmitted to the remote server. ;; @syntax (XMLRPC:error) ;; @return Error text of last error occured. (context 'XMLRPC) (set 'request [text] %s %s [/text]) (set 'error-msg "") ######### extract value(s) from XML-RPC response XML with ############# ; get result data from result structure ; (define (get-result-data xml) (if (starts-with xml "ERR:") (begin (set 'error-msg xml) (throw nil))) (xml-type-tags nil nil nil nil) (set 'sxml (xml-parse xml (+ 1 2 4))) (if (not sxml) (throw (format "XML error: %s" (first (xml-error))))) (if (match '(("methodResponse" ("fault" *))) sxml) (begin (set 'error-msg (let (fault (sxml 0 1 1 1 1 2 1 1) text (sxml 0 1 1 1 2 2 1 1)) (append "Fault " fault ": " text))) (throw nil))) (get-value (sxml 0 1 1 1))) ; get contents from expr = (value ...) ; (define (get-value expr) (if (empty? expr) nil (list? (expr 1)) (case (expr 1 0) ("i4" (int (expr 1 1))) ("int" (int (expr 1 1))) ("boolean" (if (= "0" (expr 1 1) ) nil true)) ("double" (float (expr 1 1))) ("base64" (base64-dec (expr 1 1))) ("dateTime.iso8601" (expr 1 1)) ("array" (if (= (expr 1) "array") "array" ;; if untagged string "array" (get-array (rest (expr 1 1)))) ) ("struct" (get-struct (rest (expr 1)))) ("string" (expr 1 1)) (true (expr 1)) ) ; end case true (string (expr 1)) ) ; end if ) ; get contents from expr = ((value ...) (value ...) ...) ; (define (get-array expr) (if (empty? expr) '() (cons (get-value (first expr)) (get-array (rest expr))))) ; get contents from expr = ((member ...) (member) ...) ; (define (get-struct expr) (if (empty? expr) '() (cons (get-member (first expr)) (get-struct (rest expr))))) ; get contents from expr = (member ...) ; (define (get-member expr) (list (expr 1 1) (get-value (last expr)))) ################################ standard system methods ####################### # convert to SXML (xml-type-tags nil nil nil nil) # ( method /arg.../ -- XML) Compose XML request. (define (format-request method) (let ((xml (format "%s" method))) (dolist (value (args)) (push (format "%s" value) xml -1)) (push "\n" xml -1))) # return method names in a list of strings # # (XMLRPC:system.listMethods ) # (define (system.listMethods url) (execute url (format-request "system.listMethods"))) # get help for a methodName at url # return help in a string # # (XMLRPC:system.methodHelp ) # (define (system.methodSignature url methodName) (execute url (format request "system.methodSignature" methodName) )) (define (error) error-msg) # Execute a method on url with XML formatted request # # This is a generic method, but with XML formatted by caller. # # (XMLRPC:execute ) # (define (execute url parameter-XML) (if (not (catch (begin (set 'error-msg "") (set 'xml (post-url url parameter-XML "text/xml")) (get-result-data xml)) 'result)) (begin (set 'error-msg "Wrong format in XML-RPC") nil) result)) ######################### newLISP XML-RPC specific methods ##################### # evaluate a newLISP expression in str at newLISP XML-RPC server at url # return evaluation result in a string # (define (newLISP.evalString url str) (execute url (format request "newLISP.evalString" (append "" (base64-enc str) ""))) ) (context MAIN) # eof