;; Author: Michael Albinus <michael.albinus@gmx.de>
;; Keywords: comm, hypermedia
;; Package: debbugs
-;; Version: 0.9
-;; Package-Requires: ((async "1.6"))
+;; Version: 0.9.2
+;; Package-Requires: ((soap-client "3.1.1"))
;; This file is not part of GNU Emacs.
(require 'soap-client)
(eval-when-compile (require 'cl))
-(declare-function soap-invoke-async "soap-client")
-(declare-function async-start "async")
-(declare-function async-get "async")
-
(defgroup debbugs nil
"Debbugs library"
:group 'hypermedia)
"The object manipulated by `debbugs-soap-invoke-async'.")
(defun debbugs-soap-invoke-async (operation-name &rest parameters)
- "Invoke the SOAP connection asynchronously.
-If possible, it uses `soap-invoke-async' from soapclient 3.0.
-Otherwise, `async-start' from the async package is used."
- (if (fboundp 'soap-invoke-async)
- ;; This is soap-client 3.0.
- (apply
- 'soap-invoke-async
- (lambda (response &rest args)
- (setq debbugs-soap-invoke-async-object
- (append debbugs-soap-invoke-async-object (car response))))
- nil
- debbugs-wsdl debbugs-port operation-name parameters)
- ;; Fallback with async.
- (async-start
- `(lambda ()
- (load ,(locate-library "soap-client"))
- (apply
- 'soap-invoke
- (soap-load-wsdl
- ,(expand-file-name
- "Debbugs.wsdl"
- (file-name-directory (locate-library "debbugs"))))
- ,debbugs-port ,operation-name ',parameters)))))
+ "Invoke the SOAP connection asynchronously."
+ (apply
+ 'soap-invoke-async
+ (lambda (response &rest args)
+ (setq debbugs-soap-invoke-async-object
+ (append debbugs-soap-invoke-async-object (car response))))
+ nil debbugs-wsdl debbugs-port operation-name parameters))
(defun debbugs-get-bugs (&rest query)
"Return a list of bug numbers which match QUERY.
"Return the list of bug numbers, according to AMOUNT (a number) latest bugs."
(sort (car (soap-invoke debbugs-wsdl debbugs-port "newest_bugs" amount)) '<))
+(defun debbugs-convert-soap-value-to-string (string-value)
+ "If STRING-VALUE is unibyte, decode its contents as a UTF-8 string.
+If STRING-VALUE is a multibyte string, then `soap-client'
+received an xsd:string for this value, and will have decoded it
+already.
+
+If STRING-VALUE is a unibyte string, then `soap-client' received
+an xsd:base64Binary, and ran `base64-decode-string' on it to
+produce a unibyte string of bytes.
+
+For some reason, the Debbugs server code base64-encodes strings
+that contain UTF-8 characters, and returns them as
+xsd:base64Binary, instead of just returning them as xsd:string.
+Therefore, when STRING-VALUE is a unibyte string, we assume its
+bytes represent a UTF-8 string and decode them accordingly."
+ (if (stringp string-value)
+ (if (not (multibyte-string-p string-value))
+ (decode-coding-string string-value 'utf-8)
+ string-value)
+ (error "Invalid string value")))
+
(defun debbugs-get-status (&rest bug-numbers)
"Return a list of status entries for the bugs identified by BUG-NUMBERS.
debbugs-max-hits-per-request))))
(dolist (res results)
- (if (bufferp res)
- ;; This is soap-client 3.0.
- (while (buffer-live-p res)
- (accept-process-output (get-buffer-process res) 0.1))
- ;; Fallback with async.
- (dolist (status (async-get res))
- (setq debbugs-soap-invoke-async-object
- (append debbugs-soap-invoke-async-object status)))))))
+ (while (buffer-live-p res)
+ (accept-process-output (get-buffer-process res) 0.1)))))
(append
cached-bugs
(when (stringp (cdr y))
(setcdr y (mapcar
'string-to-number (split-string (cdr y) " " t)))))
+ ;; "subject", "originator", "owner" and "summary" may be an
+ ;; xsd:base64Binary value containing a UTF-8-encoded string.
+ (dolist (attribute '(subject originator owner summary))
+ (setq y (assoc attribute (cdr (assoc 'value x))))
+ (when (stringp (cdr y))
+ (setcdr y (debbugs-convert-soap-value-to-string (cdr y)))))
;; "package" is a string, containing comma separated
;; package names. "keywords" and "tags" are strings,
;; containing blank separated package names.
(puthash
(cdr (assoc 'key x))
;; Put also a time stamp.
- (cons (cons 'cache_time (floor (float-time)))
+ (cons (cons 'cache_time (float-time))
(cdr (assoc 'value x)))
debbugs-cache-data)
;; Don't cache.
(let ((phrase (assoc :phrase query))
args result)
- (if (and phrase (not (member :skip phrase)) (not (member :skip phrase)))
+ (if (and phrase (not (member :skip phrase)) (not (member :max phrase)))
;; We loop, until we have all results.
(let ((skip 0)
(query (delete phrase query))