- (let (args result)
- ;; Compile search arguments.
- (dolist (elt query)
- (let (vec kw key val
- phrase-cond attr-cond)
-
- ;; Phrase is mandatory, even if empty.
- (when (and (or (member :skip elt) (member :max elt))
- (not (member :phrase elt)))
- (setq vec (vector "phrase" "")))
-
- ;; Parse condition.
- (while (consp elt)
- (setq kw (pop elt))
- (unless (keywordp kw)
- (error "Wrong keyword: %s" kw))
- (setq key (substring (symbol-name kw) 1))
- (case kw
- ;; Phrase condition.
- (:phrase
- ;; It shouldn't happen in an attribute condition.
- (if attr-cond
- (error "Wrong keyword: %s" kw))
- (setq phrase-cond t val (pop elt))
- ;; Value is a string.
- (if (stringp val)
- (setq vec (vconcat vec (list key val)))
- (error "Wrong %s: %s" key val)))
-
- ((:skip :max)
- ;; It shouldn't happen in an attribute condition.
- (if attr-cond
- (error "Wrong keyword: %s" kw))
- (setq phrase-cond t val (pop elt))
- ;; Value is a number.
- (if (numberp val)
- (setq vec (vconcat vec (list key (number-to-string val))))
- (error "Wrong %s: %s" key val)))
-
- ;; Attribute condition.
- ((:submitter :@author)
- ;; It shouldn't happen in a phrase condition.
- (if phrase-cond
- (error "Wrong keyword: %s" kw))
- (if (not (stringp (car elt)))
- (setq vec (vconcat vec (list key "")))
- ;; Value is an email address.
- (while (and (stringp (car elt))
- (string-match "\\`\\S-+\\'" (car elt)))
- (when (string-equal "me" (car elt))
- (setcar elt user-mail-address))
- (when (string-match "<\\(.+\\)>" (car elt))
- (setcar elt (match-string 1 (car elt))))
- (let ((x (pop elt)))
- (unless (member x val)
- (setq val (append val (list x))))))
- (setq vec
- (vconcat vec (list key (mapconcat 'identity val " "))))))
-
- (:status
- ;; It shouldn't happen in a phrase condition.
- (if phrase-cond
- (error "Wrong keyword: %s" kw))
- (setq attr-cond t)
- (if (not (stringp (car elt)))
- (setq vec (vconcat vec (list key "")))
- ;; Possible values: "done", "forwarded" and "open"
- (while (and (stringp (car elt))
- (string-match
- "\\`\\(done\\|forwarded\\|open\\)\\'" (car elt)))
- (let ((x (pop elt)))
- (unless (member x val)
- (setq val (append val (list x))))))
- (setq vec
- (vconcat vec (list key (mapconcat 'identity val " "))))))
-
- ((:subject :package :tags :severity :@title)
- ;; It shouldn't happen in a phrase condition.
- (if phrase-cond
- (error "Wrong keyword: %s" kw))
- (setq attr-cond t)
- (if (not (stringp (car elt)))
- (setq vec (vconcat vec (list key "")))
- ;; Just a string.
- (while (stringp (car elt))
- (let ((x (pop elt)))
- (unless (member x val)
- (setq val (append val (list x))))))
- (setq vec
- (vconcat vec (list key (mapconcat 'identity val " "))))))
-
- ((:date :@cdate)
- ;; It shouldn't happen in a phrase condition.
- (if phrase-cond
- (error "Wrong keyword: %s" kw))
- (setq attr-cond t)
- (if (not (numberp (car elt)))
- (setq vec (vconcat vec (list key "")))
- ;; Just a number.
- (while (numberp (car elt))
- (let ((x (pop elt)))
- (unless (member x val)
- (setq val (append val (list x))))))
- (setq vec
- (vconcat
- vec (list key (mapconcat 'number-to-string val " "))))))
-
- ((:operator :order)
- ;; It shouldn't happen in a phrase condition.
- (if phrase-cond
- (error "Wrong keyword: %s" kw))
- (setq attr-cond t val (pop elt))
- ;; Value is a number.
- (if (stringp val)
- (setq vec (vconcat vec (list key val)))
- (error "Wrong %s: %s" key val)))
-
- (t (error "Unknown key: %s" kw))))
-
- (setq args (vconcat args (list vec)))))
-
- (setq result
- (car (soap-invoke debbugs-wsdl debbugs-port "search_est" args)))
- ;; The result contains lists (key value). We transform it into
- ;; cons cells (key . value).
- (dolist (elt1 result result)
- (dolist (elt2 elt1)
- (setcdr elt2 (cadr elt2))))))
+ (let ((phrase (assoc :phrase query))
+ args result)
+ (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))
+ result1)
+ (while skip
+ (setq result1
+ (apply
+ #'debbugs-search-est
+ (append
+ (list
+ (append
+ phrase `(:skip ,skip)
+ `(:max ,debbugs-max-hits-per-request)))
+ query))
+ skip (and (= (length result1) debbugs-max-hits-per-request)
+ (+ skip debbugs-max-hits-per-request))
+ result (append result result1)))
+ result)
+
+ ;; Compile search arguments.
+ (dolist (elt query)
+ ;; FIXME: `vec' is used in an O(N²) way. It should be a list instead,
+ ;; on which we push elements, and we only convert it to a vector at
+ ;; the end.
+ (let (vec kw key val
+ phrase-cond attr-cond)
+
+ ;; Phrase is mandatory, even if empty.
+ (when (and (or (member :skip elt) (member :max elt))
+ (not (member :phrase elt)))
+ (setq vec (vector "phrase" "")))
+
+ ;; Parse condition.
+ (while (consp elt)
+ (setq kw (pop elt))
+ (unless (keywordp kw)
+ (error "Wrong keyword: %s" kw))
+ (setq key (substring (symbol-name kw) 1))
+ (cl-case kw
+ ;; Phrase condition.
+ (:phrase
+ ;; It shouldn't happen in an attribute condition.
+ (if attr-cond
+ (error "Wrong keyword: %s" kw))
+ (setq phrase-cond t val (pop elt))
+ ;; Value is a string.
+ (if (stringp val)
+ (setq vec (vconcat vec (list key val)))
+ (error "Wrong %s: %s" key val)))
+
+ ((:skip :max)
+ ;; It shouldn't happen in an attribute condition.
+ (if attr-cond
+ (error "Wrong keyword: %s" kw))
+ (setq phrase-cond t val (pop elt))
+ ;; Value is a number.
+ (if (numberp val)
+ (setq vec (vconcat vec (list key (number-to-string val))))
+ (error "Wrong %s: %s" key val)))
+
+ ;; Attribute condition.
+ ((:submitter :@author)
+ ;; It shouldn't happen.
+ (if (or (and (eq kw :submitter) phrase-cond)
+ (and (eq kw :@author) attr-cond))
+ (error "Wrong keyword: %s" kw))
+ (if (not (stringp (car elt)))
+ (setq vec (vconcat vec (list key "")))
+ ;; Value is an email address.
+ (while (and (stringp (car elt))
+ (string-match "\\`\\S-+\\'" (car elt)))
+ (when (string-equal "me" (car elt))
+ (setcar elt user-mail-address))
+ (when (string-match "<\\(.+\\)>" (car elt))
+ (setcar elt (match-string 1 (car elt))))
+ (let ((x (pop elt)))
+ (unless (member x val)
+ (setq val (append val (list x))))))
+ (setq vec
+ (vconcat
+ vec (list key (mapconcat #'identity val " "))))))
+
+ (:status
+ ;; It shouldn't happen in a phrase condition.
+ (if phrase-cond
+ (error "Wrong keyword: %s" kw))
+ (setq attr-cond t)
+ (if (not (stringp (car elt)))
+ (setq vec (vconcat vec (list key "")))
+ ;; Possible values: "pending", "forwarded", "fixed" and "done".
+ (while (and (stringp (car elt))
+ (string-match
+ "\\`\\(pending\\|forwarded\\|fixed\\|done\\)\\'"
+ (car elt)))
+ (let ((x (pop elt)))
+ (unless (member x val)
+ (setq val (append val (list x))))))
+ (setq vec
+ (vconcat
+ vec (list key (mapconcat #'identity val " "))))))
+
+ ((:subject :package :tags :severity :@title)
+ ;; It shouldn't happen in a phrase condition.
+ (if phrase-cond
+ (error "Wrong keyword: %s" kw))
+ (setq attr-cond t)
+ (if (not (stringp (car elt)))
+ (setq vec (vconcat vec (list key "")))
+ ;; Just a string.
+ (while (stringp (car elt))
+ (let ((x (pop elt)))
+ (unless (member x val)
+ (setq val (append val (list x))))))
+ (setq vec
+ (vconcat
+ vec (list key (mapconcat #'identity val " "))))))
+
+ ((:date :@cdate)
+ ;; It shouldn't happen in a phrase condition.
+ (if phrase-cond
+ (error "Wrong keyword: %s" kw))
+ (setq attr-cond t)
+ (if (not (numberp (car elt)))
+ (setq vec (vconcat vec (list key "")))
+ ;; Just a number.
+ (while (numberp (car elt))
+ (let ((x (pop elt)))
+ (unless (member x val)
+ (setq val (append val (list x))))))
+ (setq vec
+ (vconcat
+ vec
+ (list key (mapconcat #'number-to-string val " "))))))
+
+ ((:operator :order)
+ ;; It shouldn't happen in a phrase condition.
+ (if phrase-cond
+ (error "Wrong keyword: %s" kw))
+ (setq attr-cond t val (pop elt))
+ ;; Value is a number.
+ (if (stringp val)
+ (setq vec (vconcat vec (list key val)))
+ (error "Wrong %s: %s" key val)))
+
+ (t (error "Unknown key: %s" kw))))
+
+ (setq args (vconcat args (list vec)))))
+
+ (setq result
+ (car (soap-invoke debbugs-wsdl debbugs-port "search_est" args)))
+ ;; The result contains lists (key value). We transform it into
+ ;; cons cells (key . value).
+ (dolist (elt1 result result)
+ (dolist (elt2 elt1)
+ (setcdr elt2 (cadr elt2)))))))