aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Cohen2013-03-25 22:40:58 +0000
committerKatsumi Yamaoka2013-03-25 22:40:58 +0000
commitf83a656e333a47e5e452aac3eb192d2fd4c5760e (patch)
tree1d54069424a90a1177f2e981d5d34b1d8cd572b9
parentc074e458df890629fd5b9f5a9fca57fca3dcd8d2 (diff)
downloademacs-f83a656e333a47e5e452aac3eb192d2fd4c5760e.tar.gz
emacs-f83a656e333a47e5e452aac3eb192d2fd4c5760e.zip
lisp/gnus/nnir.el: Major rewrite; Separate searching from group management
-rw-r--r--lisp/gnus/ChangeLog4
-rw-r--r--lisp/gnus/nnir.el587
2 files changed, 359 insertions, 232 deletions
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index c0cf9472dd8..fc9e5b54432 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,7 @@
12013-03-26 Andrew Cohen <cohen@bu.edu>
2
3 * nnir.el: Major rewrite. Separate searching from group management.
4
12013-03-18 Sam Steingold <sds@gnu.org> 52013-03-18 Sam Steingold <sds@gnu.org>
2 6
3 * message.el (message-bury): Minor cleanup. 7 * message.el (message-bury): Minor cleanup.
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index cf5a813c5a8..cabd08b0653 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -29,10 +29,6 @@
29 29
30;;; Commentary: 30;;; Commentary:
31 31
32;; TODO: Documentation in the Gnus manual
33
34;; Where in the existing gnus manual would this fit best?
35
36;; What does it do? Well, it allows you to search your mail using 32;; What does it do? Well, it allows you to search your mail using
37;; some search engine (imap, namazu, swish-e, gmane and others -- see 33;; some search engine (imap, namazu, swish-e, gmane and others -- see
38;; later) by typing `G G' in the Group buffer. You will then get a 34;; later) by typing `G G' in the Group buffer. You will then get a
@@ -136,17 +132,26 @@
136;; other backend. 132;; other backend.
137 133
138;; The interface between the two layers consists of the single 134;; The interface between the two layers consists of the single
139;; function `nnir-run-query', which just selects the appropriate 135;; function `nnir-run-query', which dispatches the search to the
140;; function for the search engine one is using. The input to 136;; proper search function. The argument of `nnir-run-query' is an
141;; `nnir-run-query' is a string, representing the query as input by 137;; alist with two keys: 'nnir-query-spec and 'nnir-group-spec. The
142;; the user. The output of `nnir-run-query' is supposed to be a 138;; value for 'nnir-query-spec is an alist. The only required key/value
143;; vector, each element of which should in turn be a three-element 139;; pair is (query . "query") specifying the search string to pass to
144;; vector. The first element should be full group name of the article, 140;; the query engine. Individual engines may have other elements. The
145;; the second element should be the article number, and the third 141;; value of 'nnir-group-spec is a list with the specification of the
146;; element should be the Retrieval Status Value (RSV) as returned from 142;; groups/servers to search. The format of the 'nnir-group-spec is
147;; the search engine. An RSV is the score assigned to the document by 143;; (("server1" ("group11" "group12")) ("server2" ("group21"
148;; the search engine. For Boolean search engines, the 144;; "group22"))). If any of the group lists is absent then all groups
149;; RSV is always 1000 (or 1 or 100, or whatever you like). 145;; on that server are searched.
146
147;; The output of `nnir-run-query' is supposed to be a vector, each
148;; element of which should in turn be a three-element vector. The
149;; first element should be full group name of the article, the second
150;; element should be the article number, and the third element should
151;; be the Retrieval Status Value (RSV) as returned from the search
152;; engine. An RSV is the score assigned to the document by the search
153;; engine. For Boolean search engines, the RSV is always 1000 (or 1
154;; or 100, or whatever you like).
150 155
151;; The sorting order of the articles in the summary buffer created by 156;; The sorting order of the articles in the summary buffer created by
152;; nnir is based on the order of the articles in the above mentioned 157;; nnir is based on the order of the articles in the above mentioned
@@ -179,26 +184,21 @@
179 184
180;;; Internal Variables: 185;;; Internal Variables:
181 186
182(defvar nnir-current-query nil 187(defvar nnir-memo-query nil
183 "Internal: stores current query (= group name).") 188 "Internal: stores current query.")
184
185(defvar nnir-current-server nil
186 "Internal: stores current server (does it ever change?).")
187 189
188(defvar nnir-current-group-marked nil 190(defvar nnir-memo-server nil
189 "Internal: stores current list of process-marked groups.") 191 "Internal: stores current server.")
190 192
191(defvar nnir-artlist nil 193(defvar nnir-artlist nil
192 "Internal: stores search result.") 194 "Internal: stores search result.")
193 195
194(defvar nnir-tmp-buffer " *nnir*"
195 "Internal: temporary buffer.")
196
197(defvar nnir-search-history () 196(defvar nnir-search-history ()
198 "Internal: the history for querying search options in nnir") 197 "Internal: the history for querying search options in nnir")
199 198
200(defvar nnir-extra-parms nil 199(defconst nnir-tmp-buffer " *nnir*"
201 "Internal: stores request for extra search parms") 200 "Internal: temporary buffer.")
201
202 202
203;; Imap variables 203;; Imap variables
204 204
@@ -290,14 +290,14 @@ is `(valuefunc member)'."
290 (autoload 'nnimap-command "nnimap") 290 (autoload 'nnimap-command "nnimap")
291 (autoload 'nnimap-possibly-change-group "nnimap") 291 (autoload 'nnimap-possibly-change-group "nnimap")
292 (autoload 'nnimap-make-thread-query "nnimap") 292 (autoload 'nnimap-make-thread-query "nnimap")
293 (autoload 'gnus-registry-action "gnus-registry")) 293 (autoload 'gnus-registry-action "gnus-registry")
294 (autoload 'gnus-registry-get-id-key "gnus-registry")
295 (autoload 'gnus-group-topic-name "gnus-topic"))
296
294 297
295(nnoo-declare nnir) 298(nnoo-declare nnir)
296(nnoo-define-basics nnir) 299(nnoo-define-basics nnir)
297 300
298(defvoo nnir-address nil
299 "The address of the nnir server.")
300
301(gnus-declare-backend "nnir" 'mail 'virtual) 301(gnus-declare-backend "nnir" 'mail 'virtual)
302 302
303 303
@@ -344,7 +344,7 @@ result, `gnus-retrieve-headers' will be called instead."
344(defcustom nnir-imap-default-search-key "whole message" 344(defcustom nnir-imap-default-search-key "whole message"
345 "*The default IMAP search key for an nnir search. Must be one of 345 "*The default IMAP search key for an nnir search. Must be one of
346 the keys in `nnir-imap-search-arguments'. To use raw imap queries 346 the keys in `nnir-imap-search-arguments'. To use raw imap queries
347 by default set this to \"Imap\"." 347 by default set this to \"imap\"."
348 :version "24.1" 348 :version "24.1"
349 :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem))) 349 :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem)))
350 nnir-imap-search-arguments)) 350 nnir-imap-search-arguments))
@@ -546,17 +546,17 @@ that it is for notmuch, not Namazu."
546 ,nnir-imap-default-search-key ; default 546 ,nnir-imap-default-search-key ; default
547 ))) 547 )))
548 (gmane nnir-run-gmane 548 (gmane nnir-run-gmane
549 ((author . "Gmane Author: "))) 549 ((gmane-author . "Gmane Author: ")))
550 (swish++ nnir-run-swish++ 550 (swish++ nnir-run-swish++
551 ((group . "Swish++ Group spec: "))) 551 ((swish++-group . "Swish++ Group spec: ")))
552 (swish-e nnir-run-swish-e 552 (swish-e nnir-run-swish-e
553 ((group . "Swish-e Group spec: "))) 553 ((swish-e-group . "Swish-e Group spec: ")))
554 (namazu nnir-run-namazu 554 (namazu nnir-run-namazu
555 ()) 555 ())
556 (notmuch nnir-run-notmuch 556 (notmuch nnir-run-notmuch
557 ()) 557 ())
558 (hyrex nnir-run-hyrex 558 (hyrex nnir-run-hyrex
559 ((group . "Hyrex Group spec: "))) 559 ((hyrex-group . "Hyrex Group spec: ")))
560 (find-grep nnir-run-find-grep 560 (find-grep nnir-run-find-grep
561 ((grep-options . "Grep options: ")))) 561 ((grep-options . "Grep options: "))))
562 "Alist of supported search engines. 562 "Alist of supported search engines.
@@ -576,69 +576,113 @@ needs the variables `nnir-namazu-program',
576 576
577Add an entry here when adding a new search engine.") 577Add an entry here when adding a new search engine.")
578 578
579(defcustom nnir-method-default-engines 579(defcustom nnir-method-default-engines '((nnimap . imap) (nttp . gmane))
580 '((nnimap . imap)
581 (nntp . gmane))
582 "*Alist of default search engines keyed by server method." 580 "*Alist of default search engines keyed by server method."
583 :version "24.1" 581 :version "24.1"
582 :group 'nnir
584 :type `(repeat (cons (choice (const nnimap) (const nttp) (const nnspool) 583 :type `(repeat (cons (choice (const nnimap) (const nttp) (const nnspool)
585 (const nneething) (const nndir) (const nnmbox) 584 (const nneething) (const nndir) (const nnmbox)
586 (const nnml) (const nnmh) (const nndraft) 585 (const nnml) (const nnmh) (const nndraft)
587 (const nnfolder) (const nnmaildir)) 586 (const nnfolder) (const nnmaildir))
588 (choice 587 (choice
589 ,@(mapcar (lambda (elem) (list 'const (car elem))) 588 ,@(mapcar (lambda (elem) (list 'const (car elem)))
590 nnir-engines)))) 589 nnir-engines)))))
591 :group 'nnir)
592 590
593;; Gnus glue. 591;; Gnus glue.
594 592
595(defun gnus-group-make-nnir-group (nnir-extra-parms &optional parms) 593(defun gnus-group-make-nnir-group (nnir-extra-parms &optional specs)
596 "Create an nnir group. Asks for query." 594 "Create an nnir group. Prompt for a search query and determine
595the groups to search as follows: if called from the *Server*
596buffer search all groups belonging to the server on the current
597line; if called from the *Group* buffer search any marked groups,
598or the group on the current line, or all the groups under the
599current topic. Calling with a prefix-arg prompts for additional
600search-engine specific constraints. A non-nil `specs' arg must be
601an alist with `nnir-query-spec' and `nnir-group-spec' keys, and
602skips all prompting."
597 (interactive "P") 603 (interactive "P")
598 (setq nnir-current-query nil 604 (let* ((group-spec
599 nnir-current-server nil 605 (or (cdr (assoc 'nnir-group-spec specs))
600 nnir-current-group-marked nil 606 (if (gnus-server-server-name)
601 nnir-artlist nil) 607 (list (list (gnus-server-server-name)))
602 (let* ((query (unless parms (read-string "Query: " nil 'nnir-search-history))) 608 (nnir-categorize
603 (parms (or parms (list (cons 'query query)))) 609 (or gnus-group-marked
604 (srv (or (cdr (assq 'server parms)) (gnus-server-server-name) "nnir"))) 610 (if (gnus-group-group-name)
605 (add-to-list 'parms (cons 'unique-id (message-unique-id)) t) 611 (list (gnus-group-group-name))
612 (cdr (assoc (gnus-group-topic-name) gnus-topic-alist))))
613 gnus-group-server))))
614 (query-spec
615 (or (cdr (assoc 'nnir-query-spec specs))
616 (apply
617 'append
618 (list (cons 'query
619 (read-string "Query: " nil 'nnir-search-history)))
620 (when nnir-extra-parms
621 (mapcar
622 (lambda (x)
623 (nnir-read-parms (nnir-server-to-search-engine (car x))))
624 group-spec))))))
606 (gnus-group-read-ephemeral-group 625 (gnus-group-read-ephemeral-group
607 (concat "nnir:" (prin1-to-string parms)) (list 'nnir srv) t 626 (concat "nnir-" (message-unique-id))
608 (cons (current-buffer) gnus-current-window-configuration) 627 (list 'nnir "nnir")
609 nil))) 628 nil
629; (cons (current-buffer) gnus-current-window-configuration)
630 nil
631 nil nil
632 (list
633 (cons 'nnir-specs (list (cons 'nnir-query-spec query-spec)
634 (cons 'nnir-group-spec group-spec)))
635 (cons 'nnir-artlist nil)))))
636
637(defun gnus-summary-make-nnir-group (nnir-extra-parms)
638 "Search a group from the summary buffer."
639 (interactive "P")
640 (gnus-warp-to-article)
641 (let ((spec
642 (list
643 (cons 'nnir-group-spec
644 (list (list
645 (gnus-group-server gnus-newsgroup-name)
646 (list gnus-newsgroup-name)))))))
647 (gnus-group-make-nnir-group nnir-extra-parms spec)))
610 648
611 649
612;; Gnus backend interface functions. 650;; Gnus backend interface functions.
613 651
614(deffoo nnir-open-server (server &optional definitions) 652(deffoo nnir-open-server (server &optional definitions)
615 ;; Just set the server variables appropriately. 653 ;; Just set the server variables appropriately.
616 (add-hook 'gnus-summary-mode-hook 'nnir-mode) 654 (let ((backend (car (gnus-server-to-method server))))
617 (nnoo-change-server 'nnir server definitions)) 655 (if backend
618 656 (nnoo-change-server backend server definitions)
619(deffoo nnir-request-group (group &optional server fast info) 657 (add-hook 'gnus-summary-mode-hook 'nnir-mode)
620 "GROUP is the query string." 658 (nnoo-change-server 'nnir server definitions))))
621 (nnir-possibly-change-server server) 659
622 ;; Check for cache and return that if appropriate. 660(deffoo nnir-request-group (group &optional server dont-check info)
623 (if (and (equal group nnir-current-query) 661 (nnir-possibly-change-group group server)
624 (equal gnus-group-marked nnir-current-group-marked) 662 (let ((pgroup (if (gnus-group-prefixed-p group)
625 (or (null server) 663 group
626 (equal server nnir-current-server))) 664 (gnus-group-prefixed-name group '(nnir "nnir"))))
627 nnir-artlist 665 length)
628 ;; Cache miss. 666 ;; Check for cached search result or run the query and cache the
629 (setq nnir-artlist (nnir-run-query group))) 667 ;; result.
630 (with-current-buffer nntp-server-buffer 668 (unless (and nnir-artlist dont-check)
631 (setq nnir-current-query group) 669 (gnus-group-set-parameter
632 (when server (setq nnir-current-server server)) 670 pgroup 'nnir-artlist
633 (setq nnir-current-group-marked gnus-group-marked) 671 (setq nnir-artlist
634 (if (zerop (length nnir-artlist)) 672 (nnir-run-query
635 (nnheader-report 'nnir "Search produced empty results.") 673 (gnus-group-get-parameter pgroup 'nnir-specs t))))
636 ;; Remember data for cache. 674 (nnir-request-update-info pgroup (gnus-get-info pgroup)))
637 (nnheader-insert "211 %d %d %d %s\n" 675 (with-current-buffer nntp-server-buffer
638 (nnir-artlist-length nnir-artlist) ; total # 676 (if (zerop (setq length (nnir-artlist-length nnir-artlist)))
639 1 ; first # 677 (progn
640 (nnir-artlist-length nnir-artlist) ; last # 678 (nnir-close-group group)
641 group)))) ; group name 679 (nnheader-report 'nnir "Search produced empty results."))
680 (nnheader-insert "211 %d %d %d %s\n"
681 length ; total #
682 1 ; first #
683 length ; last #
684 group)))) ; group name
685 nnir-artlist)
642 686
643(deffoo nnir-retrieve-headers (articles &optional group server fetch-old) 687(deffoo nnir-retrieve-headers (articles &optional group server fetch-old)
644 (with-current-buffer nntp-server-buffer 688 (with-current-buffer nntp-server-buffer
@@ -654,13 +698,7 @@ Add an entry here when adding a new search engine.")
654 (server (gnus-group-server artgroup)) 698 (server (gnus-group-server artgroup))
655 (gnus-override-method (gnus-server-to-method server)) 699 (gnus-override-method (gnus-server-to-method server))
656 parsefunc) 700 parsefunc)
657 ;; (or (numberp art) 701 ;; (nnir-possibly-change-group nil server)
658 ;; (nnheader-report
659 ;; 'nnir
660 ;; "nnir-retrieve-headers doesn't grok message ids: %s"
661 ;; art))
662 (nnir-possibly-change-server server)
663 ;; is this needed?
664 (erase-buffer) 702 (erase-buffer)
665 (case (setq gnus-headers-retrieved-by 703 (case (setq gnus-headers-retrieved-by
666 (or 704 (or
@@ -694,6 +732,7 @@ Add an entry here when adding a new search engine.")
694 'nov))) 732 'nov)))
695 733
696(deffoo nnir-request-article (article &optional group server to-buffer) 734(deffoo nnir-request-article (article &optional group server to-buffer)
735 (nnir-possibly-change-group group server)
697 (if (and (stringp article) 736 (if (and (stringp article)
698 (not (eq 'nnimap (car (gnus-server-to-method server))))) 737 (not (eq 'nnimap (car (gnus-server-to-method server)))))
699 (nnheader-report 738 (nnheader-report
@@ -702,35 +741,35 @@ Add an entry here when adding a new search engine.")
702 server) 741 server)
703 (save-excursion 742 (save-excursion
704 (let ((article article) 743 (let ((article article)
705 query) 744 query)
706 (when (stringp article) 745 (when (stringp article)
707 (setq gnus-override-method (gnus-server-to-method server)) 746 (setq gnus-override-method (gnus-server-to-method server))
708 (setq query 747 (setq query
709 (list 748 (list
710 (cons 'query (format "HEADER Message-ID %s" article)) 749 (cons 'query (format "HEADER Message-ID %s" article))
711 (cons 'unique-id article) 750 (cons 'criteria "")
712 (cons 'criteria "") 751 (cons 'shortcut t)))
713 (cons 'shortcut t))) 752 (unless (and nnir-artlist (equal query nnir-memo-query)
714 (unless (and (equal query nnir-current-query) 753 (equal server nnir-memo-server))
715 (equal server nnir-current-server)) 754 (setq nnir-artlist (nnir-run-imap query server)
716 (setq nnir-artlist (nnir-run-imap query server)) 755 nnir-memo-query query
717 (setq nnir-current-query query) 756 nnir-memo-server server))
718 (setq nnir-current-server server)) 757 (setq article 1))
719 (setq article 1)) 758 (unless (zerop (nnir-artlist-length nnir-artlist))
720 (unless (zerop (length nnir-artlist)) 759 (let ((artfullgroup (nnir-article-group article))
721 (let ((artfullgroup (nnir-article-group article)) 760 (artno (nnir-article-number article)))
722 (artno (nnir-article-number article))) 761 (message "Requesting article %d from group %s"
723 (message "Requesting article %d from group %s" 762 artno artfullgroup)
724 artno artfullgroup) 763 (if to-buffer
725 (if to-buffer 764 (with-current-buffer to-buffer
726 (with-current-buffer to-buffer 765 (let ((gnus-article-decode-hook nil))
727 (let ((gnus-article-decode-hook nil)) 766 (gnus-request-article-this-buffer artno artfullgroup)))
728 (gnus-request-article-this-buffer artno artfullgroup))) 767 (gnus-request-article artno artfullgroup))
729 (gnus-request-article artno artfullgroup)) 768 (cons artfullgroup artno)))))))
730 (cons artfullgroup artno)))))))
731 769
732(deffoo nnir-request-move-article (article group server accept-form 770(deffoo nnir-request-move-article (article group server accept-form
733 &optional last internal-move-group) 771 &optional last internal-move-group)
772 (nnir-possibly-change-group group server)
734 (let* ((artfullgroup (nnir-article-group article)) 773 (let* ((artfullgroup (nnir-article-group article))
735 (artno (nnir-article-number article)) 774 (artno (nnir-article-number article))
736 (to-newsgroup (nth 1 accept-form)) 775 (to-newsgroup (nth 1 accept-form))
@@ -751,6 +790,7 @@ Add an entry here when adding a new search engine.")
751 (gnus-group-real-name to-newsgroup))))) 790 (gnus-group-real-name to-newsgroup)))))
752 791
753(deffoo nnir-request-expire-articles (articles group &optional server force) 792(deffoo nnir-request-expire-articles (articles group &optional server force)
793 (nnir-possibly-change-group group server)
754 (if force 794 (if force
755 (let ((articles-by-group (nnir-categorize 795 (let ((articles-by-group (nnir-categorize
756 articles nnir-article-group nnir-article-ids)) 796 articles nnir-article-group nnir-article-ids))
@@ -772,20 +812,79 @@ Add an entry here when adding a new search engine.")
772 articles)) 812 articles))
773 813
774(deffoo nnir-warp-to-article () 814(deffoo nnir-warp-to-article ()
815 (nnir-possibly-change-group gnus-newsgroup-name)
775 (let* ((cur (if (> (gnus-summary-article-number) 0) 816 (let* ((cur (if (> (gnus-summary-article-number) 0)
776 (gnus-summary-article-number) 817 (gnus-summary-article-number)
777 (error "This is not a real article"))) 818 (error "Can't warp to a pseudo-article")))
778 (backend-article-group (nnir-article-group cur)) 819 (backend-article-group (nnir-article-group cur))
779 (backend-article-number (nnir-article-number cur)) 820 (backend-article-number (nnir-article-number cur))
780 (quit-config (gnus-ephemeral-group-p gnus-newsgroup-name))) 821 (quit-config (gnus-ephemeral-group-p gnus-newsgroup-name)))
781 ;; first exit from the nnir summary buffer. 822
782 (gnus-summary-exit) 823 ;; what should we do here? we could leave all the buffers around
824 ;; and assume that we have to exit from them one by one. or we can
825 ;; try to clean up directly
826
827 ;;first exit from the nnir summary buffer.
828; (gnus-summary-exit)
783 ;; and if the nnir summary buffer in turn came from another 829 ;; and if the nnir summary buffer in turn came from another
784 ;; summary buffer we have to clean that summary up too. 830 ;; summary buffer we have to clean that summary up too.
785 (when (eq (cdr quit-config) 'summary) 831 ; (when (not (eq (cdr quit-config) 'group))
786 (gnus-summary-exit)) 832; (gnus-summary-exit))
787 (gnus-summary-read-group-1 backend-article-group t t nil 833 (gnus-summary-read-group-1 backend-article-group t t nil
788 nil (list backend-article-number)))) 834 nil (list backend-article-number))))
835
836
837(deffoo nnir-request-update-info (group info &optional server)
838 (let ((articles-by-group
839 (nnir-categorize
840 (number-sequence 1 (nnir-artlist-length nnir-artlist))
841 nnir-article-group nnir-article-ids)))
842 (gnus-set-active group
843 (cons 1 (nnir-artlist-length nnir-artlist)))
844 (while (not (null articles-by-group))
845 (let* ((group-articles (pop articles-by-group))
846 (articleids (reverse (cadr group-articles)))
847 (group-info (gnus-get-info (car group-articles)))
848 (marks (gnus-info-marks group-info))
849 (read (gnus-info-read group-info)))
850 (gnus-info-set-read
851 info
852 (gnus-add-to-range
853 (gnus-info-read info)
854 (remove nil (mapcar (lambda (art)
855 (let ((num (cdr art)))
856 (when (gnus-member-of-range num read)
857 (car art)))) articleids))))
858 (mapc (lambda (mark)
859 (let ((type (car mark))
860 (range (cdr mark)))
861 (gnus-add-marked-articles
862 group
863 type
864 (remove nil
865 (mapcar
866 (lambda (art)
867 (let ((num (cdr art)))
868 (when (gnus-member-of-range num range)
869 (car art))))
870 articleids))))) marks)))))
871
872
873(deffoo nnir-close-group (group &optional server)
874 (let ((pgroup (if (gnus-group-prefixed-p group)
875 group
876 (gnus-group-prefixed-name group '(nnir "nnir")))))
877 (when (and nnir-artlist (not (gnus-ephemeral-group-p pgroup)))
878 (gnus-group-set-parameter pgroup 'nnir-artlist nnir-artlist))
879 (setq nnir-artlist nil)
880 (when (gnus-ephemeral-group-p pgroup)
881 (gnus-kill-ephemeral-group pgroup)
882 (setq gnus-ephemeral-servers
883 (delq (assq 'nnir gnus-ephemeral-servers)
884 gnus-ephemeral-servers)))))
885;; (gnus-opened-servers-remove
886;; (car (assoc '(nnir "nnir-ephemeral" (nnir-address "nnir"))
887;; gnus-opened-servers))))
789 888
790(nnoo-define-skeleton nnir) 889(nnoo-define-skeleton nnir)
791 890
@@ -813,7 +912,7 @@ ready to be added to the list of search results."
813 ;; remove trailing slash and, for nnmaildir, cur/new/tmp 912 ;; remove trailing slash and, for nnmaildir, cur/new/tmp
814 (setq dirnam 913 (setq dirnam
815 (substring dirnam 0 914 (substring dirnam 0
816 (if (string-match "^nnmaildir:" (gnus-group-server server)) 915 (if (string-match "\\`nnmaildir:" (gnus-group-server server))
817 -5 -1))) 916 -5 -1)))
818 917
819 ;; Set group to dirnam without any leading dots or slashes, 918 ;; Set group to dirnam without any leading dots or slashes,
@@ -823,7 +922,7 @@ ready to be added to the list of search results."
823 "[/\\]" "." t))) 922 "[/\\]" "." t)))
824 923
825 (vector (gnus-group-full-name group server) 924 (vector (gnus-group-full-name group server)
826 (if (string-match "^nnmaildir:" (gnus-group-server server)) 925 (if (string-match "\\`nnmaildir:" (gnus-group-server server))
827 (nnmaildir-base-name-to-article-number 926 (nnmaildir-base-name-to-article-number
828 (substring article 0 (string-match ":" article)) 927 (substring article 0 (string-match ":" article))
829 group nil) 928 group nil)
@@ -850,35 +949,36 @@ details on the language and supported extensions."
850 (apply 949 (apply
851 'vconcat 950 'vconcat
852 (catch 'found 951 (catch 'found
853 (mapcar 952 (mapcar
854 (lambda (group) 953 (lambda (group)
855 (let (artlist) 954 (let (artlist)
856 (condition-case () 955 (condition-case ()
857 (when (nnimap-possibly-change-group 956 (when (nnimap-possibly-change-group
858 (gnus-group-short-name group) server) 957 (gnus-group-short-name group) server)
859 (with-current-buffer (nnimap-buffer) 958 (with-current-buffer (nnimap-buffer)
860 (message "Searching %s..." group) 959 (message "Searching %s..." group)
861 (let ((arts 0) 960 (let ((arts 0)
862 (result (nnimap-command "UID SEARCH %s" 961 (result (nnimap-command "UID SEARCH %s"
863 (if (string= criteria "") 962 (if (string= criteria "")
864 qstring 963 qstring
865 (nnir-imap-make-query 964 (nnir-imap-make-query
866 criteria qstring))))) 965 criteria qstring)))))
867 (mapc 966 (mapc
868 (lambda (artnum) 967 (lambda (artnum)
869 (let ((artn (string-to-number artnum))) 968 (let ((artn (string-to-number artnum)))
870 (when (> artn 0) 969 (when (> artn 0)
871 (push (vector group artn 100) 970 (push (vector group artn 100)
872 artlist) 971 artlist)
873 (when (assq 'shortcut query) 972 (when (assq 'shortcut query)
874 (throw 'found (list artlist))) 973 (throw 'found (list artlist)))
875 (setq arts (1+ arts))))) 974 (setq arts (1+ arts)))))
876 (and (car result) (cdr (assoc "SEARCH" (cdr result))))) 975 (and (car result)
877 (message "Searching %s... %d matches" group arts))) 976 (cdr (assoc "SEARCH" (cdr result)))))
878 (message "Searching %s...done" group)) 977 (message "Searching %s... %d matches" group arts)))
879 (quit nil)) 978 (message "Searching %s...done" group))
880 (nreverse artlist))) 979 (quit nil))
881 groups)))))) 980 (nreverse artlist)))
981 groups))))))
882 982
883(defun nnir-imap-make-query (criteria qstring) 983(defun nnir-imap-make-query (criteria qstring)
884 "Parse the query string and criteria into an appropriate IMAP search 984 "Parse the query string and criteria into an appropriate IMAP search
@@ -1073,14 +1173,14 @@ Windows NT 4.0."
1073 1173
1074 (save-excursion 1174 (save-excursion
1075 (let ( (qstring (cdr (assq 'query query))) 1175 (let ( (qstring (cdr (assq 'query query)))
1076 (groupspec (cdr (assq 'group query))) 1176 (groupspec (cdr (assq 'swish++-group query)))
1077 (prefix (nnir-read-server-parm 'nnir-swish++-remove-prefix server)) 1177 (prefix (nnir-read-server-parm 'nnir-swish++-remove-prefix server))
1078 artlist 1178 artlist
1079 ;; nnml-use-compressed-files might be any string, but probably this 1179 ;; nnml-use-compressed-files might be any string, but probably this
1080 ;; is sufficient. Note that we can't only use the value of 1180 ;; is sufficient. Note that we can't only use the value of
1081 ;; nnml-use-compressed-files because old articles might have been 1181 ;; nnml-use-compressed-files because old articles might have been
1082 ;; saved with a different value. 1182 ;; saved with a different value.
1083 (article-pattern (if (string-match "^nnmaildir:" 1183 (article-pattern (if (string-match "\\`nnmaildir:"
1084 (gnus-group-server server)) 1184 (gnus-group-server server))
1085 ":[0-9]+" 1185 ":[0-9]+"
1086 "^[0-9]+\\(\\.[a-z0-9]+\\)?$")) 1186 "^[0-9]+\\(\\.[a-z0-9]+\\)?$"))
@@ -1247,7 +1347,7 @@ Tested with swish-e-2.0.1 on Windows NT 4.0."
1247(defun nnir-run-hyrex (query server &optional group) 1347(defun nnir-run-hyrex (query server &optional group)
1248 (save-excursion 1348 (save-excursion
1249 (let ((artlist nil) 1349 (let ((artlist nil)
1250 (groupspec (cdr (assq 'group query))) 1350 (groupspec (cdr (assq 'hyrex-group query)))
1251 (qstring (cdr (assq 'query query))) 1351 (qstring (cdr (assq 'query query)))
1252 (prefix (nnir-read-server-parm 'nnir-hyrex-remove-prefix server)) 1352 (prefix (nnir-read-server-parm 'nnir-hyrex-remove-prefix server))
1253 score artno dirnam) 1353 score artno dirnam)
@@ -1323,7 +1423,7 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1323 ;; (when group 1423 ;; (when group
1324 ;; (error "The Namazu backend cannot search specific groups")) 1424 ;; (error "The Namazu backend cannot search specific groups"))
1325 (save-excursion 1425 (save-excursion
1326 (let ((article-pattern (if (string-match "^nnmaildir:" 1426 (let ((article-pattern (if (string-match "\\`nnmaildir:"
1327 (gnus-group-server server)) 1427 (gnus-group-server server))
1328 ":[0-9]+" 1428 ":[0-9]+"
1329 "^[0-9]+$")) 1429 "^[0-9]+$"))
@@ -1394,10 +1494,10 @@ actually)."
1394 1494
1395 (save-excursion 1495 (save-excursion
1396 (let ( (qstring (cdr (assq 'query query))) 1496 (let ( (qstring (cdr (assq 'query query)))
1397 (groupspec (cdr (assq 'group query))) 1497 (groupspec (cdr (assq 'notmuch-group query)))
1398 (prefix (nnir-read-server-parm 'nnir-notmuch-remove-prefix server)) 1498 (prefix (nnir-read-server-parm 'nnir-notmuch-remove-prefix server))
1399 artlist 1499 artlist
1400 (article-pattern (if (string-match "^nnmaildir:" 1500 (article-pattern (if (string-match "\\`nnmaildir:"
1401 (gnus-group-server server)) 1501 (gnus-group-server server))
1402 ":[0-9]+" 1502 ":[0-9]+"
1403 "^[0-9]+$")) 1503 "^[0-9]+$"))
@@ -1467,24 +1567,23 @@ actually)."
1467 (directory (cadr (assoc sym (cddr method)))) 1567 (directory (cadr (assoc sym (cddr method))))
1468 (regexp (cdr (assoc 'query query))) 1568 (regexp (cdr (assoc 'query query)))
1469 (grep-options (cdr (assoc 'grep-options query))) 1569 (grep-options (cdr (assoc 'grep-options query)))
1470 (grouplist (or grouplist (nnir-get-active server))) 1570 (grouplist (or grouplist (nnir-get-active server))))
1471 artlist)
1472 (unless directory 1571 (unless directory
1473 (error "No directory found in method specification of server %s" 1572 (error "No directory found in method specification of server %s"
1474 server)) 1573 server))
1475 (apply 1574 (apply
1476 'vconcat 1575 'vconcat
1477 (mapcar (lambda (x) 1576 (mapcar (lambda (x)
1478 (let ((group x)) 1577 (let ((group x)
1578 artlist)
1479 (message "Searching %s using find-grep..." 1579 (message "Searching %s using find-grep..."
1480 (or group server)) 1580 (or group server))
1481 (save-window-excursion 1581 (save-window-excursion
1482 (set-buffer (get-buffer-create nnir-tmp-buffer)) 1582 (set-buffer (get-buffer-create nnir-tmp-buffer))
1483 (erase-buffer)
1484 (if (> gnus-verbose 6) 1583 (if (> gnus-verbose 6)
1485 (pop-to-buffer (current-buffer))) 1584 (pop-to-buffer (current-buffer)))
1486 (cd directory) ; Using relative paths simplifies 1585 (cd directory) ; Using relative paths simplifies
1487 ; postprocessing. 1586 ; postprocessing.
1488 (let ((group 1587 (let ((group
1489 (if (not group) 1588 (if (not group)
1490 "." 1589 "."
@@ -1507,7 +1606,8 @@ actually)."
1507 (save-excursion 1606 (save-excursion
1508 (apply 1607 (apply
1509 'call-process "find" nil t 1608 'call-process "find" nil t
1510 "find" group "-type" "f" "-name" "[0-9]*" "-exec" 1609 "find" group "-maxdepth" "1" "-type" "f"
1610 "-name" "[0-9]*" "-exec"
1511 "grep" 1611 "grep"
1512 `("-l" ,@(and grep-options 1612 `("-l" ,@(and grep-options
1513 (split-string grep-options "\\s-" t)) 1613 (split-string grep-options "\\s-" t))
@@ -1557,8 +1657,8 @@ actually)."
1557 (error "Can't search non-gmane groups: %s" x))) 1657 (error "Can't search non-gmane groups: %s" x)))
1558 groups " ")) 1658 groups " "))
1559 (authorspec 1659 (authorspec
1560 (if (assq 'author query) 1660 (if (assq 'gmane-author query)
1561 (format "author:%s" (cdr (assq 'author query))) "")) 1661 (format "author:%s" (cdr (assq 'gmane-author query))) ""))
1562 (search (format "%s %s %s" 1662 (search (format "%s %s %s"
1563 qstring groupspec authorspec)) 1663 qstring groupspec authorspec))
1564 (gnus-inhibit-demon t) 1664 (gnus-inhibit-demon t)
@@ -1594,11 +1694,10 @@ actually)."
1594 1694
1595;;; Util Code: 1695;;; Util Code:
1596 1696
1597(defun nnir-read-parms (query nnir-search-engine) 1697(defun nnir-read-parms (nnir-search-engine)
1598 "Reads additional search parameters according to `nnir-engines'." 1698 "Reads additional search parameters according to `nnir-engines'."
1599 (let ((parmspec (caddr (assoc nnir-search-engine nnir-engines)))) 1699 (let ((parmspec (caddr (assoc nnir-search-engine nnir-engines))))
1600 (append query 1700 (mapcar 'nnir-read-parm parmspec)))
1601 (mapcar 'nnir-read-parm parmspec))))
1602 1701
1603(defun nnir-read-parm (parmspec) 1702(defun nnir-read-parm (parmspec)
1604 "Reads a single search parameter. 1703 "Reads a single search parameter.
@@ -1612,46 +1711,23 @@ actually)."
1612 (cons sym (format (cdr mapping) result))) 1711 (cons sym (format (cdr mapping) result)))
1613 (cons sym (read-string prompt))))) 1712 (cons sym (read-string prompt)))))
1614 1713
1615(autoload 'gnus-group-topic-name "gnus-topic") 1714(defun nnir-run-query (specs)
1616 1715 "Invoke appropriate search engine function (see `nnir-engines')."
1617(defun nnir-run-query (query) 1716 (apply 'vconcat
1618 "Invoke appropriate search engine function (see `nnir-engines'). 1717 (mapcar
1619 If some groups were process-marked, run the query for each of the groups 1718 (lambda (x)
1620 and concat the results." 1719 (let* ((server (car x))
1621 (let ((q (car (read-from-string query))) 1720 (search-engine (nnir-server-to-search-engine server))
1622 (groups (if (not (string= "nnir" nnir-address)) 1721 (search-func (cadr (assoc search-engine nnir-engines))))
1623 (list (list nnir-address)) 1722 (and search-func
1624 (nnir-categorize 1723 (funcall search-func (cdr (assq 'nnir-query-spec specs))
1625 (or gnus-group-marked 1724 server (cadr x)))))
1626 (if (gnus-group-group-name) 1725 (cdr (assq 'nnir-group-spec specs)))))
1627 (list (gnus-group-group-name)) 1726
1628 (cdr (assoc (gnus-group-topic-name) 1727(defun nnir-server-to-search-engine (server)
1629 gnus-topic-alist)))) 1728 (or (nnir-read-server-parm 'nnir-search-engine server t)
1630 gnus-group-server)))) 1729 (cdr (assoc (car (gnus-server-to-method server))
1631 (apply 'vconcat 1730 nnir-method-default-engines))))
1632 (mapcar
1633 (lambda (x)
1634 (let* ((server (car x))
1635 (nnir-search-engine
1636 (or (nnir-read-server-parm 'nnir-search-engine
1637 server t)
1638 (cdr (assoc (car
1639 (gnus-server-to-method server))
1640 nnir-method-default-engines))))
1641 search-func)
1642 (setq search-func (cadr (assoc nnir-search-engine
1643 nnir-engines)))
1644 (if search-func
1645 (funcall
1646 search-func
1647 (if nnir-extra-parms
1648 (or (and (eq nnir-search-engine 'imap)
1649 (assq 'criteria q) q)
1650 (setq q (nnir-read-parms q nnir-search-engine)))
1651 q)
1652 server (cadr x))
1653 nil)))
1654 groups))))
1655 1731
1656(defun nnir-read-server-parm (key server &optional not-global) 1732(defun nnir-read-server-parm (key server &optional not-global)
1657 "Returns the parameter value corresponding to `key' for 1733 "Returns the parameter value corresponding to `key' for
@@ -1663,36 +1739,43 @@ environment unless `not-global' is non-nil."
1663 ((and (not not-global) (boundp key)) (symbol-value key)) 1739 ((and (not not-global) (boundp key)) (symbol-value key))
1664 (t nil)))) 1740 (t nil))))
1665 1741
1742(defun nnir-possibly-change-group (group &optional server)
1743 (or (not server) (nnir-server-opened server) (nnir-open-server server))
1744 (when (and group (string-match "\\`nnir" group))
1745 (setq nnir-artlist (gnus-group-get-parameter
1746 (gnus-group-prefixed-name
1747 (gnus-group-short-name group) '(nnir "nnir"))
1748 'nnir-artlist t))))
1666 1749
1667(defun nnir-possibly-change-server (server) 1750(defun nnir-server-opened (&optional server)
1668 (unless (and server (nnir-server-opened server)) 1751 (let ((backend (car (gnus-server-to-method server))))
1669 (nnir-open-server server))) 1752 (nnoo-current-server-p (or backend 'nnir) server)))
1670
1671 1753
1672(defun nnir-search-thread (header) 1754(defun nnir-search-thread (header)
1673 "Make an nnir group based on the thread containing the article header" 1755 "Make an nnir group based on the thread containing the article
1674 (let ((parm (list 1756header. The current server will be searched. If the registry is
1675 (cons 'query 1757installed, the server that the registry reports the current
1676 (nnimap-make-thread-query header)) 1758article came from is also searched."
1677 (cons 'criteria "") 1759 (let* ((query
1678 (cons 'server (gnus-method-to-server 1760 (list (cons 'query (nnimap-make-thread-query header))
1679 (gnus-find-method-for-group 1761 (cons 'criteria "")))
1680 gnus-newsgroup-name)))))) 1762 (server
1681 (gnus-group-make-nnir-group nil parm) 1763 (list (list (gnus-method-to-server
1764 (gnus-find-method-for-group gnus-newsgroup-name)))))
1765 (registry-group (and
1766 (gnus-bound-and-true-p 'gnus-registry-enabled)
1767 (car (gnus-registry-get-id-key
1768 (mail-header-id header) 'group))))
1769 (registry-server
1770 (and registry-group
1771 (gnus-method-to-server
1772 (gnus-find-method-for-group registry-group)))))
1773 (when registry-server (add-to-list 'server (list registry-server)))
1774 (gnus-group-make-nnir-group nil (list
1775 (cons 'nnir-query-spec query)
1776 (cons 'nnir-group-spec server)))
1682 (gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header))))) 1777 (gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header)))))
1683 1778
1684;; unused?
1685(defun nnir-artlist-groups (artlist)
1686 "Returns a list of all groups in the given ARTLIST."
1687 (let ((res nil)
1688 (with-dups nil))
1689 ;; from each artitem, extract group component
1690 (setq with-dups (mapcar 'nnir-artitem-group artlist))
1691 ;; remove duplicates from above
1692 (mapc (function (lambda (x) (add-to-list 'res x)))
1693 with-dups)
1694 res))
1695
1696(defun nnir-get-active (srv) 1779(defun nnir-get-active (srv)
1697 (let ((method (gnus-server-to-method srv)) 1780 (let ((method (gnus-server-to-method srv))
1698 groups) 1781 groups)
@@ -1758,6 +1841,46 @@ environment unless `not-global' is non-nil."
1758 1841
1759 1842
1760 1843
1844(deffoo nnir-request-create-group (group &optional server args)
1845 (message "Creating nnir group %s" group)
1846 (let ((group (gnus-group-prefixed-name group '(nnir "nnir")))
1847 (query-spec
1848 (list (cons 'query
1849 (read-string "Query: " nil 'nnir-search-history))))
1850 (group-spec (list (list (read-string "Server: " nil nil)))))
1851 (gnus-group-set-parameter
1852 group 'nnir-specs
1853 (list (cons 'nnir-query-spec query-spec)
1854 (cons 'nnir-group-spec group-spec)))
1855 (gnus-group-set-parameter
1856 group 'nnir-artlist
1857 (setq nnir-artlist
1858 (nnir-run-query
1859 (list (cons 'nnir-query-spec query-spec)
1860 (cons 'nnir-group-spec group-spec)))))
1861 (nnir-request-update-info group (gnus-get-info group)))
1862 t)
1863
1864(deffoo nnir-request-delete-group (group &optional force server)
1865 t)
1866
1867(deffoo nnir-request-list (&optional server)
1868 t)
1869
1870(deffoo nnir-request-scan (group method)
1871 (if group
1872 (let ((pgroup (if (gnus-group-prefixed-p group)
1873 group
1874 (gnus-group-prefixed-name group '(nnir "nnir")))))
1875 (gnus-group-set-parameter
1876 pgroup 'nnir-artlist
1877 (setq nnir-artlist
1878 (nnir-run-query
1879 (gnus-group-get-parameter pgroup 'nnir-specs t))))
1880 (nnir-request-update-info pgroup (gnus-get-info pgroup)))
1881 t))
1882
1883
1761;; The end. 1884;; The end.
1762(provide 'nnir) 1885(provide 'nnir)
1763 1886