;;; nnir.el --- search mail with various search engines -*- coding: iso-8859-1 -*-
;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-;; 2007, 2008, 2009 Free Software Foundation, Inc.
+;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Kai Großjohann <grossjohann@ls6.cs.uni-dortmund.de>
;; Swish-e and Swish++ backends by:
;; The most recent version of this can always be fetched from the Gnus
-;; CVS repository. See http://www.gnus.org/ for more information.
+;; repository. See http://www.gnus.org/ for more information.
;; This code is still in the development stage but I'd like other
;; people to have a look at it. Please do not hesitate to contact me
;; I have tried to make the code expandable. Basically, it is divided
;; into two layers. The upper layer is somewhat like the `nnvirtual'
-;; or `nnkiboze' backends: given a specification of what articles to
-;; show from another backend, it creates a group containing exactly
-;; those articles. The lower layer issues a query to a search engine
-;; and produces such a specification of what articles to show from the
+;; backend: given a specification of what articles to show from
+;; another backend, it creates a group containing exactly those
+;; articles. The lower layer issues a query to a search engine and
+;; produces such a specification of what articles to show from the
;; other backend.
;; The interface between the two layers consists of the single
(gnus-declare-backend "nnir" 'mail)
(defvar nnir-imap-search-field "TEXT"
- "The IMAP search item when doing an nnir search")
+ "The IMAP search item when doing an nnir search. To use raw
+ imap queries by default set this to \"\"")
(defvar nnir-imap-search-arguments
'(("Whole message" . "TEXT")
("Subject" . "SUBJECT")
("To" . "TO")
("From" . "FROM")
- (nil . "HEADER \"%s\""))
+ ("Head" . "HEADER \"%s\"")
+ (nil . ""))
"Mapping from user readable strings to IMAP search items for use in nnir")
(defvar nnir-imap-search-argument-history ()
"The history for querying search options in nnir")
+(defvar nnir-get-article-nov-override-function nil
+ "If non-nil, a function that will be passed each search result. This
+should return a message's headers in NOV format.
+
+If this variable is nil, or if the provided function returns nil for a search
+result, `gnus-retrieve-headers' will be called instead.")
+
+
;;; Developer Extension Variable:
(defvar nnir-engines
and show thread that contains this article."
(interactive)
(unless (eq 'nnir (car (gnus-find-method-for-group gnus-newsgroup-name)))
- (error "Can't execute this command unless in nnir group."))
+ (error "Can't execute this command unless in nnir group"))
(let* ((cur (gnus-summary-article-number))
(group (nnir-artlist-artitem-group nnir-artlist cur))
(backend-number (nnir-artlist-artitem-number nnir-artlist cur))
;; Just set the server variables appropriately.
(nnoo-change-server 'nnir server definitions))
-(deffoo nnir-request-group (group &optional server fast)
+(deffoo nnir-request-group (group &optional server fast info)
"GROUP is the query string."
(nnir-possibly-change-server server)
;; Check for cache and return that if appropriate.
nnir-artlist
;; Cache miss.
(setq nnir-artlist (nnir-run-query group)))
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(if (zerop (length nnir-artlist))
(progn
(setq nnir-current-query nil
(nnir-possibly-change-server server)
(let ((gnus-override-method
(gnus-server-to-method server)))
- (case (setq foo (gnus-retrieve-headers (list artno) artfullgroup nil))
- (nov
- (goto-char (point-min))
- (setq novitem (nnheader-parse-nov))
- (unless novitem
- (pop-to-buffer nntp-server-buffer)
- (error
- "nnheader-parse-nov returned nil for article %s in group %s"
- artno artfullgroup)))
- (headers
- (goto-char (point-min))
- (setq novitem (nnheader-parse-head))
- (unless novitem
- (pop-to-buffer nntp-server-buffer)
- (error
- "nnheader-parse-head returned nil for article %s in group %s"
- artno artfullgroup)))
- (t (error "Unknown header type %s while requesting article %s of group %s"
- foo artno artfullgroup))))
+ ;; if nnir-get-article-nov-override-function is set, use it
+ (if nnir-get-article-nov-override-function
+ (setq novitem (funcall nnir-get-article-nov-override-function
+ artitem))
+ ;; else, set novitem through nnheader-parse-nov/nnheader-parse-head
+ (case (setq foo (gnus-retrieve-headers (list artno)
+ artfullgroup nil))
+ (nov
+ (goto-char (point-min))
+ (setq novitem (nnheader-parse-nov))
+ (unless novitem
+ (pop-to-buffer nntp-server-buffer)
+ (error
+ "nnheader-parse-nov returned nil for article %s in group %s"
+ artno artfullgroup)))
+ (headers
+ (goto-char (point-min))
+ (setq novitem (nnheader-parse-head))
+ (unless novitem
+ (pop-to-buffer nntp-server-buffer)
+ (error
+ "nnheader-parse-head returned nil for article %s in group %s"
+ artno artfullgroup)))
+ (t (error "Unknown header type %s while requesting article %s of group %s"
+ foo artno artfullgroup)))))
;; replace article number in original group with article number
;; in nnir group
(mail-header-set-number novitem art)
(when (file-readable-p (concat prefix dirnam article))
;; remove trailing slash and, for nnmaildir, cur/new/tmp
(setq dirnam
- (substring dirnam 0 (if (string= server "nnmaildir:") -5 -1)))
+ (substring dirnam 0
+ (if (string= (gnus-group-server server) "nnmaildir")
+ -5 -1)))
;; Set group to dirnam without any leading dots or slashes,
;; and with all subsequent slashes replaced by dots
"[/\\]" "." t)))
(vector (nnir-group-full-name group server)
- (if (string= server "nnmaildir:")
+ (if (string= (gnus-group-server server) "nnmaildir")
(nnmaildir-base-name-to-article-number
(substring article 0 (string-match ":" article))
group nil)
"Run given query agains waissearch. Returns vector of (group name, file name)
pairs (also vectors, actually)."
(when group
- (error "The freeWAIS-sf backend cannot search specific groups."))
+ (error "The freeWAIS-sf backend cannot search specific groups"))
(save-excursion
(let ((qstring (cdr (assq 'query query)))
(prefix (nnir-read-server-parm 'nnir-wais-remove-prefix server))
(autoload 'imap-search "imap")
(autoload 'imap-quote-specials "imap")
+(eval-when-compile
+ (autoload 'nnimap-buffer "nnimap")
+ (autoload 'nnimap-command "nnimap")
+ (autoload 'nnimap-possibly-change-group "nnimap"))
+
(defun nnir-run-imap (query srv &optional group-option)
"Run a search against an IMAP back-end server.
This uses a custom query language parser; see `nnir-imap-make-query' for
(defs (caddr (gnus-server-to-method srv)))
(criteria (or (cdr (assq 'criteria query))
nnir-imap-search-field))
- artlist buf)
+ (gnus-inhibit-demon t)
+ artlist)
(message "Opening server %s" server)
(condition-case ()
- (when (nnimap-open-server server defs) ;; xxx
- (setq buf nnimap-server-buffer) ;; xxx
- (message "Searching %s..." group)
- (let ((arts 0)
- (mbx (gnus-group-real-name group)))
- (when (imap-mailbox-select mbx nil buf)
- (mapc
- (lambda (artnum)
- (push (vector group artnum 1) artlist)
- (setq arts (1+ arts)))
- (imap-search (nnir-imap-make-query criteria qstring) buf))
- (message "Searching %s... %d matches" mbx arts)))
- (message "Searching %s...done" group))
- (quit nil))
+ (when (nnimap-possibly-change-group (gnus-group-short-name group) server)
+ (with-current-buffer (nnimap-buffer)
+ (message "Searching %s..." group)
+ (let ((arts 0)
+ (result
+ (nnimap-command "UID SEARCH %s"
+ (if (string= criteria "")
+ qstring
+ (nnir-imap-make-query criteria qstring)
+ ))))
+ (mapc
+ (lambda (artnum)
+ (push (vector group artnum 1) artlist)
+ (setq arts (1+ arts)))
+ (and (car result)
+ (delete 0 (mapcar #'string-to-number
+ (cdr (assoc "SEARCH" (cdr result)))))))
+ (message "Searching %s... %d matches" group arts)))
+ (message "Searching %s...done" group))
+ (quit nil))
(reverse artlist))))
(defun nnir-imap-make-query (criteria qstring)
Windows NT 4.0."
(when group
- (error "The swish++ backend cannot search specific groups."))
+ (error "The swish++ backend cannot search specific groups"))
(save-excursion
(let ( (qstring (cdr (assq 'query query)))
;; is sufficient. Note that we can't only use the value of
;; nnml-use-compressed-files because old articles might have been
;; saved with a different value.
- (article-pattern (if (string= server "nnmaildir:")
+ (article-pattern (if (string= (gnus-group-server server) "nnmaildir")
":[0-9]+"
"^[0-9]+\\(\\.[a-z0-9]+\\)?$"))
score artno dirnam filenam)
(when (equal "" qstring)
- (error "swish++: You didn't enter anything."))
+ (error "swish++: You didn't enter anything"))
(set-buffer (get-buffer-create nnir-tmp-buffer))
(erase-buffer)
;; swish-e crashes with empty parameter to "-w" on commandline...
(when group
- (error "The swish-e backend cannot search specific groups."))
+ (error "The swish-e backend cannot search specific groups"))
(save-excursion
(let ((qstring (cdr (assq 'query query)))
artlist score artno dirnam group )
(when (equal "" qstring)
- (error "swish-e: You didn't enter anything."))
+ (error "swish-e: You didn't enter anything"))
(set-buffer (get-buffer-create nnir-tmp-buffer))
(erase-buffer)
(when group
(error "The Namazu backend cannot search specific groups"))
(save-excursion
- (let ((article-pattern (if (string= server "nnmaildir:")
+ (let ((article-pattern (if (string= (gnus-group-server server) "nnmaildir")
":[0-9]+"
"^[0-9]+$"))
artlist
"find" group "-type" "f" "-name" "[0-9]*" "-exec"
"grep"
`("-l" ,@(and grep-options
- ;; Note: the 3rd arg of `split-string' is not
- ;; available in Emacs 21.
- (delete "" (split-string grep-options "\\s-")))
+ (split-string grep-options "\\s-" t))
"-e" ,regexp "{}" "+"))))
;; Translate relative paths to group names.
(while (not (eobp))
- (let* ((path (delete
- ""
- (split-string
- (buffer-substring (point) (line-end-position)) "/")))
+ (let* ((path (split-string
+ (buffer-substring (point) (line-end-position)) "/" t))
(art (string-to-number (car (last path)))))
(while (string= "." (car path))
(setq path (cdr path)))
(let ((sym (car parmspec))
(prompt (cdr parmspec)))
(if (listp prompt)
- (let* ((result (apply 'completing-read prompt))
+ (let* ((result (gnus-completing-read prompt nil))
(mapping (or (assoc result nnir-imap-search-arguments)
(assoc nil nnir-imap-search-arguments))))
(cons sym (format (cdr mapping) result)))
;; The end.
(provide 'nnir)
-;; arch-tag: 9b3fecf8-4397-4bbb-bf3c-6ac3cbbc6664
;;; nnir.el ends here