aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGnus developers2010-10-31 00:13:12 +0000
committerKatsumi Yamaoka2010-10-31 00:13:12 +0000
commit953d41c48214643adaca4e51ca80f67a05719f1b (patch)
treea8a8f3914fc6b229ea6c5d0a813aff753e7e0fa0
parent8a500a91a222c6c8e9ae6c72e233f1512520504a (diff)
downloademacs-953d41c48214643adaca4e51ca80f67a05719f1b.tar.gz
emacs-953d41c48214643adaca4e51ca80f67a05719f1b.zip
Merge changes made in Gnus trunk.
nnir.el: General clean-up, and reimplementation of various bits. nnir.el (nnir-search-engine): Ressurect variable, since it's used later in the file. shr.el (shr-generic): The text nodes should be text, not :text. nnir.el: Move defvars around to silence compiler warnings. shr.el (shr-tag-img): Output "*" instead of "[img]".
-rw-r--r--lisp/gnus/ChangeLog36
-rw-r--r--lisp/gnus/nnir.el940
-rw-r--r--lisp/gnus/shr.el6
3 files changed, 494 insertions, 488 deletions
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index ab16707d386..a488a164302 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,39 @@
12010-10-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
2
3 * shr.el (shr-tag-img): Output "*" instead of "[img]".
4
52010-10-30 Andrew Cohen <cohen@andy.bu.edu>
6
7 * nnir.el move defvar, defcustom around to keep file organized and keep
8 byte-compiler quiet.
9 (nnir-read-parms): accept search-engine as arg.
10 (nnir-run-query): pass search-engine as arg.
11 (nnir-search-engine): remove.
12
132010-10-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
14
15 * shr.el (shr-generic): The text nodes should be text, not :text.
16
17 * nnir.el (nnir-search-engine): Ressurect variable, since it's used
18 later in the file.
19
202010-10-30 Andrew Cohen <cohen@andy.bu.edu>
21
22 * nnir.el: general clean up. allow searching with multiple
23 engines. allow separate extra-parameters for each engine. batch queries
24 when possible.
25 (nnir-imap-default-search-key,nnir-method-default-engines): add
26 customize interface.
27 (nnir-run-gmane): new engine.
28 (nnir-engines): use it. qualify all prompts with engine name.
29 (nnir-search-engine): remove global variable.
30 (nnir-run-hyrex): restore for now.
31 (nnir-extra-parms,nnir-search-history): new variables.
32 (gnus-group-make-nnir-group): use them.
33 (nnir-group-server): remove in favor of gnus-group-server.
34 (nnir-request-group): avoid searching twice.
35 (nnir-sort-groups-by-server): new function.
36
12010-10-30 Julien Danjou <julien@danjou.info> 372010-10-30 Julien Danjou <julien@danjou.info>
2 38
3 * gnus-group.el: Remove gnus-group-fetch-control. 39 * gnus-group.el: Remove gnus-group-fetch-control.
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index adb8d094717..9e3dd9c523f 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -32,161 +32,40 @@
32 32
33;; TODO: Documentation in the Gnus manual 33;; TODO: Documentation in the Gnus manual
34 34
35;; From: Reiner Steib 35;; Where in the existing gnus manual would this fit best?
36;; Subject: Re: Including nnir.el
37;; Newsgroups: gmane.emacs.gnus.general
38;; Message-ID: <v9d5dnp6aq.fsf@marauder.physik.uni-ulm.de>
39;; Date: 2006-06-05 22:49:01 GMT
40;;
41;; On Sun, Jun 04 2006, Sascha Wilde wrote:
42;;
43;; > The one thing most hackers like to forget: Documentation. By now the
44;; > documentation is only in the comments at the head of the source, I
45;; > would use it as basis to cook up some minimal texinfo docs.
46;; >
47;; > Where in the existing gnus manual would this fit best?
48
49;; Maybe (info "(gnus)Combined Groups") for a general description.
50;; `gnus-group-make-nnir-group' might be described in (info
51;; "(gnus)Foreign Groups") as well.
52
53 36
54;; The most recent version of this can always be fetched from the Gnus 37;; What does it do? Well, it allows you to search your mail using
55;; repository. See http://www.gnus.org/ for more information. 38;; some search engine (imap, namazu, swish-e, gmane and others -- see
56 39;; later) by typing `G G' in the Group buffer. You will then get a
57;; This code is still in the development stage but I'd like other 40;; buffer which shows all articles matching the query, sorted by
58;; people to have a look at it. Please do not hesitate to contact me 41;; Retrieval Status Value (score).
59;; with your ideas.
60
61;; What does it do? Well, it allows you to index your mail using some
62;; search engine (freeWAIS-sf, swish-e and others -- see later),
63;; then type `G G' in the Group buffer and issue a query to the search
64;; engine. You will then get a buffer which shows all articles
65;; matching the query, sorted by Retrieval Status Value (score).
66 42
67;; When looking at the retrieval result (in the Summary buffer) you 43;; When looking at the retrieval result (in the Summary buffer) you
68;; can type `G T' (aka M-x gnus-summary-nnir-goto-thread RET) on an 44;; can type `G T' (aka M-x gnus-summary-nnir-goto-thread RET) on an
69;; article. You will be teleported into the group this article came 45;; article. You will be teleported into the group this article came
70;; from, showing the thread this article is part of. (See below for 46;; from, showing the thread this article is part of.
71;; restrictions.)
72
73;; The Lisp installation is simple: just put this file on your
74;; load-path, byte-compile it, and load it from ~/.gnus or something.
75;; This will install a new command `G G' in your Group buffer for
76;; searching your mail. Note that you also need to configure a number
77;; of variables, as described below.
78 47
79;; Restrictions: 48;; The Lisp setup may involve setting a few variables and setting up the
80;;
81;; * This expects that you use nnml or another one-file-per-message backend,
82;; because the others doesn't support nnfolder.
83;; * It can only search the mail backend's which are supported by one
84;; search engine, because of different query languages.
85;; * There are restrictions to the Wais setup.
86;; * There are restrictions to the imap setup.
87;; * gnus-summary-nnir-goto-thread: Fetches whole group first, before
88;; limiting to the right articles. This is much too slow, of
89;; course. May issue a query for number of articles to fetch; you
90;; must accept the default of all articles at this point or things
91;; may break.
92
93;; The Lisp setup involves setting a few variables and setting up the
94;; search engine. You can define the variables in the server definition 49;; search engine. You can define the variables in the server definition
95;; like this : 50;; like this :
96;; (setq gnus-secondary-select-methods '( 51;; (setq gnus-secondary-select-methods '(
97;; (nnimap "" (nnimap-address "localhost") 52;; (nnimap "" (nnimap-address "localhost")
98;; (nnir-search-engine namazu) 53;; (nnir-search-engine namazu)
99;; ))) 54;; )))
100;; Or you can define the global ones. The variables set in the mailer- 55;; The main variable to set is `nnir-search-engine'. Choose one of
101;; definition will be used first. 56;; the engines listed in `nnir-engines'. (Actually `nnir-engines' is
102;; The variable to set is `nnir-search-engine'. Choose one of the engines 57;; an alist, type `C-h v nnir-engines RET' for more information; this
103;; listed in `nnir-engines'. (Actually `nnir-engines' is an alist, 58;; includes examples for setting `nnir-search-engine', too.)
104;; type `C-h v nnir-engines RET' for more information; this includes
105;; examples for setting `nnir-search-engine', too.)
106;;
107;; The variable nnir-mail-backend isn't used anymore.
108;;
109 59
110;; You must also set up a search engine. I'll tell you about the two 60;; If you use one of the local indices (namazu, find-grep, swish) you
111;; search engines currently supported: 61;; must also set up a search engine backend.
112 62
113;; 1. freeWAIS-sf 63;; 1. Namazu
114;;
115;; As always with freeWAIS-sf, you need a so-called `format file'. I
116;; use the following file:
117;;
118;; ,-----
119;; | # Kai's format file for freeWAIS-sf for indexing mails.
120;; | # Each mail is in a file, much like the MH format.
121;; |
122;; | # Document separator should never match -- each file is a document.
123;; | record-sep: /^@this regex should never match@$/
124;; |
125;; | # Searchable fields specification.
126;; |
127;; | region: /^[sS]ubject:/ /^[sS]ubject: */
128;; | subject "Subject header" stemming TEXT BOTH
129;; | end: /^[^ \t]/
130;; |
131;; | region: /^([tT][oO]|[cC][cC]):/ /^([tT][oO]|[cC][cC]): */
132;; | to "To and Cc headers" SOUNDEX BOTH
133;; | end: /^[^ \t]/
134;; |
135;; | region: /^[fF][rR][oO][mM]:/ /^[fF][rR][oO][mM]: */
136;; | from "From header" SOUNDEX BOTH
137;; | end: /^[^ \t]/
138;; |
139;; | region: /^$/
140;; | stemming TEXT GLOBAL
141;; | end: /^@this regex should never match@$/
142;; `-----
143;;
144;; 1998-07-22: waisindex would dump core on me for large articles with
145;; the above settings. I used /^$/ as the end regex for the global
146;; field. That seemed to work okay.
147
148;; There is a Perl module called `WAIS.pm' which is available from
149;; CPAN as well as ls6-ftp.cs.uni-dortmund.de:/pub/wais/Perl. This
150;; module comes with a nifty tool called `makedb', which I use for
151;; indexing. Here's my `makedb.conf':
152;;
153;; ,-----
154;; | # Config file for makedb
155;; |
156;; | # Global options
157;; | waisindex = /usr/local/bin/waisindex
158;; | wais_opt = -stem -t fields
159;; | # `-stem' option necessary when `stemming' is specified for the
160;; | # global field in the *.fmt file
161;; |
162;; | # Own variables
163;; | homedir = /home/kai
164;; |
165;; | # The mail database.
166;; | database = mail
167;; | files = `find $homedir/Mail -name \*[0-9] -print`
168;; | dbdir = $homedir/.wais
169;; | limit = 100
170;; `-----
171;;
172;; The Lisp setup involves the `nnir-wais-*' variables. The most
173;; difficult to understand variable is probably
174;; `nnir-wais-remove-prefix'. Here's what it does: the output of
175;; `waissearch' basically contains the file name and the (full)
176;; directory name. As Gnus works with group names rather than
177;; directory names, the directory name is transformed into a group
178;; name as follows: first, a prefix is removed from the (full)
179;; directory name, then all `/' are replaced with `.'. The variable
180;; `nnir-wais-remove-prefix' should contain a regex matching exactly
181;; this prefix. It defaults to `$HOME/Mail/' (note the trailing
182;; slash).
183
184;; 2. Namazu
185;; 64;;
186;; The Namazu backend requires you to have one directory containing all 65;; The Namazu backend requires you to have one directory containing all
187;; index files, this is controlled by the `nnir-namazu-index-directory' 66;; index files, this is controlled by the `nnir-namazu-index-directory'
188;; variable. To function the `nnir-namazu-remove-prefix' variable must 67;; variable. To function the `nnir-namazu-remove-prefix' variable must
189;; also be correct, see the documentation for `nnir-wais-remove-prefix' 68;; also be correct, see the documentation for `nnir-namazu-remove-prefix'
190;; above. 69;; above.
191;; 70;;
192;; It is particularly important not to pass any any switches to namazu 71;; It is particularly important not to pass any any switches to namazu
@@ -225,7 +104,7 @@
225;; For maximum searching efficiency I have a cron job set to run this 104;; For maximum searching efficiency I have a cron job set to run this
226;; command every four hours. 105;; command every four hours.
227 106
228;; 3. find-grep 107;; 2. find-grep
229;; 108;;
230;; The find-grep engine simply runs find(1) to locate eligible 109;; The find-grep engine simply runs find(1) to locate eligible
231;; articles and searches them with grep(1). This, of course, is much 110;; articles and searches them with grep(1). This, of course, is much
@@ -281,39 +160,7 @@
281;; function should return the list of articles as a vector, as 160;; function should return the list of articles as a vector, as
282;; described above. Then, you need to register this backend in 161;; described above. Then, you need to register this backend in
283;; `nnir-engines'. Then, users can choose the backend by setting 162;; `nnir-engines'. Then, users can choose the backend by setting
284;; `nnir-search-engine'. 163;; `nnir-search-engine' as a server variable.
285
286;; Todo, or future ideas:
287
288;; * It should be possible to restrict search to certain groups.
289;;
290;; * There is currently no error checking.
291;;
292;; * The summary buffer display is currently really ugly, with all the
293;; added information in the subjects. How could I make this
294;; prettier?
295;;
296;; * A function which can be called from an nnir summary buffer which
297;; teleports you into the group the current article came from and
298;; shows you the whole thread this article is part of.
299;; Implementation suggestions?
300;; (1998-07-24: There is now a preliminary implementation, but
301;; it is much too slow and quite fragile.)
302;;
303;; * Support other mail backends. In particular, probably quite a few
304;; people use nnfolder. How would one go about searching nnfolders
305;; and producing the right data needed? The group name and the RSV
306;; are simple, but what about the article number?
307;; - The article number is encoded in the `X-Gnus-Article-Number'
308;; header of each mail.
309;;
310;; * Support compressed mail files. Probably, just stripping off the
311;; `.gz' or `.Z' file name extension is sufficient.
312;;
313;; * At least for imap, the query is performed twice.
314;;
315
316;; Have you got other ideas?
317 164
318;;; Setup Code: 165;;; Setup Code:
319 166
@@ -336,116 +183,27 @@
336 183
337(gnus-declare-backend "nnir" 'mail) 184(gnus-declare-backend "nnir" 'mail)
338 185
339(defvar nnir-imap-default-search-key "Whole message"
340 "The default IMAP search key for an nnir search. Must be one of
341 the keys in nnir-imap-search-arguments. To use raw imap queries
342 by default set this to \"Imap\"")
343
344(defvar nnir-imap-search-arguments
345 '(("Whole message" . "TEXT")
346 ("Subject" . "SUBJECT")
347 ("To" . "TO")
348 ("From" . "FROM")
349 ("Imap" . ""))
350 "Mapping from user readable keys to IMAP search items for use in nnir")
351
352(defvar nnir-imap-search-other "HEADER %S"
353 "The IMAP search item to use for anything other than
354 nnir-imap-search-arguments. By default this is the name of an
355 email header field")
356
357(defvar nnir-imap-search-argument-history ()
358 "The history for querying search options in nnir")
359
360(defvar nnir-get-article-nov-override-function nil
361 "If non-nil, a function that will be passed each search result. This
362should return a message's headers in NOV format.
363
364If this variable is nil, or if the provided function returns nil for a search
365result, `gnus-retrieve-headers' will be called instead.")
366
367(defvar nnir-method-default-engines
368 '((nnimap . imap)
369 (nntp . nil))
370 "Alist of default search engines by server method")
371
372;;; Developer Extension Variable:
373
374(defvar nnir-engines
375 `((wais nnir-run-waissearch
376 ())
377 (imap nnir-run-imap
378 ((criteria
379 "Search in" ; Prompt
380 ,(mapcar 'car nnir-imap-search-arguments) ; alist for completing
381 nil ; allow any user input
382 nil ; initial value
383 nnir-imap-search-argument-history ; the history to use
384 ,nnir-imap-default-search-key ; default
385 )))
386 (swish++ nnir-run-swish++
387 ((group . "Group spec: ")))
388 (swish-e nnir-run-swish-e
389 ((group . "Group spec: ")))
390 (namazu nnir-run-namazu
391 ())
392 (find-grep nnir-run-find-grep
393 ((grep-options . "Grep options: "))))
394 "Alist of supported search engines.
395Each element in the alist is a three-element list (ENGINE FUNCTION ARGS).
396ENGINE is a symbol designating the searching engine. FUNCTION is also
397a symbol, giving the function that does the search. The third element
398ARGS is a list of cons pairs (PARAM . PROMPT). When issuing a query,
399the FUNCTION will issue a query for each of the PARAMs, using PROMPT.
400
401The value of `nnir-search-engine' must be one of the ENGINE symbols.
402For example, use the following line for searching using freeWAIS-sf:
403 (setq nnir-search-engine 'wais)
404Use the following line if you read your mail via IMAP and your IMAP
405server supports searching:
406 (setq nnir-search-engine 'imap)
407Note that you have to set additional variables for most backends. For
408example, the `wais' backend needs the variables `nnir-wais-program',
409`nnir-wais-database' and `nnir-wais-remove-prefix'.
410
411Add an entry here when adding a new search engine.")
412 186
413;;; User Customizable Variables: 187;;; User Customizable Variables:
414 188
415(defgroup nnir nil 189(defgroup nnir nil
416 "Search nnmh and nnml groups in Gnus with swish-e, freeWAIS-sf, or EWS." 190 "Search groups in Gnus with assorted seach engines."
417 :group 'gnus) 191 :group 'gnus)
418 192
419;; Mail backend. 193(defcustom nnir-method-default-engines
420 194 '((nnimap . imap)
421;; TODO: 195 (nntp . gmane))
422;; If `nil', use server parameters to find out which server to search. CCC 196 "*Alist of default search engines keyed by server method"
423;; 197 :type '(alist)
424(defcustom nnir-mail-backend '(nnml "")
425 "*Specifies which backend should be searched.
426More precisely, this is used to determine from which backend to fetch the
427messages found.
428
429This must be equal to an existing server, so maybe it is best to use
430something like the following:
431 (setq nnir-mail-backend (nth 0 gnus-secondary-select-methods))
432The above line works fine if the mail backend you want to search is
433the first element of gnus-secondary-select-methods (`nth' starts counting
434at zero)."
435 :type '(sexp)
436 :group 'nnir) 198 :group 'nnir)
437 199
438;; Search engine to use. 200(defcustom nnir-imap-default-search-key "Whole message"
439 201 "*The default IMAP search key for an nnir search. Must be one of
440(defcustom nnir-search-engine 'wais 202 the keys in `nnir-imap-search-arguments'. To use raw imap queries
441 "*The search engine to use. Must be a symbol. 203 by default set this to \"Imap\""
442See `nnir-engines' for a list of supported engines, and for example 204 :type '(string)
443settings of `nnir-search-engine'."
444 :type '(sexp)
445 :group 'nnir) 205 :group 'nnir)
446 206
447;; freeWAIS-sf.
448
449(defcustom nnir-wais-program "waissearch" 207(defcustom nnir-wais-program "waissearch"
450 "*Name of waissearch executable." 208 "*Name of waissearch executable."
451 :type '(string) 209 :type '(string)
@@ -501,8 +259,8 @@ Instead, use this:
501in order to get a group name (albeit with / instead of .). This is a 259in order to get a group name (albeit with / instead of .). This is a
502regular expression. 260regular expression.
503 261
504This variable is very similar to `nnir-wais-remove-prefix', except 262This variable is very similar to `nnir-namazu-remove-prefix', except
505that it is for swish++, not Wais." 263that it is for swish++, not Namazu."
506 :type '(regexp) 264 :type '(regexp)
507 :group 'nnir) 265 :group 'nnir)
508 266
@@ -552,13 +310,47 @@ This could be a server parameter."
552in order to get a group name (albeit with / instead of .). This is a 310in order to get a group name (albeit with / instead of .). This is a
553regular expression. 311regular expression.
554 312
555This variable is very similar to `nnir-wais-remove-prefix', except 313This variable is very similar to `nnir-namazu-remove-prefix', except
556that it is for swish-e, not Wais. 314that it is for swish-e, not Namazu.
557 315
558This could be a server parameter." 316This could be a server parameter."
559 :type '(regexp) 317 :type '(regexp)
560 :group 'nnir) 318 :group 'nnir)
561 319
320;; HyREX engine, see <URL:http://ls6-www.cs.uni-dortmund.de/>
321
322(defcustom nnir-hyrex-program "nnir-search"
323 "*Name of the nnir-search executable."
324 :type '(string)
325 :group 'nnir)
326
327(defcustom nnir-hyrex-additional-switches '()
328 "*A list of strings, to be given as additional arguments for nnir-search.
329Note that this should be a list. Ie, do NOT use the following:
330 (setq nnir-hyrex-additional-switches \"-ddl ddl.xml -c nnir\") ; wrong !
331Instead, use this:
332 (setq nnir-hyrex-additional-switches '(\"-ddl\" \"ddl.xml\" \"-c\" \"nnir\"))"
333 :type '(repeat (string))
334 :group 'nnir)
335
336(defcustom nnir-hyrex-index-directory (getenv "HOME")
337 "*Index directory for HyREX."
338 :type '(directory)
339 :group 'nnir)
340
341(defcustom nnir-hyrex-remove-prefix (concat (getenv "HOME") "/Mail/")
342 "*The prefix to remove from each file name returned by HyREX
343in order to get a group name (albeit with / instead of .).
344
345For example, suppose that HyREX returns file names such as
346\"/home/john/Mail/mail/misc/42\". For this example, use the following
347setting: (setq nnir-hyrex-remove-prefix \"/home/john/Mail/\")
348Note the trailing slash. Removing this prefix gives \"mail/misc/42\".
349`nnir' knows to remove the \"/42\" and to replace \"/\" with \".\" to
350arrive at the correct group name, \"mail.misc\"."
351 :type '(directory)
352 :group 'nnir)
353
562;; Namazu engine, see <URL:http://www.namazu.org/> 354;; Namazu engine, see <URL:http://www.namazu.org/>
563 355
564(defcustom nnir-namazu-program "namazu" 356(defcustom nnir-namazu-program "namazu"
@@ -587,11 +379,83 @@ Instead, use this:
587 "*The prefix to remove from each file name returned by Namazu 379 "*The prefix to remove from each file name returned by Namazu
588in order to get a group name (albeit with / instead of .). 380in order to get a group name (albeit with / instead of .).
589 381
590This variable is very similar to `nnir-wais-remove-prefix', except 382For example, suppose that Namazu returns file names such as
591that it is for Namazu, not Wais." 383\"/home/john/Mail/mail/misc/42\". For this example, use the following
384setting: (setq nnir-namazu-remove-prefix \"/home/john/Mail/\")
385Note the trailing slash. Removing this prefix gives \"mail/misc/42\".
386`nnir' knows to remove the \"/42\" and to replace \"/\" with \".\" to
387arrive at the correct group name, \"mail.misc\"."
592 :type '(directory) 388 :type '(directory)
593 :group 'nnir) 389 :group 'nnir)
594 390
391;; Imap variables
392
393(defvar nnir-imap-search-arguments
394 '(("Whole message" . "TEXT")
395 ("Subject" . "SUBJECT")
396 ("To" . "TO")
397 ("From" . "FROM")
398 ("Imap" . ""))
399 "Mapping from user readable keys to IMAP search items for use in nnir")
400
401(defvar nnir-imap-search-other "HEADER %S"
402 "The IMAP search item to use for anything other than
403 `nnir-imap-search-arguments'. By default this is the name of an
404 email header field")
405
406(defvar nnir-imap-search-argument-history ()
407 "The history for querying search options in nnir")
408
409;;; Developer Extension Variable:
410
411(defvar nnir-engines
412 `((wais nnir-run-waissearch
413 ())
414 (imap nnir-run-imap
415 ((criteria
416 "Imap Search in" ; Prompt
417 ,(mapcar 'car nnir-imap-search-arguments) ; alist for completing
418 nil ; allow any user input
419 nil ; initial value
420 nnir-imap-search-argument-history ; the history to use
421 ,nnir-imap-default-search-key ; default
422 )))
423 (gmane nnir-run-gmane
424 ((author . "Gmane Author: ")))
425 (swish++ nnir-run-swish++
426 ((group . "Swish++ Group spec: ")))
427 (swish-e nnir-run-swish-e
428 ((group . "Swish-e Group spec: ")))
429 (namazu nnir-run-namazu
430 ())
431 (hyrex nnir-run-hyrex
432 ((group . "Hyrex Group spec: ")))
433 (find-grep nnir-run-find-grep
434 ((grep-options . "Grep options: "))))
435 "Alist of supported search engines.
436Each element in the alist is a three-element list (ENGINE FUNCTION ARGS).
437ENGINE is a symbol designating the searching engine. FUNCTION is also
438a symbol, giving the function that does the search. The third element
439ARGS is a list of cons pairs (PARAM . PROMPT). When issuing a query,
440the FUNCTION will issue a query for each of the PARAMs, using PROMPT.
441
442The value of `nnir-search-engine' must be one of the ENGINE symbols.
443For example, for searching a server using namazu include
444 (nnir-search-engine namazu)
445in the server definition. Note that you have to set additional
446variables for most backends. For example, the `namazu' backend
447needs the variables `nnir-namazu-program',
448`nnir-namazu-index-directory' and `nnir-namazu-remove-prefix'.
449
450Add an entry here when adding a new search engine.")
451
452(defvar nnir-get-article-nov-override-function nil
453 "If non-nil, a function that will be passed each search result. This
454should return a message's headers in NOV format.
455
456If this variable is nil, or if the provided function returns nil for a search
457result, `gnus-retrieve-headers' will be called instead.")
458
595;;; Internal Variables: 459;;; Internal Variables:
596 460
597(defvar nnir-current-query nil 461(defvar nnir-current-query nil
@@ -609,43 +473,31 @@ that it is for Namazu, not Wais."
609(defvar nnir-tmp-buffer " *nnir*" 473(defvar nnir-tmp-buffer " *nnir*"
610 "Internal: temporary buffer.") 474 "Internal: temporary buffer.")
611 475
476(defvar nnir-search-history ()
477 "Internal: the history for querying search options in nnir")
478
479(defvar nnir-extra-parms nil
480 "Internal: stores request for extra search parms")
481
612;;; Code: 482;;; Code:
613 483
614;; Gnus glue. 484;; Gnus glue.
615 485
616(defun gnus-group-make-nnir-group (extra-parms query) 486(defun gnus-group-make-nnir-group (nnir-extra-parms)
617 "Create an nnir group. Asks for query." 487 "Create an nnir group. Asks for query."
618 (interactive "P\nsQuery: ") 488 (interactive "P")
619 (setq nnir-current-query nil 489 (setq nnir-current-query nil
620 nnir-current-server nil 490 nnir-current-server nil
621 nnir-current-group-marked nil 491 nnir-current-group-marked nil
622 nnir-artlist nil) 492 nnir-artlist nil)
623 (let ((parms nil)) 493 (let* ((query (read-string "Query: " nil 'nnir-search-history))
624 (if extra-parms 494 (parms (list (cons 'query query))))
625 (setq parms (nnir-read-parms query))
626 (setq parms (list (cons 'query query))))
627 (add-to-list 'parms (cons 'unique-id (message-unique-id)) t) 495 (add-to-list 'parms (cons 'unique-id (message-unique-id)) t)
628 (gnus-group-read-ephemeral-group 496 (gnus-group-read-ephemeral-group
629 (concat "nnir:" (prin1-to-string parms)) '(nnir "") t 497 (concat "nnir:" (prin1-to-string parms)) '(nnir "") t
630 (cons (current-buffer) 498 (cons (current-buffer) gnus-current-window-configuration)
631 gnus-current-window-configuration)
632 nil))) 499 nil)))
633 500
634;; Why is this needed? Is this for compatibility with old/new gnusae? Using
635;; gnus-group-server instead works for me. -- Justus Piater
636(defmacro nnir-group-server (group)
637 "Return the server for a newsgroup GROUP.
638The returned format is as `gnus-server-to-method' needs it. See
639`gnus-group-real-prefix' and `gnus-group-real-name'."
640 `(let ((gname ,group))
641 (if (string-match "^\\([^:]+\\):" gname)
642 (progn
643 (setq gname (match-string 1 gname))
644 (if (string-match "^\\([^+]+\\)\\+\\(.+\\)$" gname)
645 (format "%s:%s" (match-string 1 gname) (match-string 2 gname))
646 (concat gname ":")))
647 (format "%s:%s" (car gnus-select-method) (cadr gnus-select-method)))))
648
649;; Summary mode commands. 501;; Summary mode commands.
650 502
651(defun gnus-summary-nnir-goto-thread () 503(defun gnus-summary-nnir-goto-thread ()
@@ -660,22 +512,27 @@ and show thread that contains this article."
660 (id (mail-header-id (gnus-summary-article-header))) 512 (id (mail-header-id (gnus-summary-article-header)))
661 (refs (split-string 513 (refs (split-string
662 (mail-header-references (gnus-summary-article-header))))) 514 (mail-header-references (gnus-summary-article-header)))))
663 (if (eq (car (gnus-group-method group)) 'nnimap) 515 (if (eq (car (gnus-find-method-for-group group)) 'nnimap)
664 (progn (nnimap-possibly-change-group (gnus-group-short-name group) nil) 516 (progn
665 (with-current-buffer (nnimap-buffer) 517 (nnimap-possibly-change-group (gnus-group-short-name group) nil)
666 (let* ((cmd (let ((value (format 518 (with-current-buffer (nnimap-buffer)
667 "(OR HEADER REFERENCES %s HEADER Message-Id %s)" 519 (let* ((cmd
668 id id))) 520 (let ((value
669 (dolist (refid refs value) 521 (format
670 (setq value (format 522 "(OR HEADER REFERENCES %s HEADER Message-Id %s)"
671 "(OR (OR HEADER Message-Id %s HEADER REFERENCES %s) %s)" 523 id id)))
672 refid refid value))))) 524 (dolist (refid refs value)
673 (result (nnimap-command 525 (setq value
674 "UID SEARCH %s" cmd))) 526 (format
675 (gnus-summary-read-group-1 group t t gnus-summary-buffer nil 527 "(OR (OR HEADER Message-Id %s HEADER REFERENCES %s) %s)"
676 (and (car result) 528 refid refid value)))))
677 (delete 0 (mapcar #'string-to-number 529 (result (nnimap-command "UID SEARCH %s" cmd)))
678 (cdr (assoc "SEARCH" (cdr result)))))))))) 530 (gnus-summary-read-group-1
531 group t t gnus-summary-buffer nil
532 (and (car result)
533 (delete 0 (mapcar
534 #'string-to-number
535 (cdr (assoc "SEARCH" (cdr result))))))))))
679 (gnus-summary-read-group-1 group t t gnus-summary-buffer 536 (gnus-summary-read-group-1 group t t gnus-summary-buffer
680 nil (list backend-number)) 537 nil (list backend-number))
681 (gnus-summary-limit (list backend-number)) 538 (gnus-summary-limit (list backend-number))
@@ -711,22 +568,17 @@ and show thread that contains this article."
711 ;; Cache miss. 568 ;; Cache miss.
712 (setq nnir-artlist (nnir-run-query group))) 569 (setq nnir-artlist (nnir-run-query group)))
713 (with-current-buffer nntp-server-buffer 570 (with-current-buffer nntp-server-buffer
571 (setq nnir-current-query group)
572 (when server (setq nnir-current-server server))
573 (setq nnir-current-group-marked gnus-group-marked)
714 (if (zerop (length nnir-artlist)) 574 (if (zerop (length nnir-artlist))
715 (progn 575 (nnheader-report 'nnir "Search produced empty results.")
716 (setq nnir-current-query nil
717 nnir-current-server nil
718 nnir-current-group-marked nil
719 nnir-artlist nil)
720 (nnheader-report 'nnir "Search produced empty results."))
721 ;; Remember data for cache. 576 ;; Remember data for cache.
722 (setq nnir-current-query group)
723 (when server (setq nnir-current-server server))
724 (setq nnir-current-group-marked gnus-group-marked)
725 (nnheader-insert "211 %d %d %d %s\n" 577 (nnheader-insert "211 %d %d %d %s\n"
726 (nnir-artlist-length nnir-artlist) ; total # 578 (nnir-artlist-length nnir-artlist) ; total #
727 1 ; first # 579 1 ; first #
728 (nnir-artlist-length nnir-artlist) ; last # 580 (nnir-artlist-length nnir-artlist) ; last #
729 group)))) ; group name 581 group)))) ; group name
730 582
731(deffoo nnir-retrieve-headers (articles &optional group server fetch-old) 583(deffoo nnir-retrieve-headers (articles &optional group server fetch-old)
732 (save-excursion 584 (save-excursion
@@ -745,7 +597,7 @@ and show thread that contains this article."
745 (setq artfullgroup (nnir-artitem-group artitem)) 597 (setq artfullgroup (nnir-artitem-group artitem))
746 (setq artno (nnir-artitem-number artitem)) 598 (setq artno (nnir-artitem-number artitem))
747 (setq artgroup (gnus-group-real-name artfullgroup)) 599 (setq artgroup (gnus-group-real-name artfullgroup))
748 (setq server (nnir-group-server artfullgroup)) 600 (setq server (gnus-group-server artfullgroup))
749 ;; retrieve NOV or HEAD data for this article, transform into 601 ;; retrieve NOV or HEAD data for this article, transform into
750 ;; NOV data and prepend to `novdata' 602 ;; NOV data and prepend to `novdata'
751 (set-buffer nntp-server-buffer) 603 (set-buffer nntp-server-buffer)
@@ -859,8 +711,8 @@ ready to be added to the list of search results."
859(defun nnir-run-waissearch (query server &optional group) 711(defun nnir-run-waissearch (query server &optional group)
860 "Run given query agains waissearch. Returns vector of (group name, file name) 712 "Run given query agains waissearch. Returns vector of (group name, file name)
861pairs (also vectors, actually)." 713pairs (also vectors, actually)."
862 (when group 714 ;; (when group
863 (error "The freeWAIS-sf backend cannot search specific groups")) 715 ;; (error "The freeWAIS-sf backend cannot search specific groups"))
864 (save-excursion 716 (save-excursion
865 (let ((qstring (cdr (assq 'query query))) 717 (let ((qstring (cdr (assq 'query query)))
866 (prefix (nnir-read-server-parm 'nnir-wais-remove-prefix server)) 718 (prefix (nnir-read-server-parm 'nnir-wais-remove-prefix server))
@@ -900,49 +752,49 @@ pairs (also vectors, actually)."
900 (> (nnir-artitem-rsv x) 752 (> (nnir-artitem-rsv x)
901 (nnir-artitem-rsv y))))))))) 753 (nnir-artitem-rsv y)))))))))
902 754
903;; IMAP interface. 755;; imap interface
904;; todo: 756(defun nnir-run-imap (query srv &optional groups)
905;; send queries as literals
906;; handle errors
907
908
909(defun nnir-run-imap (query srv &optional group-option)
910 "Run a search against an IMAP back-end server. 757 "Run a search against an IMAP back-end server.
911This uses a custom query language parser; see `nnir-imap-make-query' for 758This uses a custom query language parser; see `nnir-imap-make-query' for
912details on the language and supported extensions" 759details on the language and supported extensions"
913 (save-excursion 760 (save-excursion
914 (let ((qstring (cdr (assq 'query query))) 761 (let ((qstring (cdr (assq 'query query)))
915 (server (cadr (gnus-server-to-method srv))) 762 (server (cadr (gnus-server-to-method srv)))
916 (group (or group-option (gnus-group-group-name))) 763 (defs (caddr (gnus-server-to-method srv)))
917 (defs (caddr (gnus-server-to-method srv))) 764 (criteria (or (cdr (assq 'criteria query))
918 (criteria (or (cdr (assq 'criteria query)) 765 (cdr (assoc nnir-imap-default-search-key
919 (cdr (assoc nnir-imap-default-search-key 766 nnir-imap-search-arguments))))
920 nnir-imap-search-arguments)))) 767 (gnus-inhibit-demon t)
921 (gnus-inhibit-demon t) 768 artlist)
922 artlist)
923 (message "Opening server %s" server) 769 (message "Opening server %s" server)
924 (condition-case () 770 (apply
925 (when (nnimap-possibly-change-group (gnus-group-short-name group) server) 771 'vconcat
926 (with-current-buffer (nnimap-buffer) 772 (mapcar
927 (message "Searching %s..." group) 773 (lambda (x)
928 (let ((arts 0) 774 (let ((group x))
929 (result 775 (condition-case ()
930 (nnimap-command "UID SEARCH %s" 776 (when (nnimap-possibly-change-group
931 (if (string= criteria "") 777 (gnus-group-short-name group) server)
932 qstring 778 (with-current-buffer (nnimap-buffer)
933 (nnir-imap-make-query criteria qstring) 779 (message "Searching %s..." group)
934 )))) 780 (let ((arts 0)
935 (mapc 781 (result (nnimap-command "UID SEARCH %s"
936 (lambda (artnum) 782 (if (string= criteria "")
937 (push (vector group artnum 1) artlist) 783 qstring
938 (setq arts (1+ arts))) 784 (nnir-imap-make-query
939 (and (car result) 785 criteria qstring)))))
940 (delete 0 (mapcar #'string-to-number 786 (mapc
941 (cdr (assoc "SEARCH" (cdr result))))))) 787 (lambda (artnum) (push (vector group artnum 1) artlist)
942 (message "Searching %s... %d matches" group arts))) 788 (setq arts (1+ arts)))
943 (message "Searching %s...done" group)) 789 (and (car result)
944 (quit nil)) 790 (delete 0 (mapcar #'string-to-number
945 (reverse artlist)))) 791 (cdr (assoc "SEARCH"
792 (cdr result)))))))
793 (message "Searching %s... %d matches" group arts)))
794 (message "Searching %s...done" group))
795 (quit nil))
796 (reverse artlist)))
797 groups)))))
946 798
947(defun nnir-imap-make-query (criteria qstring) 799(defun nnir-imap-make-query (criteria qstring)
948 "Parse the query string and criteria into an appropriate IMAP search 800 "Parse the query string and criteria into an appropriate IMAP search
@@ -1132,8 +984,8 @@ actually).
1132Tested with swish++ 4.7 on GNU/Linux and with swish++ 5.0b2 on 984Tested with swish++ 4.7 on GNU/Linux and with swish++ 5.0b2 on
1133Windows NT 4.0." 985Windows NT 4.0."
1134 986
1135 (when group 987 ;; (when group
1136 (error "The swish++ backend cannot search specific groups")) 988 ;; (error "The swish++ backend cannot search specific groups"))
1137 989
1138 (save-excursion 990 (save-excursion
1139 (let ( (qstring (cdr (assq 'query query))) 991 (let ( (qstring (cdr (assq 'query query)))
@@ -1221,8 +1073,8 @@ actually).
1221Tested with swish-e-2.0.1 on Windows NT 4.0." 1073Tested with swish-e-2.0.1 on Windows NT 4.0."
1222 1074
1223 ;; swish-e crashes with empty parameter to "-w" on commandline... 1075 ;; swish-e crashes with empty parameter to "-w" on commandline...
1224 (when group 1076 ;; (when group
1225 (error "The swish-e backend cannot search specific groups")) 1077 ;; (error "The swish-e backend cannot search specific groups"))
1226 1078
1227 (save-excursion 1079 (save-excursion
1228 (let ((qstring (cdr (assq 'query query))) 1080 (let ((qstring (cdr (assq 'query query)))
@@ -1306,14 +1158,85 @@ Tested with swish-e-2.0.1 on Windows NT 4.0."
1306 (> (nnir-artitem-rsv x) 1158 (> (nnir-artitem-rsv x)
1307 (nnir-artitem-rsv y))))))))) 1159 (nnir-artitem-rsv y)))))))))
1308 1160
1161;; HyREX interface
1162(defun nnir-run-hyrex (query server &optional group)
1163 (save-excursion
1164 (let ((artlist nil)
1165 (groupspec (cdr (assq 'group query)))
1166 (qstring (cdr (assq 'query query)))
1167 (prefix (nnir-read-server-parm 'nnir-hyrex-remove-prefix server))
1168 score artno dirnam)
1169 (when (and (not groupspec) group)
1170 (setq groupspec
1171 (regexp-opt
1172 (mapcar (lambda (x) (gnus-group-real-name x)) group))))
1173 (set-buffer (get-buffer-create nnir-tmp-buffer))
1174 (erase-buffer)
1175 (message "Doing hyrex-search query %s..." query)
1176 (let* ((cp-list
1177 `( ,nnir-hyrex-program
1178 nil ; input from /dev/null
1179 t ; output
1180 nil ; don't redisplay
1181 "-i",(nnir-read-server-parm 'nnir-hyrex-index-directory server) ; index directory
1182 ,@(nnir-read-server-parm 'nnir-hyrex-additional-switches server)
1183 ,qstring ; the query, in hyrex-search format
1184 ))
1185 (exitstatus
1186 (progn
1187 (message "%s args: %s" nnir-hyrex-program
1188 (mapconcat 'identity (cddddr cp-list) " "))
1189 (apply 'call-process cp-list))))
1190 (unless (or (null exitstatus)
1191 (zerop exitstatus))
1192 (nnheader-report 'nnir "Couldn't run hyrex-search: %s" exitstatus)
1193 ;; nnir-search failure reason is in this buffer, show it if
1194 ;; the user wants it.
1195 (when (> gnus-verbose 6)
1196 (display-buffer nnir-tmp-buffer)))) ;; FIXME: Dont clear buffer !
1197 (message "Doing hyrex-search query \"%s\"...done" qstring)
1198 (sit-for 0)
1199 ;; nnir-search returns:
1200 ;; for nnml/nnfolder: "filename mailid weigth"
1201 ;; for nnimap: "group mailid weigth"
1202 (goto-char (point-min))
1203 (delete-non-matching-lines "^\\S + [0-9]+ [0-9]+$")
1204 ;; HyREX doesn't search directly in groups -- so filter out here.
1205 (when groupspec
1206 (keep-lines groupspec))
1207 ;; extract data from result lines
1208 (goto-char (point-min))
1209 (while (re-search-forward
1210 "\\(\\S +\\) \\([0-9]+\\) \\([0-9]+\\)" nil t)
1211 (setq dirnam (match-string 1)
1212 artno (match-string 2)
1213 score (match-string 3))
1214 (when (string-match prefix dirnam)
1215 (setq dirnam (replace-match "" t t dirnam)))
1216 (push (vector (nnir-group-full-name
1217 (gnus-replace-in-string dirnam "/" ".") server)
1218 (string-to-number artno)
1219 (string-to-number score))
1220 artlist))
1221 (message "Massaging hyrex-search output...done.")
1222 (apply 'vector
1223 (sort artlist
1224 (function (lambda (x y)
1225 (if (string-lessp (nnir-artitem-group x)
1226 (nnir-artitem-group y))
1227 t
1228 (< (nnir-artitem-number x)
1229 (nnir-artitem-number y)))))))
1230 )))
1231
1309;; Namazu interface 1232;; Namazu interface
1310(defun nnir-run-namazu (query server &optional group) 1233(defun nnir-run-namazu (query server &optional group)
1311 "Run given query against Namazu. Returns a vector of (group name, file name) 1234 "Run given query against Namazu. Returns a vector of (group name, file name)
1312pairs (also vectors, actually). 1235pairs (also vectors, actually).
1313 1236
1314Tested with Namazu 2.0.6 on a GNU/Linux system." 1237Tested with Namazu 2.0.6 on a GNU/Linux system."
1315 (when group 1238 ;; (when group
1316 (error "The Namazu backend cannot search specific groups")) 1239 ;; (error "The Namazu backend cannot search specific groups"))
1317 (save-excursion 1240 (save-excursion
1318 (let ((article-pattern (if (string= (gnus-group-server server) "nnmaildir") 1241 (let ((article-pattern (if (string= (gnus-group-server server) "nnmaildir")
1319 ":[0-9]+" 1242 ":[0-9]+"
@@ -1375,7 +1298,7 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1375 (> (nnir-artitem-rsv x) 1298 (> (nnir-artitem-rsv x)
1376 (nnir-artitem-rsv y))))))))) 1299 (nnir-artitem-rsv y)))))))))
1377 1300
1378(defun nnir-run-find-grep (query server &optional group) 1301(defun nnir-run-find-grep (query server &optional grouplist)
1379 "Run find and grep to obtain matching articles." 1302 "Run find and grep to obtain matching articles."
1380 (let* ((method (gnus-server-to-method server)) 1303 (let* ((method (gnus-server-to-method server))
1381 (sym (intern 1304 (sym (intern
@@ -1387,65 +1310,128 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1387 (unless directory 1310 (unless directory
1388 (error "No directory found in method specification of server %s" 1311 (error "No directory found in method specification of server %s"
1389 server)) 1312 server))
1390 (message "Searching %s using find-grep..." (or group server)) 1313 (apply
1391 (save-window-excursion 1314 'vconcat
1392 (set-buffer (get-buffer-create nnir-tmp-buffer)) 1315 (mapcar (lambda (x)
1393 (erase-buffer) 1316 (let ((group x))
1394 (if (> gnus-verbose 6) 1317 (message "Searching %s using find-grep..."
1395 (pop-to-buffer (current-buffer))) 1318 (or group server))
1396 (cd directory) ; Using relative paths simplifies postprocessing. 1319 (save-window-excursion
1397 (let ((group 1320 (set-buffer (get-buffer-create nnir-tmp-buffer))
1398 (if (not group) 1321 (erase-buffer)
1399 "." 1322 (if (> gnus-verbose 6)
1400 ;; Try accessing the group literally as well as 1323 (pop-to-buffer (current-buffer)))
1401 ;; interpreting dots as directory separators so the 1324 (cd directory) ; Using relative paths simplifies
1402 ;; engine works with plain nnml as well as the Gnus Cache. 1325 ; postprocessing.
1403 (let ((group (gnus-group-real-name group))) 1326 (let ((group
1404 ;; Replace cl-func find-if. 1327 (if (not group)
1405 (if (file-directory-p group) 1328 "."
1406 group 1329 ;; Try accessing the group literally as
1407 (if (file-directory-p 1330 ;; well as interpreting dots as directory
1408 (setq group (gnus-replace-in-string group "\\." "/" t))) 1331 ;; separators so the engine works with
1409 group)))))) 1332 ;; plain nnml as well as the Gnus Cache.
1410 (unless group 1333 (let ((group (gnus-group-real-name group)))
1411 (error "Cannot locate directory for group")) 1334 ;; Replace cl-func find-if.
1412 (save-excursion 1335 (if (file-directory-p group)
1413 (apply 1336 group
1414 'call-process "find" nil t 1337 (if (file-directory-p
1415 "find" group "-type" "f" "-name" "[0-9]*" "-exec" 1338 (setq group
1416 "grep" 1339 (gnus-replace-in-string
1417 `("-l" ,@(and grep-options 1340 group
1418 (split-string grep-options "\\s-" t)) 1341 "\\." "/" t)))
1419 "-e" ,regexp "{}" "+")))) 1342 group))))))
1420 1343 (unless group
1421 ;; Translate relative paths to group names. 1344 (error "Cannot locate directory for group"))
1422 (while (not (eobp)) 1345 (save-excursion
1423 (let* ((path (split-string 1346 (apply
1424 (buffer-substring (point) (line-end-position)) "/" t)) 1347 'call-process "find" nil t
1425 (art (string-to-number (car (last path))))) 1348 "find" group "-type" "f" "-name" "[0-9]*" "-exec"
1426 (while (string= "." (car path)) 1349 "grep"
1427 (setq path (cdr path))) 1350 `("-l" ,@(and grep-options
1428 (let ((group (mapconcat 'identity 1351 (split-string grep-options "\\s-" t))
1429 ;; Replace cl-func: (subseq path 0 -1) 1352 "-e" ,regexp "{}" "+"))))
1430 (let ((end (1- (length path))) 1353
1431 res) 1354 ;; Translate relative paths to group names.
1432 (while (>= (setq end (1- end)) 0) 1355 (while (not (eobp))
1433 (push (pop path) res)) 1356 (let* ((path (split-string
1434 (nreverse res)) 1357 (buffer-substring
1435 "."))) 1358 (point)
1436 (push (vector (nnir-group-full-name group server) art 0) 1359 (line-end-position)) "/" t))
1437 artlist)) 1360 (art (string-to-number (car (last path)))))
1438 (forward-line 1))) 1361 (while (string= "." (car path))
1439 (message "Searching %s using find-grep...done" (or group server)) 1362 (setq path (cdr path)))
1440 artlist))) 1363 (let ((group (mapconcat 'identity
1364 ;; Replace cl-func:
1365 ;; (subseq path 0 -1)
1366 (let ((end (1- (length path)))
1367 res)
1368 (while
1369 (>= (setq end (1- end)) 0)
1370 (push (pop path) res))
1371 (nreverse res))
1372 ".")))
1373 (push
1374 (vector (nnir-group-full-name group server) art 0)
1375 artlist))
1376 (forward-line 1)))
1377 (message "Searching %s using find-grep...done"
1378 (or group server))
1379 artlist)))
1380 grouplist))))
1381
1382;; gmane interface
1383(defun nnir-run-gmane (query srv &optional groups)
1384 "Run a search against a gmane back-end server."
1385 (if (string-match-p "gmane" srv)
1386 (let* ((case-fold-search t)
1387 (qstring (cdr (assq 'query query)))
1388 (server (cadr (gnus-server-to-method srv)))
1389 (groupspec (if groups
1390 (mapconcat
1391 (function (lambda (x)
1392 (format "group:%s"
1393 (gnus-group-short-name x))))
1394 groups " ") ""))
1395 (authorspec
1396 (if (assq 'author query)
1397 (format "author:%s" (cdr (assq 'author query))) ""))
1398 (search (format "%s %s %s"
1399 qstring groupspec authorspec))
1400 artlist)
1401 (with-current-buffer nntp-server-buffer
1402 (erase-buffer)
1403 (mm-url-insert
1404 (concat
1405 "http://search.gmane.org/nov.php"
1406 "?"
1407 (mm-url-encode-www-form-urlencoded
1408 `(("query" . ,search)
1409 ("HITSPERPAGE" . "999")))))
1410 (unless (featurep 'xemacs) (set-buffer-multibyte t))
1411 (mm-decode-coding-region (point-min) (point-max) 'utf-8)
1412 (goto-char (point-min))
1413 (forward-line 1)
1414 (while (not (eobp))
1415 (unless (or (eolp) (looking-at "\x0d"))
1416 (let ((header (nnheader-parse-nov)))
1417 (let ((xref (mail-header-xref header)))
1418 (when (string-match " \\([^:]+\\)[:/]\\([0-9]+\\)" xref)
1419 (push
1420 (vector
1421 (gnus-group-prefixed-name (match-string 1 xref) srv)
1422 (string-to-number (match-string 2 xref)) 1)
1423 artlist)))))
1424 (forward-line 1)))
1425 (reverse artlist))
1426 (message "Can't search non-gmane nntp groups")))
1441 1427
1442;;; Util Code: 1428;;; Util Code:
1443 1429
1444(defun nnir-read-parms (query) 1430(defun nnir-read-parms (query nnir-search-engine)
1445 "Reads additional search parameters according to `nnir-engines'." 1431 "Reads additional search parameters according to `nnir-engines'."
1446 (let ((parmspec (caddr (assoc nnir-search-engine nnir-engines)))) 1432 (let ((parmspec (caddr (assoc nnir-search-engine nnir-engines))))
1447 (cons (cons 'query query) 1433 (nconc query
1448 (mapcar 'nnir-read-parm parmspec)))) 1434 (mapcar 'nnir-read-parm parmspec))))
1449 1435
1450(defun nnir-read-parm (parmspec) 1436(defun nnir-read-parm (parmspec)
1451 "Reads a single search parameter. 1437 "Reads a single search parameter.
@@ -1461,67 +1447,40 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1461 1447
1462(defun nnir-run-query (query) 1448(defun nnir-run-query (query)
1463 "Invoke appropriate search engine function (see `nnir-engines'). 1449 "Invoke appropriate search engine function (see `nnir-engines').
1464If some groups were process-marked, run the query for each of the groups 1450 If some groups were process-marked, run the query for each of the groups
1465and concat the results." 1451 and concat the results."
1466 (let ((q (car (read-from-string query)))) 1452 (let ((q (car (read-from-string query)))
1467 (if gnus-group-marked 1453 (groups (nnir-sort-groups-by-server
1468 (apply 'vconcat 1454 (or gnus-group-marked (list (gnus-group-group-name))))))
1469 (mapcar (lambda (x) 1455 (apply 'vconcat
1470 (let* ((server (nnir-group-server x)) 1456 (mapcar (lambda (x)
1471 (engine 1457 (let* ((server (car x))
1472 (or (nnir-read-server-parm 'nnir-search-engine 1458 (nnir-search-engine
1473 server) 1459 (or (nnir-read-server-parm 'nnir-search-engine
1474 (cdr 1460 server)
1475 (assoc (car (gnus-server-to-method server)) 1461 (cdr (assoc (car
1476 nnir-method-default-engines)))) 1462 (gnus-server-to-method server))
1477 search-func) 1463 nnir-method-default-engines))))
1478 (setq search-func (cadr 1464 search-func)
1479 (assoc 1465 (setq search-func (cadr
1480 engine 1466 (assoc nnir-search-engine
1481 nnir-engines)))
1482 (if search-func
1483 (funcall search-func q server x)
1484 nil)))
1485 gnus-group-marked))
1486 (apply 'vconcat
1487 (mapcar (lambda (x)
1488 (if (and (equal (cadr x) 'ok) (not (equal (cadar x) "-ephemeral")))
1489 (let* ((server (format "%s:%s" (caar x) (cadar x)))
1490 (engine
1491 (or (nnir-read-server-parm 'nnir-search-engine
1492 server)
1493 (cdr
1494 (assoc (car (gnus-server-to-method server))
1495 nnir-method-default-engines))))
1496 search-func)
1497 (setq search-func (cadr
1498 (assoc
1499 engine
1500 nnir-engines))) 1467 nnir-engines)))
1501 (if search-func 1468 (if search-func
1502 (funcall search-func q server nil) 1469 (funcall search-func
1503 nil)) 1470 (if nnir-extra-parms
1504 nil)) 1471 (nnir-read-parms q nnir-search-engine)
1505 gnus-opened-servers) 1472 q)
1506 )) 1473 server (cdr x))
1507 )) 1474 nil)))
1475 groups))))
1508 1476
1509(defun nnir-read-server-parm (key server) 1477(defun nnir-read-server-parm (key server)
1510 "Returns the parameter value of for the given server, where server is of 1478 "Returns the parameter value of key for the given server, where
1511form 'backend:name'." 1479server is of form 'backend:name'."
1512 (let ((method (gnus-server-to-method server))) 1480 (let ((method (gnus-server-to-method server)))
1513 (cond ((and method (assq key (cddr method))) 1481 (cond ((and method (assq key (cddr method)))
1514 (nth 1 (assq key (cddr method)))) 1482 (nth 1 (assq key (cddr method))))
1515 ((and nnir-mail-backend 1483 (t nil))))
1516 (gnus-server-equal method nnir-mail-backend))
1517 (symbol-value key))
1518 (t nil))))
1519;; (if method
1520;; (if (assq key (cddr method))
1521;; (nth 1 (assq key (cddr method)))
1522;; (symbol-value key))
1523;; (symbol-value key))
1524;; ))
1525 1484
1526(defun nnir-group-full-name (shortname server) 1485(defun nnir-group-full-name (shortname server)
1527 "For the given group name, return a full Gnus group name. 1486 "For the given group name, return a full Gnus group name.
@@ -1564,8 +1523,8 @@ The Gnus backend/server information is added."
1564 (elt artitem 2)) 1523 (elt artitem 2))
1565 1524
1566(defun nnir-artlist-artitem-rsv (artlist n) 1525(defun nnir-artlist-artitem-rsv (artlist n)
1567 "Returns from ARTLIST the Retrieval Status Value of the Nth artitem 1526 "Returns from ARTLIST the Retrieval Status Value of the Nth
1568\(counting from 1)." 1527artitem (counting from 1)."
1569 (nnir-artitem-rsv (nnir-artlist-article artlist n))) 1528 (nnir-artitem-rsv (nnir-artlist-article artlist n)))
1570 1529
1571;; unused? 1530;; unused?
@@ -1580,6 +1539,17 @@ The Gnus backend/server information is added."
1580 with-dups) 1539 with-dups)
1581 res)) 1540 res))
1582 1541
1542(defun nnir-sort-groups-by-server (groups)
1543 "sorts a list of groups into an alist keyed by server"
1544(if (car groups)
1545 (let (value)
1546 (dolist (var groups value)
1547 (let ((server (gnus-group-server var)))
1548 (if (assoc server value)
1549 (nconc (cdr (assoc server value)) (list var))
1550 (push (cons (gnus-group-server var) (list var)) value))))
1551 value)
1552 nil))
1583 1553
1584;; The end. 1554;; The end.
1585(provide 'nnir) 1555(provide 'nnir)
diff --git a/lisp/gnus/shr.el b/lisp/gnus/shr.el
index bbb7ff18a46..d72473527df 100644
--- a/lisp/gnus/shr.el
+++ b/lisp/gnus/shr.el
@@ -181,7 +181,7 @@ redirects somewhere else."
181 result)) 181 result))
182 (dolist (sub dom) 182 (dolist (sub dom)
183 (if (stringp sub) 183 (if (stringp sub)
184 (push (cons :text sub) result) 184 (push (cons 'text sub) result)
185 (push (shr-transform-dom sub) result))) 185 (push (shr-transform-dom sub) result)))
186 (nreverse result))) 186 (nreverse result)))
187 187
@@ -194,7 +194,7 @@ redirects somewhere else."
194(defun shr-generic (cont) 194(defun shr-generic (cont)
195 (dolist (sub cont) 195 (dolist (sub cont)
196 (cond 196 (cond
197 ((eq (car sub) :text) 197 ((eq (car sub) 'text)
198 (shr-insert (cdr sub))) 198 (shr-insert (cdr sub)))
199 ((listp (cdr sub)) 199 ((listp (cdr sub))
200 (shr-descend sub))))) 200 (shr-descend sub)))))
@@ -524,7 +524,7 @@ Return a string with image data."
524 (url (or url (cdr (assq :src cont))))) 524 (url (or url (cdr (assq :src cont)))))
525 (let ((start (point-marker))) 525 (let ((start (point-marker)))
526 (when (zerop (length alt)) 526 (when (zerop (length alt))
527 (setq alt "[img]")) 527 (setq alt "*"))
528 (cond 528 (cond
529 ((or (member (cdr (assq :height cont)) '("0" "1")) 529 ((or (member (cdr (assq :height cont)) '("0" "1"))
530 (member (cdr (assq :width cont)) '("0" "1"))) 530 (member (cdr (assq :width cont)) '("0" "1")))