Compare commits

...

78 commits

Author SHA1 Message Date
Eric Abrahamsen
a40b1be061 Fix gnus-search-query-expand-key
* lisp/gnus/gnus-search.el (gnus-search-query-expand-key): Use the
proper built-in functions, rather than trying to replicate string
completion ourself.
2020-10-08 22:58:19 -07:00
Eric Abrahamsen
3d333b146a Provide completion of search keys when reading the query
* lisp/gnus/gnus-search.el (gnus-search-minibuffer-map): Keymap for
use in reading the query.
(gnus-search-complete-key): Completion function bound to TAB.
(gnus-search-make-specs): Use `read-from-minibuffer', with our new
keymap.
2020-10-08 22:36:24 -07:00
Eric Abrahamsen
5e786dc28b Dumb updates
Mostly updating dates and versions, and some formatting stuff.
2020-10-08 22:25:11 -07:00
Eric Abrahamsen
da6675fdb5 WIP on gnus-search 2020-09-13 10:21:10 -07:00
Eric Abrahamsen
9dae21a631 Missing comma in notmuch search command
Thanks to George McNinch

* lisp/gnus/gnus-search.el (gnus-search-indexed-search-command):
  Missing comma in backquote template.
2017-08-15 08:54:36 -07:00
Eric Abrahamsen
79597457a9 Move the config-file slot to the base gnus-search-indexed class
* lisp/gnus/gnus-search.el (gnus-search-indexed): They pretty much all
  have or can have configuration files.
2017-06-10 12:28:10 +08:00
Eric Abrahamsen
7d34930785 Fix to 7f21251a56, don't parse address key
* lisp/gnus/gnus-search.el (gnus-search-transform-expression): There's
  no need to parenthesize those expressions. Nested parentheses
  actually raise a parsing error, which is another bug.
2017-06-10 12:28:10 +08:00
Eric Abrahamsen
d249e6bc4a Restore thread search behavior
* lisp/gnus/gnus-search.el (gnus-search-thread): Make this function
  produce an engine-agnostic search query.
  (gnus-search-prepare-query): Fix dumb error.
  (gnus-search-indexed-search-command): Edit to handle the 'thread
  key.
  (gnus-search-run-search): In thread searches, have the imap
  implementation expand Message-Id searches to include the References
  header. Also, somewhere along the way we lost the
  `gnus-search-get-active' call.
  (gnus-search-run-search): For Notmuch, add an :around method on this
  function, which does a primary search for thread-ids, then passes
  off to the secondary search for the messages themselves.
  (gnus-search-transform-expression): Forgot
  that multiple nested ORs have to be parenthesized for IMAP.
* lisp/gnus/nnselect.el (nnselect-request-thread): Alter function to
  pass in a generic thread search query; no longer calls imap-specific
  code.
2017-06-10 12:26:40 +08:00
Eric Abrahamsen
1f821aee7f New defsubst gnus-search-single-p
* lisp/gnus/gnus-search.el (gnus-search-single-p): Convenience
  function for checking if a search is meant to return a single
  message: ie, the query is only (id . "<msg-id>").
  (gnus-search-run-search): Use in the imap method.
  (gnus-search-indexed-parse-output): Use in the indexed method.
2017-06-05 16:04:35 +08:00
Eric Abrahamsen
b23fe432f0 Fix bug in indexed gnus-search-run-search method
* lisp/gnus/gnus-search.el (gnus-search-run-search): In case of error,
  this would have returned the actual process buffer for the notmuch
  process: it should return nil.
2017-06-02 22:10:11 +08:00
Eric Abrahamsen
353288d9e3 Don't use nconc
* lisp/gnus/gnus-search.el (gnus-search-indexed-search-command): Use
  append instead of nconc, nconc modifies destructively and makes a
  mess.
2017-06-01 21:25:02 +08:00
Eric Abrahamsen
039df5e777 Provide a bit more backward-compatibility
* lisp/gnus/gnus-search.el (nnir-method-default-engines): Note
  obsolete variable.
  (gnus-search-server-to-engine): Handle old 'nnir-search-engine
  server parameter keys. Additionally, warn when no engine can be
  found for a server.
2017-06-01 12:18:21 +08:00
Eric Abrahamsen
7f21251a56 Don't parse the address: key
* lisp/gnus/gnus-search.el (gnus-search-query-parse-kv): Allow this
  key to pass unmolested. Handle it in the individual search engines.
  (gnus-search-query-parse-contact): Produce the "address" key as
  necessary.
  (gnus-search-transform-expression): Handle "address" key explicitly
  in imap, notmuch, and namazu backends.
2017-05-26 14:27:56 +08:00
Eric Abrahamsen
9965b9b340 Restore IMAP ability to short-circuit message-id searches
* lisp/gnus/gnus-search.el (gnus-search-run-search): When searching
  for a single message via message-id, nnir originally used a loop
  break when the message was found.  Reinstate this functionality,
  albeit through different means.
2017-05-26 13:59:03 +08:00
Eric Abrahamsen
64bf8de675 Messed up rebase 2017-05-26 13:47:43 +08:00
Eric Abrahamsen
09aff5299d Do result limiting in the indexed engine process
* lisp/gnus/gnus-search.el (gnus-search-indexed-parse-output): Limit
  number of results, in case the engine didn't handle it.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
79b5546079 Add gnus-search-grep abstract engine
* lisp/gnus/gnus-search.el (gnus-search-grep): New abstract mixin
  engine, providing 'grep-program and 'grep-options slots.
  (gnus-search-grep-search): Method for doing secondary grep searches
  over previous search results.
  (gnus-search-find-grep): Inherit from gnus-search-grep.
  (gnus-search-indexed): Likewise.
  (gnus-search-indexed-parse-output): Add a grep pass pas part of this.
  (gnus-search-run-search): Use the grep options in the find-grep
  engine.
  (gnus-search-prepare-query): Find the grep: key when parsing the
  query.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
2ae25496a1 Fix bum namazu search command
* lisp/gnus/gnus-search.el (gnus-search-indexed-search-command): Had
  named it incorrectly. Also switch to using nconc.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
8ea8644653 Refactor parsing of indexed search engine output
* lisp/gnus/gnus-search.el (gnus-search-indexed-parse-output): Rename
  `gnus-search-indexed-massage-output' to this. All indexed search
  engines now use this method.
  (gnus-search-index-extract): This new method is now distinct to each
  engine. All it does is extract a single search result from the
  output buffer.

Remove `gnus-search-add-result' and `gnus-search-compose-result',
these are now part of `gnus-search-indexed-parse-output'.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
371748dbdc Switch base massage-output method for indexed search engines
* lisp/gnus/gnus-search.el (gnus-search-indexed-massage-output): I had
  been using the namazu version, which was wrong -- that's very
  namazue specific. Use the notmuch version: the base method should
  handle plain lists of absolute filenames.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
9eebc881e9 More comments, small improvements
* lisp/gnus/gnus-search.el (gnus-search-transform-expression): Handle
  the 'body term.
  (gnus-search-transform-expression): Interpret more terms as
  "author", handle 'body.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
66a7735817 WIP on rebase 2017-05-26 13:47:43 +08:00
Eric Abrahamsen
37e044feb6 Don't do any sorting at all in gnus-search 2017-05-26 13:47:43 +08:00
Eric Abrahamsen
a4fe929956 Notmuch query transformation improvements
* lisp/gnus/gnus-search.el (gnus-search-transform-expression): A
  "body" keyword should just be removed. Also, strip angle brackets
  from message ids.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
32a328f83e Fix for parsing delimited strings
* lisp/gnus/gnus-search.el (gnus-search-query-next-symbol): Hadn't
  quite gotten this all the way over to the new definition of
  `gnus-search-query-return-string'.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
9e61dd3148 Find-grep can only search on plain strings
* lisp/gnus/gnus-search.el (gnus-search-indexed-massage-output): Drop
  any list expression.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
9c57f16b44 Some refactoring of gnus-search-run-query
* lisp/gnus/gnus-search.el (gnus-search-run-query): Move results
  sorting here.
  (gnus-search-run-search): No need to sort here. Also, loop
  accept-process-output on process-live-p, apparently it doesn't
  necessarily get *all* the output.

Other formatting and variable naming fixes.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
cc541ba3f8 Missing a base implementation of transform-expression for strings
* lisp/gnus/gnus-search.el (gnus-search-transform-expression):
  Othewise plain string searches would raise an error!
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
a43c41064a Refactor parsing/no parsing of queries
* lisp/gnus/gnus-search.el (gnus-search-prepare-query): Only check
  `gnus-search-use-parsed-queries' here.
  (gnus-search-make-query-string): New engine method responsible for
  main final check of whether to use a parsed or raw query.
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
ede46affca Avoid circular import
* lisp/gnus/gnus-group.el: Don't require 'gnus-search at top
  level. Better solution for this?
2017-05-26 13:47:43 +08:00
Eric Abrahamsen
c89e129223 Change "no-parse" query meta-key to "raw"
* lisp/gnus/gnus-search.el (gnus-search-prepare-query): Easier to
  type, and makes a little more sense.
* lisp/gnus/gnus-group.el (gnus-group-make-search-group): Swap out
  here.
2017-05-26 13:47:42 +08:00
Eric Abrahamsen
fcf327bcdc Add Mairix search engine 2017-05-26 13:47:42 +08:00
Eric Abrahamsen
6a4dc138ab WIP on documentation 2017-05-26 13:47:42 +08:00
Eric Abrahamsen
e39079c74c Remove Hyrex search engine
* lisp/gnus/gnus-search.el: Yank the whole engine out, it was already
  obsolete, and now seems to not exist at all.
* doc/misc/gnus.texi: Remove from docs.
2017-05-26 13:47:42 +08:00
Eric Abrahamsen
b086d9a818 Handle regexp and wildcard search terms
* lisp/gnus/gnus-search.el (gnus-search-query-return-string): Fix up
  this function to be a little more general. Quoted strings are now
  returned with quotes.
  (gnus-search-run-search): Pick up and (partially) use the FUZZY IMAP
  capability.
  (gnus-search-transform-expression): In IMAP, check for wildcards and
  turn them into FUZZY as appropriate. Drop regexps.
  (gnus-search-indexed-massage-output):
  (gnus-search-transform-expression): In Notmuch, only drop leading
  asterisks.
* test/lisp/gnus/search-tests.el (gnus-s-delimited-string): Add test
  for `gnus-search-query-return-string'.
2017-05-26 13:47:42 +08:00
Eric Abrahamsen
5e80a4da88 Create general gnus-search-indexed-massage-output method
* lisp/gnus/gnus-search.el (gnus-search-indexed-massage-output): Take
  the namazu version, and install it as general for all
  gnus-search-indexed engines. Probably they all can use the same
  method, but I haven't taken the time to test them all yet.
2017-05-21 21:05:13 +08:00
Eric Abrahamsen
c7cf2127d8 Move search group creation functions to gnus-group.el
* lisp/gnus/gnus-group.el (gnus-group-make-search-group,
  gnus-group-make-permanent-search-group): These two functions live in
  gnus.group.el now.
* lisp/gnus/gnus-search.el: Remove from here.
2017-05-21 21:05:13 +08:00
Eric Abrahamsen
31514a043a Add function gnus-search-prepare-query
* lisp/gnus/gnus-search.el (gnus-search-prepare-query): Check for
  "top-level" meta search keys and parse them into the query
  structure, alongside the query itself.
2017-05-21 21:04:16 +08:00
Eric Abrahamsen
ad83eabc85 Make related change to nnselect.el
Move *-make-search-group stuff to gnus-search.el
2017-05-21 21:04:16 +08:00
Eric Abrahamsen
a80b6f9da4 Rename nnir.el to gnus-search.el
And everything in it.
2017-05-21 21:04:16 +08:00
Eric Abrahamsen
a1cfb383e7 WIP on a generalized search query language for Gnus
* lisp/gnus/nnir.el (nnir-search-parse-query, nnir-query-next-expr,
  nnir-query-next-term, nnir-query-next-symbol,
  nnir-query-peek-symbol, nnir-query-end-of-input,
  nnir-query-parse-kv, nnir-query-parse-date nnir-query-parse-mark,
  nnir-query-parse-contact): Functions for reading the generalized
  search query language and parsing it into a sexp.
  (gnus-search-engine, gnus-search-process, gnus-search-indexed): Base
  classes for creating search-engine specific engine classes.
  (nnir-run-search): Method for running one engine's search routine.
  (nnir-search-transform-top-level, nnir-search-transform-expression):
  Methods for transforming the parsed sexp query format into a
  backend-specific string.
  (nnir-search-indexed-search-command,
  nnir-search-indexed-massage-output): Methods used by indexed
  backends to retrieve their results.
* test/lisp/gnus/search-tests.el: Basic set of tests for the parsing
  routine.
2017-05-21 20:44:05 +08:00
Andrew G Cohen
f723102b32 * lisp/gnus/nnir.el (nnir-make-specs): Use the current buffer. 2017-05-17 10:39:57 +08:00
Andrew G Cohen
ac63735def * lisp/gnus/gnus-srvr.el (gnus-server-mode-map): Use ephemeral group 2017-05-15 10:45:45 +08:00
Andrew G Cohen
ddfd397305 Improve search and select group creation
* lisp/gnus/gnus-group.el (gnus-group-make-search-group): Make sure
new group is inserted into the group buffer.
* lisp/gnus/nnselect.el (nnselect-request-create-group): Improve input
of selection function.
2017-05-13 15:05:27 +08:00
Andrew G Cohen
046785e5b7 Redo entry functions for making search groups
* lisp/gnus/gnus-group.el (gnus-group-make-search-group):
(gnus-group-read-ephemeral-search-group): Rename these functions to be
more consistent with other group creation functions, and move to
gnus-group.el.
* lisp/gnus/nnir.el (nnir-make-specs): Refactor new function to ease
search group creation.
2017-05-12 09:40:03 +08:00
Andrew G Cohen
7f263d8a9d Inline nnselect helper macros
* lisp/gnus/gnus-registry.el (gnus-nnselect-group-p):
* lisp/gnus/gnus-sum.el (nnselect-article-rsv): Silence byte-compiler.
* lisp/gnus/nnselect.el (nnselect-group-server): New function.
(nnselect-artlist-length):
(nnselect-artlist-article):
(nnselect-artitem-group):
(nnselect-artitem-number):
(nnselect-artitem-rsv):
(nnselect-article-group):
(nnselect-article-number):
(nnselect-article-rsv):
(nnselect-article-id):
(nnselect-categorize):
(ids-by-group):
(numbers-by-group): Inline for speed.
2017-05-11 10:36:40 +08:00
Andrew G Cohen
0e2516b72c * lisp/gnus/nnselect.el (nnselect-request-rename-group): Allow it. 2017-05-11 10:07:19 +08:00
Andrew G Cohen
232de89341 * lisp/gnus/nnselect.el (nnselect-request-group): Don't close group. 2017-05-11 10:07:19 +08:00
Andrew G Cohen
c838fe43cf * lisp/gnus/nnselect.el (nnselect-server-opened): Just return t. 2017-05-11 10:07:18 +08:00
Andrew G Cohen
28f6e8a04b Restore accidentally remove gnus-summary-make-search-group
* lisp/gnus/nnselect.el (gnus-summary-make-search-group): Restore the
function that was removed in a fit of overzealousness.
2017-05-09 10:13:50 +08:00
Andrew G Cohen
0f36c34ad2 Improve nnselect-request-article
* lisp/gnus/nnselect.el (nnselect-request-article): Recode the
selection of the article server.
(nnselect-request-thread): Spelling.
2017-05-09 10:11:47 +08:00
Andrew G Cohen
57a86e5b2c Improve group-info handling in nnselect
* lisp/gnus/nnselect.el (nnselect-request-group):
(nnselect-push-info): Use info argument to functions or retrieve the
group info. If the info is null (for example the group might have been
killed) don't try to update it.
2017-05-09 10:08:55 +08:00
Andrew G Cohen
ba7b51f27f Remove unnecessary listing in nnselect-categorize
* lisp/gnus/nnselect.el (nnselect-categorize): Remove unneeded extra
list around a category value.
(nnselect-retrieve-headers):
(nnselect-request-expire-articles):
(nnselect-request-set-mark):
(nnselect-request-update-info):
(nnselect-request-thread):
(nnselect-push-info):
(gnus-group-make-permanent-search-group): Accommodate change to
nnselect-categorize.
* lisp/gnus/nnir.el (nnir-run-query): Accommodate change to
nnselect-categorize.
2017-05-09 07:51:56 +08:00
Andrew G Cohen
55c5e699d8 Use gnus-newsgroup-selection instead of nnselect-artlist
* lisp/gnus/nnselect.el (nnselect-retrieve-headers):
(nnselect-request-thread):
(nnselect-retrieve-headers):
(nnselect-close-group): Use the summary local variable
gnus-newsgroup-selection rather than the internal nnselect-artlist
variable.
(nnselect-request-group):
(nnselect-request-move-article):
(nnselect-request-expire-articles):
(nnselect-warp-to-article):
(nnselect-request-set-mark):
(nnselect-request-thread): Don't unnecessarily retrieve the
nnselect-artlist value.
2017-05-09 07:44:19 +08:00
Andrew G Cohen
7c3595470d Fix pushing marks on nnselect exit
* lisp/gnus/nnselect.el (nnselect-push-info): Deal with scoring.
Ensure that mark lists are properly compressed before saving. Add only
the group-specific articles to the `seen' lists.
2017-05-06 21:24:37 +08:00
Andrew G Cohen
cab358ed19 New gnus summary sorting functions on rsv
* lisp/gnus/gnus-sum.el (gnus-article-sort-by-rsv):
(gnus-thread-sort-by-rsv): New functions to allow sorting by rsv in
nnselect groups.
2017-05-06 16:11:58 +08:00
Andrew G Cohen
02c66f38bb Remove obsolete variable nnselect-summary-line-format
* lisp/gnus/nnselect.el (nnselect-summary-line-format): This variable
is no longer needed.
2017-05-04 14:34:42 +08:00
Andrew G Cohen
2f67fadd86 Use fetch-old-headers group parameter in nnselect
* lisp/gnus/nnselect.el (nnselect-retrieve-headers): Use
gnus-fetch-old-headers parameter for original article group.
2017-05-02 10:33:59 +08:00
Andrew G Cohen
9e9fdd950d Disable nnselect-server-opened check
* lisp/gnus/nnselect.el (nnselect-server-opened): Always return t for
now. This is disabled for testing purposes.
(nnselect-possibly-change-group): Eliminate unnecessary test for
server openness.
2017-04-29 10:03:11 +08:00
Andrew G Cohen
130bba8a69 Improve nnselect-request-article
* lisp/gnus/nnselect.el (nnselect-request-article): Rework to prepare
for universal search language.
(nnselect-request-thread): Remove duplicate declare-function.
2017-04-29 09:50:20 +08:00
Andrew G Cohen
5e7a373f2c Remove unnecessary check gnus-nnselect-group-p
* lisp/gnus/gnus-msg.el (gnus-setup-message):
* lisp/gnus/gnus-sum.el (gnus-summary-line-format-alist): No need to
check that we are coming from an nnselect group now that we use
gnus-newsgroup-selection.
2017-04-29 07:49:39 +08:00
Andrew G Cohen
cbe6a2b998 Don't stomp on local variables in gnus-msg
* lisp/gnus/gnus-msg.el (gnus-setup-message):
(gnus-msg-mail):
(gnus-group-mail):
(gnus-group-post-news):
(gnus-summary-news-other-window):
(gnus-summary-post-news): Use let rather than setq for temporary
overriding of gnus-newsgroup-name.
2017-04-29 07:43:54 +08:00
Andrew G Cohen
1af8d59c6b Introduce summary-local variable gnus-newsgroup-selection
* lisp/gnus/gnus-sum.el (gnus-newsgroup-selection): Introduce a new
gnus-summary-local-variable to hold an nnselect article list.
* lisp/gnus/nnselect.el: Use the summary-local variable where
appropriate.
2017-04-27 15:27:00 +08:00
Andrew G Cohen
6c64891e88 Restore article retrieval by message-id in nnselect
* lisp/gnus/nnselect.el (nnselect-request-article): If passed a
message-id attempt to find an article by searching.

; Silence byte-compiler

* lisp/gnus/nnselect.el (nnir-run-query): declare-function to silence
byte-compiler.
2017-04-27 15:27:00 +08:00
Andrew G Cohen
8a96272dde Restore article retrieval by message-id in nnselect
* lisp/gnus/nnselect.el (nnselect-request-article): If passed a
message-id attempt to find an article by searching.
2017-04-25 13:26:59 +08:00
Andrew G Cohen
01a97228ed Fix requesting sparse articles in gnus
* lisp/gnus/gnus-art.el (gnus-request-article-this-buffer): Delete the
sparse article number from the list, not its id.
2017-04-25 13:26:59 +08:00
Andrew G Cohen
48dad784a2 Temporary function to ease search group creation
* lisp/gnus/nnselect.el (gnus-group-make-permanent-search-group):
(gnus-group-make-search-group): Allow permanent group creation.
* lisp/gnus/gnus-group.el (gnus-group-group-map): Bind it to "G g" in
the group buffer.
2017-04-25 09:55:36 +08:00
Glenn Morris
e7fd7245e8 Don't advertise s_client in tls.el docs
* lisp/net/tls.el (tls-end-of-info, tls-success, tls-untrusted):
Don't mention s_client in docs.
; * doc/misc/gnus.texi (Direct Functions): Comment.
2017-04-25 09:14:35 +08:00
Rob Browning
66d1ec0818 Remove s_client usage from tls.el
* lisp/net/tls.el (tls-program, tls-checktrust): Remove s_client.
Ref http://bugs.debian.org/766397
http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00803.html

; Backport this to Emacs 25.3, if there is one
2017-04-25 09:14:35 +08:00
Glenn Morris
bcf49f627d Further robustify cedet bootstrap to loaddefs not yet built
* lisp/cedet/semantic/util.el (semantic-something-to-tag-table):
Avoid void-function error when bootstrapping and semantic/loaddefs.el
does not yet exist.
2017-04-25 09:14:35 +08:00
Alan Third
e528a750da Fix XBM colour rendering in NS port (bug#22060)
src/nsimage.m (setXBMColor): Fix calculation of xbm_fg.
2017-04-25 09:14:35 +08:00
Vibhav Pant
5d21c627f7 Add support for IRCv3 message tags.
* erc-backend.el:
  erc-response: Add `tags' element.
  Add (erc-parse-tags).
  (erc-parse-server-response): Use (erc-parse-tags) to parse message
  tags (if any), and store them in `erc-resopnse' struct.

* erc.el: (erc-display-message): Expose message tags with text
  properties of the corresponding message line.
2017-04-25 09:14:35 +08:00
Lars Ingebrigtsen
7bbc43ec77 Add image sizing tests for an image that's narrow 2017-04-25 09:14:35 +08:00
Lars Ingebrigtsen
ec5a24989f Needlessly refactor tests for clarity 2017-04-25 09:14:35 +08:00
Andrew G Cohen
6ff9a4f22e ; Clean up parameter input for nnselect groups
* lisp/gnus/nnselect.el (nnselect-request-create-group): Better
argument parsing.
2017-04-24 10:53:07 +08:00
Andrew G Cohen
fd548f570b Merge branch 'nnselect' into feature/gnus-select 2017-04-24 09:28:32 +08:00
Andrew G Cohen
bbd2b1fbee ; Silence byte-compiler
* lisp/gnus/nnir.el: Require gnus.
(gnus-request-list): Autoload.
* lisp/gnus/nnselect.el: Require gnus-art.
(nnselect-request-set-mark): Use cl-destructuring-bind.
(nnir-run-query): Declare function.
(nnselect-request-thread): Use cl-incf.
(nnselect-push-info): Use cl-decf.
2017-04-23 20:08:29 +08:00
Andrew G Cohen
163313049b Initial landing of gnus nnselect backend
This is a new virtual backend for gnus, wherein any collection of
articles can be viewed as a gnus group (permanent or ephemeral).

* lisp/gnus/nnselect.el: New file.
* lisp/gnus/nnir.el: Remove the nnir backend but leave the search
functions.
* lisp/gnus/nnimap.el: Replace nnir backend related items with
nnselect.
(gnus-refer-thread-use-search): Renamed from gnus-refer-thread-use-nnir
(nnselect-search-thread): New function.
(nnimap-request-thread): Use it.
* lisp/gnus/gnus-group.el (gnus-group-make-search-group): New function
replacing gnus-group-make-nnir-group.
* lisp/gnus/gnus-msg.el: Replace nnir backend related items with
nnselect.
(gnus-setup-message): Pass virtual group article number to
gnus-inews-add-send-actions.
* lisp/gnus/gnus-registry.el (gnus-registry-action): Find the
originating article group when in an nnselect group.
(gnus-registry-ignore-group-p): Ignore virtual groups.
* lisp/gnus/gnus-srvr.el (gnus-group-make-search-group): Use new
function.
* lisp/gnus/gnus-sum.el (nnselect-article-): Use new nnselect backend
functions.
(gnus-summary-line-format-alist): Rework specs specific to nnselect
groups.
(nnselect-artlist):
(gnus-summary-local-variables): A new group-local variable.
2017-04-23 19:02:14 +08:00
20 changed files with 3679 additions and 2288 deletions

View file

@ -404,33 +404,26 @@ This manual corresponds to Gnus v5.13
@end iftex
@menu
* Starting Up:: Finding news can be a pain.
* Group Buffer:: Selecting, subscribing and killing groups.
* Summary Buffer:: Reading, saving and posting articles.
* Article Buffer:: Displaying and handling articles.
* Composing Messages:: Information on sending mail and news.
* Select Methods:: Gnus reads all messages from various select methods.
* Scoring:: Assigning values to articles.
* Searching:: Mail and News search engines.
* Various:: General purpose settings.
* The End:: Farewell and goodbye.
* Appendices:: Terminology, Emacs intro, @acronym{FAQ}, History, Internals.
* GNU Free Documentation License:: The license for this documentation.
* Index:: Variable, function and concept index.
* Key Index:: Key Index.
* Starting Up:: Finding news can be a pain.
* Group Buffer:: Selecting, subscribing and killing groups.
* Summary Buffer:: Reading, saving and posting articles.
* Article Buffer:: Displaying and handling articles.
* Composing Messages:: Information on sending mail and news.
* Select Methods:: Gnus reads all messages from various select methods.
* Scoring:: Assigning values to articles.
* Searching:: Mail and News search engines.
* Various:: General purpose settings.
* The End:: Farewell and goodbye.
* Appendices:: Terminology, Emacs intro, @acronym{FAQ}, History, Internals.
* GNU Free Documentation License:: The license for this documentation.
* Index:: Variable, function and concept index.
* Key Index:: Key Index.
@c Doesn't work right in html.
@c FIXME Do this in a more standard way.
@ifinfo
Other related manuals
* Message:(message). Composing messages.
* Emacs-MIME:(emacs-mime). Composing messages; @acronym{MIME}-specific parts.
* Sieve:(sieve). Managing Sieve scripts in Emacs.
* EasyPG:(epa). @acronym{PGP/MIME} with Gnus.
* SASL:(sasl). @acronym{SASL} authentication in Emacs.
@end ifinfo
@detailmenu
--- The Detailed Node Listing ---
@ -439,7 +432,6 @@ Starting Gnus
* Finding the News:: Choosing a method for getting news.
* The Server is Down:: How can I read my mail then?
* Slave Gnusae:: You can have more than one Gnus active at a time.
* Fetching a Group:: Starting Gnus just to read a group.
* New Groups:: What is Gnus supposed to do with new groups?
* Changing Servers:: You may want to move from one server to another.
* Startup Files:: Those pesky startup files---@file{.newsrc}.
@ -597,7 +589,8 @@ Article Treatment
* Article Buttons:: Click on URLs, Message-IDs, addresses and the like.
* Article Button Levels:: Controlling appearance of buttons.
* Article Date:: Grumble, UT!
* Article Display:: Display various stuff---X-Face, Picons, Smileys, Gravatars
* Article Display:: Display various stuff:
X-Face, Picons, Gravatars, Smileys.
* Article Signature:: What is a signature?
* Article Miscellanea:: Various other stuff.
@ -661,12 +654,19 @@ Getting News
* NNTP:: Reading news from an @acronym{NNTP} server.
* News Spool:: Reading news from the local spool.
@acronym{NNTP}
NNTP
* Direct Functions:: Connecting directly to the server.
* Indirect Functions:: Connecting indirectly to the server.
* Common Variables:: Understood by several connection functions.
Using IMAP
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
* Customizing the IMAP Connection:: Variables for @acronym{IMAP} connection.
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
* Support for IMAP Extensions:: Getting extensions and labels from servers.
Getting Mail
* Mail in a Newsreader:: Important introductory notes.
@ -686,6 +686,7 @@ Getting Mail
Mail Sources
* Mail Source Specifiers:: How to specify what a mail source is.
* Mail Source Functions::
* Mail Source Customization:: Some variables that influence things.
* Fetching Mail:: Using the mail source specifiers.
@ -696,6 +697,10 @@ Choosing a Mail Back End
* Mail Spool:: Store your mail in a private spool?
* MH Spool:: An mhspool-like back end.
* Maildir:: Another one-file-per-message format.
* nnmaildir Group Parameters::
* Article Identification::
* NOV Data::
* Article Marks::
* Mail Folders:: Having one file for each group.
* Comparing Mail Back Ends:: An in-depth looks at pros and cons.
@ -735,10 +740,10 @@ The NNDiary Back End
The Gnus Diary Library
* Diary Summary Line Format:: A nicer summary buffer line format.
* Diary Articles Sorting:: A nicer way to sort messages.
* Diary Headers Generation:: Not doing it manually.
* Diary Group Parameters:: Not handling them manually.
* Diary Summary Line Format:: A nicer summary buffer line format.
* Diary Articles Sorting:: A nicer way to sort messages.
* Diary Headers Generation:: Not doing it manually.
* Diary Group Parameters:: Not handling them manually.
Gnus Unplugged
@ -796,18 +801,37 @@ Advanced Scoring
Searching
* nnir:: Searching with various engines.
* Specifying Search Engines::
* nnmairix:: Searching with Mairix.
nnir
Specifying Search Engines
* What is nnir?:: What does nnir do.
* What is nnir?:: What does @code{nnir} do?
* Basic Usage:: How to perform simple searches.
* Setting up nnir:: How to set up nnir.
* Setting up nnir:: How to set up @code{nnir}.
Setting up nnir
* Associating Engines:: How to associate engines.
* The imap Engine:: Imap configuration and usage.
* The gmane Engine:: Gmane configuration and usage.
* The swish++ Engine:: Swish++ configuration and usage.
* The swish-e Engine:: Swish-e configuration and usage.
* The namazu Engine:: Namazu configuration and usage.
* The notmuch Engine:: Notmuch configuration and usage.
* Customizations:: User customizable settings.
nnmairix
* About mairix:: About the mairix mail search engine
* nnmairix requirements:: What you will need for using nnmairix
* What nnmairix does:: What does nnmairix actually do?
* Setting up mairix:: Set up your mairix installation
* Configuring nnmairix:: Set up the nnmairix back end
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
* Propagating marks:: How to propagate marks from nnmairix groups
* nnmairix tips and tricks:: Some tips, tricks and examples
* nnmairix caveats:: Some more stuff you might want to know
Various
@ -823,6 +847,7 @@ Various
* Undo:: Some actions can be undone.
* Predicate Specifiers:: Specifying predicates.
* Moderation:: What to do if you're a moderator.
* Fetching a Group:: Starting Gnus just to read a group.
* Image Enhancements:: Modern versions of Emacs/XEmacs can display images.
* Fuzzy Matching:: What's the big fuzz?
* Thwarting Email Spam:: Simple ways to avoid unsolicited commercial email.
@ -847,8 +872,7 @@ Image Enhancements
* X-Face:: Display a funky, teensy black-and-white image.
* Face:: Display a funkier, teensier colored image.
* Smileys:: Show all those happy faces the way they were
meant to be shown.
* Smileys:: Show all those happy faces the way they were meant to be shown.
* Picons:: How to display pictures of what you're reading.
* Gravatars:: Display the avatar of people you read.
* XVarious:: Other XEmacsy Gnusey variables.
@ -871,23 +895,50 @@ Spam Package
* Extending the Spam package::
* Spam Statistics Package::
Spam Back Ends
* Blacklists and Whitelists::
* BBDB Whitelists::
* Gmane Spam Reporting::
* Anti-spam Hashcash Payments::
* Blackholes::
* Regular Expressions Header Matching::
* Bogofilter::
* SpamAssassin back end::
* ifile spam filtering::
* Spam Statistics Filtering::
* SpamOracle::
Spam Statistics Package
* Creating a spam-stat dictionary::
* Splitting mail using spam-stat::
* Low-level interface to the spam-stat dictionary::
The Gnus Registry
* Gnus Registry Setup::
* Registry Article Refer Method::
* Fancy splitting to parent::
* Store custom flags and keywords::
* Store arbitrary data::
The Gnus Cloud
* Gnus Cloud Setup::
* Gnus Cloud Usage::
Appendices
* XEmacs:: Requirements for installing under XEmacs.
* History:: How Gnus got where it is today.
* The Manual::
* On Writing Manuals:: Why this is not a beginner's guide.
* Terminology:: We use really difficult, like, words here.
* Customization:: Tailoring Gnus to your needs.
* Troubleshooting:: What you might try if things do not work.
* Gnus Reference Guide:: Rilly, rilly technical stuff.
* Emacs for Heathens:: A short introduction to Emacsian terms.
* Frequently Asked Questions:: The Gnus FAQ
History
@ -908,7 +959,7 @@ New Features
* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11.
* No Gnus:: Very punny. Gnus 5.12/5.13
* No Gnus:: Very punny. Gnus 5.12/5.13.
* Ma Gnus:: Celebrating 25 years of Gnus.
Customization
@ -981,15 +1032,15 @@ If you puzzle at any terms used in this manual, please refer to the
terminology section (@pxref{Terminology}).
@menu
* Finding the News:: Choosing a method for getting news.
* The Server is Down:: How can I read my mail then?
* Slave Gnusae:: You can have more than one Gnus active at a time.
* New Groups:: What is Gnus supposed to do with new groups?
* Changing Servers:: You may want to move from one server to another.
* Startup Files:: Those pesky startup files---@file{.newsrc}.
* Auto Save:: Recovering from a crash.
* The Active File:: Reading the active file over a slow line Takes Time.
* Startup Variables:: Other variables you might change.
* Finding the News:: Choosing a method for getting news.
* The Server is Down:: How can I read my mail then?
* Slave Gnusae:: You can have more than one Gnus active at a time.
* New Groups:: What is Gnus supposed to do with new groups?
* Changing Servers:: You may want to move from one server to another.
* Startup Files:: Those pesky startup files---@file{.newsrc}.
* Auto Save:: Recovering from a crash.
* The Active File:: Reading the active file over a slow line Takes Time.
* Startup Variables:: Other variables you might change.
@end menu
@ -13871,6 +13922,7 @@ installed. You then define a server as follows:
(nntp-address "snews.bar.com"))
@end lisp
@c FIXME openssl s_client should be deprecated in favor of gnutls.
@findex nntp-open-ssl-stream
@item nntp-open-ssl-stream
Opens a connection to a server over a @dfn{secure} channel. To use
@ -14190,10 +14242,10 @@ This means that it's a convenient choice when you're reading your mail
from different locations, or with different user agents.
@menu
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
* Customizing the IMAP Connection:: Variables for @acronym{IMAP} connection.
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
* Support for IMAP Extensions:: Getting extensions and labels from servers.
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
* Support for IMAP Extensions:: Getting extensions and labels from servers.
@end menu
@ -18002,10 +18054,10 @@ useful things for you.
@menu
* Diary Summary Line Format:: A nicer summary buffer line format.
* Diary Articles Sorting:: A nicer way to sort messages.
* Diary Headers Generation:: Not doing it manually.
* Diary Group Parameters:: Not handling them manually.
* Diary Summary Line Format:: A nicer summary buffer line format.
* Diary Articles Sorting:: A nicer way to sort messages.
* Diary Headers Generation:: Not doing it manually.
* Diary Group Parameters:: Not handling them manually.
@end menu
@node Diary Summary Line Format
@ -21091,123 +21143,62 @@ four days, Gnus will decay the scores four times, for instance.
@chapter Searching
@cindex searching
FIXME: Add a brief overview of Gnus search capabilities. A brief
comparison of nnir, nnmairix, contrib/gnus-namazu would be nice
as well.
Gnus allows you to search for messages from one or more backends, and
to show the results in group summary buffers. The groups that hold
search results are created on the nnselect backend (@xref{nnselect}),
and can be either ephemeral or persistent (@xref{Creating Search
Groups}).
This chapter describes tools for searching groups and servers for
articles matching a query and then retrieving those articles. Gnus
provides a simpler mechanism for searching through articles in a summary buffer
to find those matching a pattern. @xref{Searching for Articles}.
Each backend has a search engine associated with it. Default
associations between backends and engines can be defined in
@code{gnus-search-default-engines}, and engines can also be defined on
a per-backend basis (@xref{Specifying Search Engines}).
Gnus uses a generalized search query language, which is translated
appropriately across all the backends being searched. For instance,
if you mark one group from an IMAP backend, and another group from an
nnmaildir backend indexed using notmuch, you can enter a single query,
using Gnus' general search syntax, and that query will be translated
appropriately for the IMAP and notmuch engines, returning relevant
results from both backends. For details on Gnus' query language,
@xref{Search Queries}.
If you're already in a summary buffer, Gnus provides a simpler
mechanism for searching through the articles in that buffer.
@xref{Searching for Articles}.
@menu
* nnir:: Searching with various engines.
* nnmairix:: Searching with Mairix.
* Specifying Search Engines:: Which engines for which backends?
* nnmairix:: Searching with Mairix.
@end menu
@node nnir
@section nnir
@cindex nnir
@node Search Engines
@section Search Engines
@cindex search engines
This section describes how to use @code{nnir} to search for articles
within gnus.
Each backend can have a search engine associated with it. Some
backends don't provide much flexibility in this regard: imap servers
generally provide their own search functionality, for instance. Other
backends, like nnml or nnmaildir, don't come with any search
capabilities at all, and it is up to the user to create and maintain
search indexes using some external program. See below for details on
the various search programs Gnus supports.
@menu
* What is nnir?:: What does @code{nnir} do?
* Basic Usage:: How to perform simple searches.
* Setting up nnir:: How to set up @code{nnir}.
@end menu
There are two ways to associate a search engine with a backend: either
by creating default associations using
@code{gnus-search-default-engines}, or on a per-backend basis in the
backend declaration.
@node What is nnir?
@subsection What is nnir?
@table @code
@code{nnir} is a Gnus interface to a number of tools for searching
through mail and news repositories. Different backends (like
@code{nnimap} and @code{nntp}) work with different tools (called
@dfn{engines} in @code{nnir} lingo), but all use the same basic search
interface.
@item @code{gnus-search-default-engines}
@vindex gnus-search-default-engines
An alist of pairs of the form @code{(backend . engine)}.
Backends are a symbol like @code{nnimap} or @code{nnml}.
Engines are the symbol name of a search engine class, for
instance @code{gnus-search-imap} or @code{gnus-search-mairix}.
@end table
The @code{nnimap} and @code{gmane} search engines should work with no
configuration. Other engines require a local index that needs to be
created and maintained outside of Gnus.
@node Basic Usage
@subsection Basic Usage
In the group buffer typing @kbd{G G} will search the group on the
current line by calling @code{gnus-group-make-nnir-group}. This prompts
for a query string, creates an ephemeral @code{nnir} group containing
the articles that match this query, and takes you to a summary buffer
showing these articles. Articles may then be read, moved and deleted
using the usual commands.
The @code{nnir} group made in this way is an @code{ephemeral} group,
and some changes are not permanent: aside from reading, moving, and
deleting, you can't act on the original article. But there is an
alternative: you can @emph{warp} (i.e., jump) to the original group
for the article on the current line with @kbd{A W}, aka
@code{gnus-warp-to-article}. Even better, the function
@code{gnus-summary-refer-thread}, bound by default in summary buffers
to @kbd{A T}, will first warp to the original group before it works
its magic and includes all the articles in the thread. From here you
can read, move and delete articles, but also copy them, alter article
marks, whatever. Go nuts.
You say you want to search more than just the group on the current line?
No problem: just process-mark the groups you want to search. You want
even more? Calling for an nnir search with the cursor on a topic heading
will search all the groups under that heading.
Still not enough? OK, in the server buffer
@code{gnus-group-make-nnir-group} (now bound to @kbd{G}) will search all
groups from the server on the current line. Too much? Want to ignore
certain groups when searching, like spam groups? Just customize
@code{nnir-ignored-newsgroups}.
One more thing: individual search engines may have special search
features. You can access these special features by giving a prefix-arg
to @code{gnus-group-make-nnir-group}. If you are searching multiple
groups with different search engines you will be prompted for the
special search features for each engine separately.
@node Setting up nnir
@subsection Setting up nnir
To set up nnir you may need to do some prep work. Firstly, you may need
to configure the search engines you plan to use. Some of them, like
@code{imap} and @code{gmane}, need no special configuration. Others,
like @code{namazu} and @code{swish}, require configuration as described
below. Secondly, you need to associate a search engine with a server or
a backend.
If you just want to use the @code{imap} engine to search @code{nnimap}
servers, and the @code{gmane} engine to search @code{gmane} then you
don't have to do anything. But you might want to read the details of the
query language anyway.
@menu
* Associating Engines:: How to associate engines.
* The imap Engine:: Imap configuration and usage.
* The gmane Engine:: Gmane configuration and usage.
* The swish++ Engine:: Swish++ configuration and usage.
* The swish-e Engine:: Swish-e configuration and usage.
* The namazu Engine:: Namazu configuration and usage.
* The notmuch Engine:: Notmuch configuration and usage.
* The hyrex Engine:: Hyrex configuration and usage.
* Customizations:: User customizable settings.
@end menu
@node Associating Engines
@subsubsection Associating Engines
When searching a group, @code{nnir} needs to know which search engine to
use. You can configure a given server to use a particular engine by
setting the server variable @code{nnir-search-engine} to the engine
name. For example to use the @code{namazu} engine to search the server
named @code{home} you can use
@lisp
(setq gnus-secondary-select-methods
@ -21216,22 +21207,27 @@ named @code{home} you can use
(nnir-search-engine namazu))))
@end lisp
Alternatively you might want to use a particular engine for all servers
with a given backend. For example, you might want to use the @code{imap}
engine for all servers using the @code{nnimap} backend. In this case you
can customize the variable @code{nnir-method-default-engines}. This is
an alist of pairs of the form @code{(backend . engine)}. By default this
variable is set to use the @code{imap} engine for all servers using the
@code{nnimap} backend, and the @code{gmane} backend for @code{nntp}
servers. (Don't worry, the @code{gmane} search engine won't actually try
to search non-gmane @code{nntp} servers.) But if you wanted to use
@code{namazu} for all your servers with an @code{nnimap} backend you
could change this to
Search engines are implemented as classes in Gnus, an implementation
detail that users can usually ignore. The class names all begin with
@samp{gnus-search-*}, see below for the full list. Many of the
classes accept options changing their behavior: for instance,
command-line search programs mostly accept a @samp{switches} option
specifying extra switches to be passed on the command line.
@lisp
'((nnimap . namazu)
(nntp . gmane))
@end lisp
These options can be set either generally, for a whole class of search
engine, or specifically for a single engine instance.
@node Supported Engines
@subsection Supported Engines
@menu
* The imap Engine:: Imap configuration and usage.
* The gmane Engine:: Gmane configuration and usage.
* The swish++ Engine:: Swish++ configuration and usage.
* The swish-e Engine:: Swish-e configuration and usage.
* The namazu Engine:: Namazu configuration and usage.
* The notmuch Engine:: Notmuch configuration and usage.
@end menu
@node The imap Engine
@subsubsection The imap Engine
@ -21445,54 +21441,93 @@ is a regular expression.
@end table
@node Creating Search Groups
@section Creating Search Groups
@cindex search groups
@node The hyrex Engine
@subsubsection The hyrex Engine
This engine is obsolete.
In the group buffer typing @kbd{G G} will search the group on the
current line by calling @code{gnus-group-make-search-group}. This
prompts for a query string, creates an ephemeral @code{nnselect} group
containing the articles that match this query, and takes you to a
summary buffer showing these articles. Articles may then be read,
moved and deleted using the usual commands.
The @code{nnir} group made in this way is an @code{ephemeral} group,
and some changes are not permanent: aside from reading, moving, and
deleting, you can't act on the original article. But there is an
alternative: you can @emph{warp} (i.e., jump) to the original group
for the article on the current line with @kbd{A W}, aka
@code{gnus-warp-to-article}. Even better, the function
@code{gnus-summary-refer-thread}, bound by default in summary buffers
to @kbd{A T}, will first warp to the original group before it works
its magic and includes all the articles in the thread. From here you
can read, move and delete articles, but also copy them, alter article
marks, whatever. Go nuts.
You say you want to search more than just the group on the current line?
No problem: just process-mark the groups you want to search. You want
even more? Calling for an nnir search with the cursor on a topic heading
will search all the groups under that heading.
Still not enough? OK, in the server buffer
@code{gnus-group-make-search-group} (now bound to @kbd{G}) will search all
groups from the server on the current line. Too much? Want to ignore
certain groups when searching, like spam groups? Just customize
@code{gnus-search-ignored-newsgroups}.
@node Search Queries
@section Search Queries
@cindex search queries
Gnus provides a generalized search query language that can be used to
search many engines at once. The language is meant to be as flexible
as possible, with the expectation that the search engines will
interpret the queries as best they can, and ignore any terms or
expressions that cannot be interpreted.
The language is built on a simple @samp{key:value} pattern. The keys
are defined below; many engines can also accept arbitrary keys,
typically interpreting them as mail header names. Values are words,
occasionally numbers, or quote-delimited phrases.
Keys can be arbitrarily abbreviated, for convenience in typing. For
instance, @samp{subject} could also be written as @samp{subj}, or even
@samp{su}. Abbreviated keywords will be expanded at parse time,
though if a keyword is so abbreviated as to become ambiguous (@samp{s}
could expand to either @samp{subject} or @samp{since}, for instance),
an error will be raised.
Multiple terms are implicitly ANDed. The infixed @samp{or} keyword
performs the OR function. The @samp{near} keyword is understood by
some engines; by others it is treated as an AND. Parentheses can be
used to group and/or nest sub-expressions.
@table @samp
@end table
@node Customizations
@subsubsection Customizations
@section Customizations
@table @code
@item nnir-method-default-engines
@item gnus-search-use-parsed-queries
When non-nil, the default, Gnus will parse string queries into sexp
form, and allow search engines to transform those sexps into
understandable formats. If you want to always send raw, unparsed queries to the engines,
@item gnus-search-default-engines
Alist of pairs of server backends and search engines. The default
associations are
@example
(nnimap . imap)
(nntp . gmane)
(nnimap . gnus-search-imap)
(nntp . gnus-search-gmane)
@end example
@item nnir-ignored-newsgroups
@item gnus-search-ignored-newsgroups
A regexp to match newsgroups in the active file that should be skipped
when searching all groups on a server.
@item nnir-summary-line-format
The format specification to be used for lines in an nnir summary buffer.
All the items from @code{gnus-summary-line-format} are available, along with
three items unique to nnir summary buffers:
@example
%Z Search retrieval score value (integer)
%G Article original full group name (string)
%g Article original short group name (string)
@end example
If @code{nil} (the default) this will use @code{gnus-summary-line-format}.
@item nnir-retrieve-headers-override-function
If non-@code{nil}, a function that retrieves article headers rather than using
the gnus built-in function. This function takes an article list and
group as arguments and populates the @code{nntp-server-buffer} with the
retrieved headers. It should then return either 'nov or 'headers
indicating the retrieved header format. Failure to retrieve headers
should return @code{nil}.
If this variable is @code{nil}, or if the provided function returns
@code{nil} for a search result, @code{gnus-retrieve-headers} will be
called instead."
@end table
@ -21512,7 +21547,7 @@ bound to mairix searches and are automatically updated.
* What nnmairix does:: What does nnmairix actually do?
* Setting up mairix:: Set up your mairix installation
* Configuring nnmairix:: Set up the nnmairix back end
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
* Propagating marks:: How to propagate marks from nnmairix groups
* nnmairix tips and tricks:: Some tips, tricks and examples
* nnmairix caveats:: Some more stuff you might want to know
@ -26465,13 +26500,13 @@ but at the common table.@*
@menu
* XEmacs:: Requirements for installing under XEmacs.
* History:: How Gnus got where it is today.
* The Manual::
* On Writing Manuals:: Why this is not a beginner's guide.
* Terminology:: We use really difficult, like, words here.
* Customization:: Tailoring Gnus to your needs.
* Troubleshooting:: What you might try if things do not work.
* Gnus Reference Guide:: Rilly, rilly technical stuff.
* Emacs for Heathens:: A short introduction to Emacsian terms.
* Frequently Asked Questions:: The Gnus FAQ
@end menu

View file

@ -110,12 +110,14 @@ buffer, or a filename. If SOMETHING is nil return nil."
(semantic-file-tag-table something))
;; A Semanticdb table
((and (featurep 'semantic/db)
(require 'semantic/db-mode)
(semanticdb-minor-mode-p)
(semanticdb-abstract-table-child-p something))
(semanticdb-refresh-table something)
(semanticdb-get-tags something))
;; Semanticdb find-results
((and (featurep 'semantic/db)
(require 'semantic/db-mode)
(semanticdb-minor-mode-p)
(require 'semantic/db-find)
(semanticdb-find-results-p something))

View file

@ -53,6 +53,7 @@
;; CONTENTS --- `erc-response.contents'
;; SENDER --- `erc-response.sender'
;; LINE --- `erc-response.unparsed'
;; TAGS --- `erc-response.tags'
;;
;; WARNING, WARNING!!
;; It's probably not a good idea to destructively modify the list
@ -115,7 +116,8 @@
(sender "" :type string)
(command "" :type string)
(command-args '() :type list)
(contents "" :type string))
(contents "" :type string)
(tags '() :type list))
;;; User data
@ -955,16 +957,34 @@ See also `erc-server-send'."
;;;; Handling responses
(defun erc-parse-tags (string)
"Parse IRCv3 tags list in STRING to a (tag . value) alist."
(let ((tags)
(tag-strings (split-string string ";")))
(dolist (tag-string tag-strings tags)
(let ((pair (split-string tag-string "=")))
(push (if (consp pair)
pair
`(,pair))
tags)))))
(defun erc-parse-server-response (proc string)
"Parse and act upon a complete line from an IRC server.
PROC is the process (connection) from which STRING was received.
PROCs `process-buffer' is `current-buffer' when this function is called."
(unless (string= string "") ;; Ignore empty strings
(save-match-data
(let ((posn (if (eq (aref string 0) ?:)
(string-match " " string)
0))
(msg (make-erc-response :unparsed string)))
(let* ((tag-list (when (eq (aref string 0) ?@)
(substring string 1 (string-match " " string))))
(msg (make-erc-response :unparsed string :tags (when tag-list
(erc-parse-tags
tag-list))))
(string (if tag-list
(substring string (+ 1 (string-match " " string)))
string))
(posn (if (eq (aref string 0) ?:)
(string-match " " string)
0)))
(setf (erc-response.sender msg)
(if (eq posn 0)

View file

@ -2700,7 +2700,10 @@ See also `erc-format-message' and `erc-display-line'."
(unless (erc-hide-current-message-p parsed)
(erc-put-text-property 0 (length string) 'erc-parsed parsed string)
(erc-put-text-property 0 (length string) 'rear-sticky t string)
(erc-display-line string buffer)))))
(when (erc-response.tags parsed)
(erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed)
string))
(erc-display-line string buffer)))))
(defun erc-message-type-member (position list)
"Return non-nil if the erc-parsed text-property at POSITION is in LIST.

View file

@ -6993,10 +6993,10 @@ If given a prefix, show the hidden text instead."
((memq article gnus-newsgroup-sparse)
;; This is a sparse gap article.
(setq do-update-line article)
(setq article (mail-header-id header))
(setq sparse-header (gnus-read-header article))
(setq gnus-newsgroup-sparse
(delq article gnus-newsgroup-sparse)))
(delq article gnus-newsgroup-sparse))
(setq article (mail-header-id header))
(setq sparse-header (gnus-read-header article)))
((vectorp header)
;; It's a real article.
(setq article (mail-header-id header)))

View file

@ -49,10 +49,11 @@
(autoload 'gnus-agent-total-fetched-for "gnus-agent")
(autoload 'gnus-cache-total-fetched-for "gnus-cache")
(autoload 'gnus-group-make-nnir-group "nnir")
(autoload 'gnus-cloud-upload-all-data "gnus-cloud")
(autoload 'gnus-cloud-download-all-data "gnus-cloud")
(autoload 'gnus-registry-get-id-key "gnus-registry")
(declare-function 'gnus-group-topic-name "gnus-topic")
(defcustom gnus-no-groups-message "No news is good news"
"Message displayed by Gnus when no groups are available."
@ -671,7 +672,8 @@ simple manner."
"D" gnus-group-enter-directory
"f" gnus-group-make-doc-group
"w" gnus-group-make-web-group
"G" gnus-group-make-nnir-group
"G" gnus-group-read-ephemeral-search-group
"g" gnus-group-make-search-group
"M" gnus-group-read-ephemeral-group
"r" gnus-group-rename-group
"R" gnus-group-make-rss-group
@ -917,7 +919,8 @@ simple manner."
["Add the help group" gnus-group-make-help-group t]
["Make a doc group..." gnus-group-make-doc-group t]
["Make a web group..." gnus-group-make-web-group t]
["Make a search group..." gnus-group-make-nnir-group t]
["Read a search group..." gnus-group-read-ephemeral-search-group t]
["Make a search group..." gnus-group-make-search-group t]
["Make a virtual group..." gnus-group-make-empty-virtual t]
["Add a group to a virtual..." gnus-group-add-to-virtual t]
["Make an ephemeral group..." gnus-group-read-ephemeral-group t]
@ -3193,6 +3196,51 @@ mail messages or news articles in files that have numeric names."
(gnus-group-real-name group)
(list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir)))))
(autoload 'gnus-search-make-specs "gnus-search")
(autoload 'gnus-group-topic-name "gnus-topic")
;; Temporary to make group creation easier
(defun gnus-group-make-search-group (arg &optional specs)
(interactive "P")
(let ((name (read-string "Group name: " nil)))
(with-current-buffer gnus-group-buffer
(gnus-group-make-group
name
(list 'nnselect "nnselect")
nil
(list
(cons 'nnselect-specs
(list
(cons 'nnselect-function 'gnus-search-run-query)
(cons 'nnselect-args
(gnus-search-make-specs arg specs)))))))))
(defun gnus-group-read-ephemeral-search-group (arg &optional specs)
"Create an nnselect group based on a search. Prompt for a
search query and determine the groups to search as follows: if
called from the *Server* buffer search all groups belonging to
the server on the current line; if called from the *Group* buffer
search any marked groups, or the group on the current line, or
all the groups under the current topic. Calling with a prefix-arg
prevents parsing of the query. A non-nil `specs' arg must be an
alist with `search-query-spec' and `search-group-spec' keys, and
skips all prompting."
(interactive "P")
(gnus-group-read-ephemeral-group
(concat "nnselect-" (message-unique-id))
(list 'nnselect "nnselect")
nil
(cons (current-buffer) gnus-current-window-configuration)
; nil
nil nil
(list
(cons 'nnselect-specs
(list
(cons 'nnselect-function 'gnus-search-run-query)
(cons 'nnselect-args
(gnus-search-make-specs arg specs))))
(cons 'nnselect-artlist nil))))
(defun gnus-group-add-to-virtual (n vgroup)
"Add the current group to a virtual group."
(interactive
@ -4728,6 +4776,7 @@ you the groups that have both dormant articles and cached articles."
group 'expire (list article))))))
;;;
;;; Group compaction. -- dvl
;;;

View file

@ -414,10 +414,9 @@ Thank you for your help in stamping out bugs.
(gnus-inews-make-draft-meta-information
,(gnus-group-decoded-name gnus-newsgroup-name) ',articles)))
(autoload 'nnir-article-number "nnir" nil nil 'macro)
(autoload 'nnir-article-group "nnir" nil nil 'macro)
(autoload 'gnus-nnir-group-p "nnir")
(autoload 'nnselect-article-number "nnselect" nil nil 'macro)
(autoload 'nnselect-article-group "nnselect" nil nil 'macro)
(autoload 'gnus-nnselect-group-p "nnselect")
(defvar gnus-article-reply nil)
(defmacro gnus-setup-message (config &rest forms)
@ -425,22 +424,24 @@ Thank you for your help in stamping out bugs.
(winconf-name (make-symbol "gnus-setup-message-winconf-name"))
(buffer (make-symbol "gnus-setup-message-buffer"))
(article (make-symbol "gnus-setup-message-article"))
(oarticle (make-symbol "gnus-setup-message-oarticle"))
(yanked (make-symbol "gnus-setup-yanked-articles"))
(group (make-symbol "gnus-setup-message-group")))
`(let ((,winconf (current-window-configuration))
(,winconf-name gnus-current-window-configuration)
(,buffer (buffer-name (current-buffer)))
(,article (if (and (gnus-nnir-group-p gnus-newsgroup-name)
gnus-article-reply)
(nnir-article-number (or (car-safe gnus-article-reply)
gnus-article-reply))
gnus-article-reply))
(,article (when gnus-article-reply
(or (nnselect-article-number
(or (car-safe gnus-article-reply)
gnus-article-reply))
gnus-article-reply)))
(,oarticle gnus-article-reply)
(,yanked gnus-article-yanked-articles)
(,group (if (and (gnus-nnir-group-p gnus-newsgroup-name)
gnus-article-reply)
(nnir-article-group (or (car-safe gnus-article-reply)
gnus-article-reply))
gnus-newsgroup-name))
(,group (when gnus-article-reply
(or (nnselect-article-group
(or (car-safe gnus-article-reply)
gnus-article-reply))
gnus-newsgroup-name)))
(message-header-setup-hook
(copy-sequence message-header-setup-hook))
(mbl mml-buffer-list)
@ -481,24 +482,23 @@ Thank you for your help in stamping out bugs.
(unwind-protect
(progn
,@forms)
(gnus-inews-add-send-actions ,winconf ,buffer ,article ,config
(gnus-inews-add-send-actions ,winconf ,buffer ,oarticle ,config
,yanked ,winconf-name)
(setq gnus-message-buffer (current-buffer))
(set (make-local-variable 'gnus-message-group-art)
(cons ,group ,article))
(set (make-local-variable 'gnus-newsgroup-name) ,group)
;; Enable highlighting of different citation levels
(when gnus-message-highlight-citation
(gnus-message-citation-mode 1))
(gnus-run-hooks 'gnus-message-setup-hook)
(if (eq major-mode 'message-mode)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl) ;; Global value
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
(add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
(mml-destroy-buffers)
(setq mml-buffer-list mbl)))
;; Enable highlighting of different citation levels
(when gnus-message-highlight-citation
(gnus-message-citation-mode 1))
(gnus-run-hooks 'gnus-message-setup-hook)
(if (eq major-mode 'message-mode)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl) ;; Global value
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
(add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
(mml-destroy-buffers)
(setq mml-buffer-list mbl)))
(message-hide-headers)
(gnus-add-buffer)
(gnus-configure-windows ,config t)
@ -542,12 +542,10 @@ instead."
mail-buf)
(unwind-protect
(progn
(setq gnus-newsgroup-name "")
(let ((gnus-newsgroup-name ""))
(gnus-setup-message 'message
(message-mail to subject other-headers continue
nil yank-action send-actions return-action)))
(with-current-buffer buf
(setq gnus-newsgroup-name group-name)))
nil yank-action send-actions return-action)))))
(when switch-action
(setq mail-buf (current-buffer))
(switch-to-buffer buf)
@ -638,18 +636,15 @@ If ARG is 1, prompt for a group name to find the posting style."
(buffer (current-buffer)))
(unwind-protect
(progn
(setq gnus-newsgroup-name
(if arg
(if (= 1 (prefix-numeric-value arg))
(gnus-group-completing-read
"Use posting style of group"
nil (gnus-read-active-file-p))
(gnus-group-group-name))
""))
;; #### see comment in gnus-setup-message -- drv
(gnus-setup-message 'message (message-mail)))
(with-current-buffer buffer
(setq gnus-newsgroup-name group)))))
(let ((gnus-newsgroup-name
(if arg
(if (= 1 (prefix-numeric-value arg))
(gnus-group-completing-read
"Use posting style of group"
nil (gnus-read-active-file-p))
(gnus-group-group-name))
"")))
(gnus-setup-message 'message (message-mail)))))))
(defun gnus-group-news (&optional arg)
"Start composing a news.
@ -668,19 +663,16 @@ network. The corresponding back end must have a 'request-post method."
(buffer (current-buffer)))
(unwind-protect
(progn
(setq gnus-newsgroup-name
(let ((gnus-newsgroup-name
(if arg
(if (= 1 (prefix-numeric-value arg))
(gnus-group-completing-read "Use group"
nil
(gnus-read-active-file-p))
(gnus-group-group-name))
""))
;; #### see comment in gnus-setup-message -- drv
"")))
(gnus-setup-message 'message
(message-news (gnus-group-real-name gnus-newsgroup-name))))
(with-current-buffer buffer
(setq gnus-newsgroup-name group)))))
(message-news (gnus-group-real-name gnus-newsgroup-name))))))))
(defun gnus-group-post-news (&optional arg)
"Start composing a message (a news by default).
@ -715,18 +707,15 @@ posting style."
(buffer (current-buffer)))
(unwind-protect
(progn
(setq gnus-newsgroup-name
(let ((gnus-newsgroup-name
(if arg
(if (= 1 (prefix-numeric-value arg))
(gnus-group-completing-read "Use group"
nil
(gnus-read-active-file-p))
"")
gnus-newsgroup-name))
;; #### see comment in gnus-setup-message -- drv
(gnus-setup-message 'message (message-mail)))
(with-current-buffer buffer
(setq gnus-newsgroup-name group)))))
gnus-newsgroup-name)))
(gnus-setup-message 'message (message-mail)))))))
(defun gnus-summary-news-other-window (&optional arg)
"Start composing a news in another window.
@ -745,24 +734,21 @@ network. The corresponding back end must have a 'request-post method."
(buffer (current-buffer)))
(unwind-protect
(progn
(setq gnus-newsgroup-name
(let ((gnus-newsgroup-name
(if arg
(if (= 1 (prefix-numeric-value arg))
(gnus-group-completing-read "Use group"
nil
(gnus-read-active-file-p))
"")
gnus-newsgroup-name))
;; #### see comment in gnus-setup-message -- drv
gnus-newsgroup-name)))
(gnus-setup-message 'message
(progn
(message-news (gnus-group-real-name gnus-newsgroup-name))
(set (make-local-variable 'gnus-discouraged-post-methods)
(remove
(car (gnus-find-method-for-group gnus-newsgroup-name))
gnus-discouraged-post-methods)))))
(with-current-buffer buffer
(setq gnus-newsgroup-name group)))))
gnus-discouraged-post-methods)))))))))
(defun gnus-summary-post-news (&optional arg)
"Start composing a message. Post to the current group by default.

View file

@ -380,6 +380,8 @@ This is not required after changing `gnus-registry-cache-file'."
(gnus-message 4 "Removed %d ignored entries from the Gnus registry"
(- old-size (registry-size db)))))
(declare-function gnus-nnselect-group-p "nnselect" (group))
(declare-function nnselect-article-group "nnselect" (article))
;; article move/copy/spool/delete actions
(defun gnus-registry-action (action data-header from &optional to method)
(let* ((id (mail-header-id data-header))
@ -390,7 +392,10 @@ This is not required after changing `gnus-registry-cache-file'."
(or (cdr-safe (assq 'To extra)) "")))
(sender (nth 0 (gnus-registry-extract-addresses
(mail-header-from data-header))))
(from (gnus-group-guess-full-name-from-command-method from))
(from (gnus-group-guess-full-name-from-command-method
(if (gnus-nnselect-group-p from)
(nnselect-article-group (mail-header-number data-header))
from)))
(to (if to (gnus-group-guess-full-name-from-command-method to) nil)))
(gnus-message 7 "Gnus registry: article %s %s from %s to %s"
id (if method "respooling" "going") from to)
@ -737,7 +742,7 @@ Consults `gnus-registry-unfollowed-groups' and
Consults `gnus-registry-ignored-groups' and
`nnmail-split-fancy-with-parent-ignore-groups'."
(and group
(or (gnus-grep-in-list
(or (gnus-virtual-group-p group) (gnus-grep-in-list
group
(delq nil (mapcar (lambda (g)
(cond
@ -1175,7 +1180,7 @@ is `ask', ask the user; or if `gnus-registry-install' is non-nil, enable it."
(gnus-registry-initialize)))
gnus-registry-enabled)
;; largely based on nnir-warp-to-article
;; largely based on nnselect-warp-to-article
(defun gnus-try-warping-via-registry ()
"Try to warp via the registry.
This will be done via the current article's source group based on
@ -1199,7 +1204,7 @@ data stored in the registry."
(gnus-ephemeral-group-p group) ;; any ephemeral group
(memq (car (gnus-find-method-for-group group))
;; Specific methods; this list may need to expand.
'(nnir)))
'(nnselect)))
;; remember that we've seen this group already
(push group seen-groups)

2254
lisp/gnus/gnus-search.el Normal file

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,8 @@
(require 'gnus-range)
(require 'gnus-cloud)
(autoload 'gnus-group-make-nnir-group "nnir")
(autoload 'gnus-group-make-search-group "nnselect")
(autoload 'gnus-group-make-permanent-search-group "nnselect")
(defcustom gnus-server-mode-hook nil
"Hook run in `gnus-server-mode' buffers."
@ -184,7 +185,7 @@ If nil, a faster, but more primitive, buffer is used instead."
"g" gnus-server-regenerate-server
"G" gnus-group-make-nnir-group
"G" gnus-group-read-ephemeral-search-group
"z" gnus-server-compact-server

View file

@ -52,8 +52,8 @@
(autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
(autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
(autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
(autoload 'nnir-article-rsv "nnir" nil nil 'macro)
(autoload 'nnir-article-group "nnir" nil nil 'macro)
(autoload 'nnselect-article-rsv "nnselect" nil nil)
(autoload 'nnselect-article-group "nnselect" nil nil)
(defcustom gnus-kill-summary-on-exit t
"If non-nil, kill the summary buffer when you exit from it.
@ -111,8 +111,8 @@ If t, fetch all the available old headers."
:type '(choice number
(sexp :menu-tag "other" t)))
(defcustom gnus-refer-thread-use-nnir nil
"Use nnir to search an entire server when referring threads. A
(defcustom gnus-refer-thread-use-search nil
"Search an entire server when referring threads. A
nil value will only search for thread-related articles in the
current group."
:version "24.1"
@ -844,6 +844,7 @@ controls how articles are sorted."
(function-item gnus-article-sort-by-subject)
(function-item gnus-article-sort-by-date)
(function-item gnus-article-sort-by-score)
(function-item gnus-article-sort-by-rsv)
(function-item gnus-article-sort-by-random)
(function :tag "other"))
(boolean :tag "Reverse order"))))
@ -887,6 +888,7 @@ subthreads, customize `gnus-subthread-sort-functions'."
(function-item gnus-thread-sort-by-subject)
(function-item gnus-thread-sort-by-date)
(function-item gnus-thread-sort-by-score)
(function-item gnus-thread-sort-by-rsv)
(function-item gnus-thread-sort-by-most-recent-number)
(function-item gnus-thread-sort-by-most-recent-date)
(function-item gnus-thread-sort-by-random)
@ -1388,12 +1390,12 @@ the normal Gnus MIME machinery."
(?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
(?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
(?L gnus-tmp-lines ?s)
(?Z (or (nnir-article-rsv (mail-header-number gnus-tmp-header))
(?Z (or (nnselect-article-rsv (mail-header-number gnus-tmp-header))
0) ?d)
(?G (or (nnir-article-group (mail-header-number gnus-tmp-header))
(?G (or (nnselect-article-group (mail-header-number gnus-tmp-header))
"") ?s)
(?g (or (gnus-group-short-name
(nnir-article-group (mail-header-number gnus-tmp-header)))
(nnselect-article-group (mail-header-number gnus-tmp-header)))
"") ?s)
(?O gnus-tmp-downloaded ?c)
(?I gnus-tmp-indentation ?s)
@ -1568,6 +1570,8 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
(defvar gnus-newsgroup-sparse nil)
(defvar gnus-newsgroup-selection nil)
(defvar gnus-current-article nil)
(defvar gnus-article-current nil)
(defvar gnus-current-headers nil)
@ -1602,6 +1606,8 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
gnus-newsgroup-undownloaded
gnus-newsgroup-unsendable
gnus-newsgroup-selection
gnus-newsgroup-begin gnus-newsgroup-end
gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
gnus-newsgroup-last-folder gnus-newsgroup-last-file
@ -5022,6 +5028,17 @@ using some other form will lead to serious barfage."
(gnus-article-sort-by-date
(gnus-thread-header h1) (gnus-thread-header h2)))
(defsubst gnus-article-sort-by-rsv (h1 h2)
"Sort articles by rsv."
(when gnus-newsgroup-selection
(< (nnselect-article-rsv (mail-header-number h1))
(nnselect-article-rsv (mail-header-number h2)))))
(defun gnus-thread-sort-by-rsv (h1 h2)
"Sort threads by root article rsv."
(gnus-article-sort-by-rsv
(gnus-thread-header h1) (gnus-thread-header h2)))
(defsubst gnus-article-sort-by-score (h1 h2)
"Sort articles by root article score.
Unscored articles will be counted as having a score of zero."
@ -9007,9 +9024,9 @@ Return the number of articles fetched."
(defun gnus-summary-refer-thread (&optional limit)
"Fetch all articles in the current thread. For backends that
know how to search for threads (currently only 'nnimap) a
non-numeric prefix arg will use nnir to search the entire
non-numeric prefix arg will search the entire
server; without a prefix arg only the current group is
searched. If the variable `gnus-refer-thread-use-nnir' is
searched. If the variable `gnus-refer-thread-use-search' is
non-nil the prefix arg has the reverse meaning. If no
backend-specific 'request-thread function is available fetch
LIMIT (the numerical prefix) old headers. If LIMIT is
@ -9021,9 +9038,9 @@ non-numeric or nil fetch the number specified by the
(gnus-inhibit-demon t)
(gnus-summary-ignore-duplicates t)
(gnus-read-all-available-headers t)
(gnus-refer-thread-use-nnir
(gnus-refer-thread-use-search
(if (and (not (null limit)) (listp limit))
(not gnus-refer-thread-use-nnir) gnus-refer-thread-use-nnir))
(not gnus-refer-thread-use-search) gnus-refer-thread-use-search))
(new-headers
(if (gnus-check-backend-function
'request-thread gnus-newsgroup-name)
@ -9162,9 +9179,9 @@ non-numeric or nil fetch the number specified by the
(dolist (method gnus-refer-article-method)
(push (if (eq 'current method)
gnus-current-select-method
(if (eq 'nnir (car method))
(if (eq 'nnselect (car method))
(list
'nnir
'nnselect
(or (cadr method)
(gnus-method-to-server gnus-current-select-method)))
method))

View file

@ -1868,7 +1868,7 @@ total number of articles in the group.")
:variable-default (mapcar
(lambda (g) (list g t))
'("delayed$" "drafts$" "queue$" "INBOX$"
"^nnmairix:" "^nnir:" "archive"))
"^nnmairix:" "^nnselect:" "archive"))
:variable-document
"Groups in which the registry should be turned off."
:variable-group gnus-registry

View file

@ -1797,17 +1797,17 @@ If LIMIT, first try to limit the search to the N last articles."
(setq nnimap-status-string "Read-only server")
nil)
(defvar gnus-refer-thread-use-nnir) ;; gnus-sum.el
(defvar gnus-refer-thread-use-search) ;; gnus-sum.el
(declare-function gnus-fetch-headers "gnus-sum"
(articles &optional limit force-new dependencies))
(autoload 'nnir-search-thread "nnir")
(autoload 'nnselect-search-thread "nnselect")
(deffoo nnimap-request-thread (header &optional group server)
(when group
(setq group (nnimap-decode-gnus-group group)))
(if gnus-refer-thread-use-nnir
(nnir-search-thread header)
(if gnus-refer-thread-use-search
(nnselect-search-thread header)
(when (nnimap-change-group group server)
(let* ((cmd (nnimap-make-thread-query header))
(result (with-current-buffer (nnimap-buffer)
@ -1819,6 +1819,20 @@ If LIMIT, first try to limit the search to the N last articles."
(cdr (assoc "SEARCH" (cdr result))))))
nil t))))))
(defun nnimap-make-thread-query (header)
(let* ((id (mail-header-id header))
(refs (split-string
(or (mail-header-references header)
"")))
(value
(format
"(OR HEADER REFERENCES %S HEADER Message-Id %S)"
id id)))
(dolist (refid refs value)
(setq value (format
"(OR (OR HEADER Message-Id %S HEADER REFERENCES %S) %s)"
refid refid value)))))
(defun nnimap-change-group (group &optional server no-reconnect read-only)
"Change group to GROUP if non-nil.
If SERVER is set, check that server is connected, otherwise retry
@ -2212,21 +2226,6 @@ Return the server's response to the SELECT or EXAMINE command."
group-art))
nnimap-incoming-split-list)))
(defun nnimap-make-thread-query (header)
(let* ((id (mail-header-id header))
(refs (split-string
(or (mail-header-references header)
"")))
(value
(format
"(OR HEADER REFERENCES %S HEADER Message-Id %S)"
id id)))
(dolist (refid refs value)
(setq value (format
"(OR (OR HEADER Message-Id %S HEADER REFERENCES %S) %s)"
refid refid value)))))
(provide 'nnimap)
;;; nnimap.el ends here

File diff suppressed because it is too large Load diff

826
lisp/gnus/nnselect.el Normal file
View file

@ -0,0 +1,826 @@
;;; nnselect.el --- a virtual group backend -*- lexical-binding:t -*-
;; Copyright (C) 2017 Free Software Foundation, Inc.
;; Author: Andrew Cohen <cohen@andy.bu.edu>
;; Keywords: news mail
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This is a "virtual" backend that allows an aribtrary list of
;; articles to be treated as a gnus group. An nnselect group uses an
;; nnselect-spec group parameter to specify this list of
;; articles. nnselect-spec is an alist with two keys:
;; nnselect-function, whose value should be a function that returns
;; the list of articles, and nnselect-args. The function will be
;; applied to the arguments to generate the list of articles. The
;; return value should be a vector, each element of which should in
;; turn be a vector of three elements: a real prefixed group name, an
;; article number in that group, and an integer score. The score is
;; not used by nnselect but may be used by other code to help in
;; sorting. Most functions will just chose a fixed number, such as
;; 100, for this score.
;; For example the search function `gnus-search-run-query' applied to
;; arguments specifying a search query (see "gnus-search.el") can be
;; used to return a list of articles from a search. Or the function
;; can be the identity and the args a vector of articles.
;;; Code:
;;; Setup:
(require 'gnus-art)
(require 'gnus-search)
(eval-when-compile (require 'cl-lib))
;; Set up the backend
(nnoo-declare nnselect)
(nnoo-define-basics nnselect)
(gnus-declare-backend "nnselect" 'post-mail 'virtual)
;;; Internal Variables:
(defvar gnus-inhibit-demon)
(defvar gnus-message-group-art)
(defvar nnselect-artlist nil
"Internal: stores the list of articles.")
;; For future use
(defvoo nnselect-directory gnus-directory
"Directory for the nnselect backend.")
(defvoo nnselect-active-file
(expand-file-name "nnselect-active" nnselect-directory)
"nnselect active file.")
(defvoo nnselect-groups-file
(expand-file-name "nnselect-newsgroups" nnselect-directory)
"nnselect groups description file.")
;;; Helper routines.
(defun nnselect-group-server (group)
(gnus-group-server group))
;; Data type article list.
(define-inline nnselect-artlist-length (artlist)
(inline-quote (length ,artlist)))
(define-inline nnselect-artlist-article (artlist n)
"Return from ARTLIST the Nth artitem (counting starting at 1)."
(inline-quote (when (> ,n 0)
(elt ,artlist (1- ,n)))))
(define-inline nnselect-artitem-group (artitem)
"Return the group from the ARTITEM."
(inline-quote (elt ,artitem 0)))
(define-inline nnselect-artitem-number (artitem)
"Return the number from the ARTITEM."
(inline-quote (elt ,artitem 1)))
(define-inline nnselect-artitem-rsv (artitem)
"Return the Retrieval Status Value (RSV, score) from the ARTITEM."
(inline-quote (elt ,artitem 2)))
(define-inline nnselect-article-group (article)
"Return the group for ARTICLE."
(inline-quote
(nnselect-artitem-group (nnselect-artlist-article
gnus-newsgroup-selection ,article))))
(define-inline nnselect-article-number (article)
"Return the number for ARTICLE."
(inline-quote (nnselect-artitem-number
(nnselect-artlist-article
gnus-newsgroup-selection ,article))))
(define-inline nnselect-article-rsv (article)
"Return the rsv for ARTICLE."
(inline-quote (nnselect-artitem-rsv
(nnselect-artlist-article
gnus-newsgroup-selection ,article))))
(define-inline nnselect-article-id (article)
"Return the pair `(nnselect id . real id)' of ARTICLE."
(inline-quote (cons ,article (nnselect-article-number ,article))))
(define-inline nnselect-categorize (sequence keyfunc &optional valuefunc)
"Sorts a sequence into categories and returns a list of the form
`((key1 (element11 element12)) (key2 (element21 element22))'.
The category key for a member of the sequence is obtained
as `(keyfunc member)' and the corresponding element is just
`member' (or `(valuefunc member)' if `valuefunc' is non-nil)."
(inline-letevals (sequence keyfunc valuefunc)
(inline-quote (let ((valuefunc (or ,valuefunc 'identity))
result)
(unless (null ,sequence)
(mapc
(lambda (member)
(let* ((key (funcall ,keyfunc member))
(value (funcall valuefunc member))
(kr (assoc key result)))
(if kr
(push value (cdr kr))
(push (list key value) result))))
(reverse ,sequence))
result)))))
;; (defmacro nnselect-categorize (sequence keyfunc &optional valuefunc)
;; "Sorts a sequence into categories and returns a list of the form
;; `((key1 (element11 element12)) (key2 (element21 element22))'.
;; The category key for a member of the sequence is obtained
;; as `(keyfunc member)' and the corresponding element is just
;; `member' (or `(valuefunc member)' if `valuefunc' is non-nil)."
;; (let ((key (make-symbol "key"))
;; (value (make-symbol "value"))
;; (result (make-symbol "result"))
;; (valuefunc (or valuefunc 'identity)))
;; `(unless (null ,sequence)
;; (let (,result)
;; (mapc
;; (lambda (member)
;; (let* ((,key (,keyfunc member))
;; (,value (,valuefunc member))
;; (kr (assoc ,key ,result)))
;; (if kr
;; (push ,value (cdr kr))
;; (push (list ,key ,value) ,result))))
;; (reverse ,sequence))
;; ,result))))
(define-inline ids-by-group (articles)
(inline-quote
(nnselect-categorize ,articles 'nnselect-article-group
'nnselect-article-id)))
(define-inline numbers-by-group (articles)
(inline-quote
(nnselect-categorize
,articles 'nnselect-article-group 'nnselect-article-number)))
;;; User Customizable Variables:
(defgroup nnselect nil
"Virtual groups in Gnus with arbitrary selection methods."
:group 'gnus)
(defcustom nnselect-retrieve-headers-override-function nil
"A function that retrieves article headers for ARTICLES from GROUP.
The retrieved headers should populate the `nntp-server-buffer'.
Returns either the retrieved header format 'nov or 'headers.
If this variable is nil, or if the provided function returns nil,
`gnus-retrieve-headers' will be called instead."
:version "24.1" :type '(function) :group 'nnselect)
;; Gnus backend interface functions.
(deffoo nnselect-open-server (server &optional definitions)
;; Just set the server variables appropriately.
(let ((backend (or (car (gnus-server-to-method server)) 'nnselect)))
(nnoo-change-server backend server definitions)))
;; (deffoo nnselect-server-opened (&optional server)
;; "Is SERVER the current virtual server?"
;; (if (string-empty-p server)
;; t
;; (let ((backend (car (gnus-server-to-method server))))
;; (nnoo-current-server-p (or backend 'nnselect) server))))
(deffoo nnselect-server-opened (&optional _server)
t)
(deffoo nnselect-request-group (group &optional server dont-check info)
(let ((group (nnselect-possibly-change-group group server))
length)
;; Check for cached select result or run the selection and cache
;; the result.
(unless (and nnselect-artlist dont-check)
(gnus-group-set-parameter
group 'nnselect-artlist
(setq nnselect-artlist
(nnselect-run
(gnus-group-get-parameter group 'nnselect-specs t))))
(nnselect-request-update-info
group (or info (gnus-get-info group))))
(if (zerop (setq length (nnselect-artlist-length nnselect-artlist)))
(progn
(nnheader-report 'nnselect "Selection produced empty results.")
(nnheader-insert ""))
(with-current-buffer nntp-server-buffer
(nnheader-insert "211 %d %d %d %s\n"
length ; total #
1 ; first #
length ; last #
group)))) ; group name
nnselect-artlist)
(deffoo nnselect-retrieve-headers (articles &optional _group _server fetch-old)
(setq gnus-newsgroup-selection (or gnus-newsgroup-selection nnselect-artlist))
(let ((gnus-inhibit-demon t)
(gartids (ids-by-group articles))
headers)
(with-current-buffer nntp-server-buffer
(pcase-dolist (`(,artgroup . ,artids) gartids)
(let ((artlist (sort (mapcar 'cdr artids) '<))
(gnus-override-method (gnus-find-method-for-group artgroup))
(fetch-old
(or
(car-safe
(gnus-group-find-parameter artgroup 'gnus-fetch-old-headers t))
fetch-old))
parsefunc)
(erase-buffer)
(pcase (setq gnus-headers-retrieved-by
(or
(and
nnselect-retrieve-headers-override-function
(funcall nnselect-retrieve-headers-override-function
artlist artgroup))
(gnus-retrieve-headers artlist artgroup fetch-old)))
('nov
(setq parsefunc 'nnheader-parse-nov))
('headers
(setq parsefunc 'nnheader-parse-head))
(_ (error "Unknown header type %s while requesting articles \
of group %s" gnus-headers-retrieved-by artgroup)))
(goto-char (point-min))
(while (not (eobp))
(let* ((novitem (funcall parsefunc))
(artno (and novitem
(mail-header-number novitem)))
(art (car (rassq artno artids))))
(when art
(mail-header-set-number novitem art)
(push novitem headers))
(forward-line 1)))))
(setq headers
(sort headers
(lambda (x y)
(< (mail-header-number x) (mail-header-number y)))))
(erase-buffer)
(mapc 'nnheader-insert-nov headers)
'nov)))
(declare-function gnus-search-run-query "gnus-search" (specs))
(deffoo nnselect-request-article (article &optional _group server to-buffer)
(let* ((gnus-override-method nil)
servers group-art artlist)
(if (numberp article)
(with-current-buffer gnus-summary-buffer
(unless (zerop (nnselect-artlist-length
gnus-newsgroup-selection))
(setq group-art (cons (nnselect-article-group article)
(nnselect-article-number article)))))
;; message-id: either coming from a referral or a pseudo-article
;; find the servers for a pseudo-article
(if (eq 'nnselect (car (gnus-server-to-method server)))
(with-current-buffer gnus-summary-buffer
(let ((thread (gnus-id-to-thread article)))
(when thread
(mapc
#'(lambda (x)
(when (and x (> x 0))
(cl-pushnew
(list
(gnus-method-to-server
(gnus-find-method-for-group
(nnselect-article-group x)))) servers :test 'equal)))
(gnus-articles-in-thread thread)))))
(setq servers (list (list server))))
(setq artlist
(gnus-search-run-query
(list
(cons 'search-query-spec
(list (cons 'query `((id . ,article)))))
(cons 'search-group-spec servers))))
(unless (zerop (nnselect-artlist-length artlist))
(setq
group-art
(cons
(nnselect-artitem-group (nnselect-artlist-article artlist 1))
(nnselect-artitem-number (nnselect-artlist-article artlist 1))))))
(when (numberp (cdr group-art))
(message "Requesting article %d from group %s"
(cdr group-art) (car group-art))
(if to-buffer
(with-current-buffer to-buffer
(let ((gnus-article-decode-hook nil))
(gnus-request-article-this-buffer
(cdr group-art) (car group-art))))
(gnus-request-article (cdr group-art) (car group-art)))
group-art)))
(deffoo nnselect-request-move-article
(article _group _server accept-form &optional last _internal-move-group)
;; is this necessary?
;; (nnselect-possibly-change-group group server)
(let* ((artgroup (nnselect-article-group article))
(artnumber (nnselect-article-number article))
(to-newsgroup (nth 1 accept-form))
(to-method (gnus-find-method-for-group to-newsgroup))
(from-method (gnus-find-method-for-group artgroup))
(move-is-internal (gnus-server-equal from-method to-method)))
(unless (gnus-check-backend-function
'request-move-article artgroup)
(error "The group %s does not support article moving" artgroup))
(gnus-request-move-article
artnumber
artgroup
(nth 1 from-method)
accept-form
last
(and move-is-internal
to-newsgroup ; Not respooling
(gnus-group-real-name to-newsgroup)))))
(deffoo nnselect-request-expire-articles
(articles _group &optional _server force)
;; is this necessary?
;; (nnselect-possibly-change-group group server)
(if force
(let (not-expired)
(pcase-dolist (`(,artgroup . ,artids) (ids-by-group articles))
(let ((artlist (sort (mapcar 'cdr artids) '<)))
(unless (gnus-check-backend-function 'request-expire-articles
artgroup)
(error "Group %s does not support article expiration" artgroup))
(unless (gnus-check-server (gnus-find-method-for-group artgroup))
(error "Couldn't open server for group %s" artgroup))
(push (mapcar #'(lambda (art)
(car (rassq art artids)))
(gnus-request-expire-articles
artlist artgroup force))
not-expired)))
(sort (delq nil not-expired) '<))
articles))
(deffoo nnselect-warp-to-article ()
;; is this necessary?
;; (nnselect-possibly-change-group gnus-newsgroup-name)
(let* ((cur (if (> (gnus-summary-article-number) 0)
(gnus-summary-article-number)
(error "Can't warp to a pseudo-article")))
(artgroup (nnselect-article-group cur))
(artnumber (nnselect-article-number cur))
(_quit-config (gnus-ephemeral-group-p gnus-newsgroup-name)))
;; what should we do here? we could leave all the buffers around
;; and assume that we have to exit from them one by one. or we can
;; try to clean up directly
;;first exit from the nnselect summary buffer.
; (gnus-summary-exit)
;; and if the nnselect summary buffer in turn came from another
;; summary buffer we have to clean that summary up too.
; (when (not (eq (cdr quit-config) 'group))
; (gnus-summary-exit))
(gnus-summary-read-group-1 artgroup t t nil
nil (list artnumber))))
;; we pass this through to the real group in case it wants to adjust
;; the mark. We also use this to mark an article expirable iff it is
;; expirable in the real group.
(deffoo nnselect-request-update-mark (_group article mark)
(let* ((artgroup (nnselect-article-group article))
(artnumber (nnselect-article-number article))
(gmark (gnus-request-update-mark artgroup artnumber mark)))
(when (and artnumber
(memq mark gnus-auto-expirable-marks)
(= mark gmark)
(gnus-group-auto-expirable-p artgroup))
(setq gmark gnus-expirable-mark))
gmark))
(deffoo nnselect-request-set-mark (_group actions &optional _server)
;; is this necessary?
;; (nnselect-possibly-change-group group server)
(mapc
(lambda (request) (gnus-request-set-mark (car request) (cdr request)))
(nnselect-categorize
(cl-mapcan
(lambda (act)
(cl-destructuring-bind (range action marks) act
(mapcar
(lambda (artgroup)
(list (car artgroup)
(gnus-compress-sequence (sort (cdr artgroup) '<))
action marks))
(numbers-by-group
(gnus-uncompress-range range)))))
actions)
'car 'cdr)))
(deffoo nnselect-request-update-info (group info &optional server)
(let ((group (nnselect-possibly-change-group group server))
(gnus-newsgroup-selection (or gnus-newsgroup-selection
nnselect-artlist)))
(gnus-info-set-marks info nil)
(gnus-info-set-read info nil)
(pcase-dolist (`(,artgroup . ,nartids)
(ids-by-group
(number-sequence 1 (nnselect-artlist-length
gnus-newsgroup-selection))))
(let* ((gnus-newsgroup-active nil)
(artids (cl-sort nartids '< :key 'car))
(group-info (gnus-get-info artgroup))
(marks (gnus-info-marks group-info))
(read (gnus-uncompress-sequence (gnus-info-read group-info))))
(gnus-atomic-progn
(gnus-info-set-read
info
(gnus-add-to-range
(gnus-info-read info)
(delq nil
(mapcar
#'(lambda (art)
(when (member (cdr art) read) (car art)))
artids))))
(pcase-dolist (`(,type . ,range) marks)
(setq range (gnus-uncompress-sequence range))
(gnus-add-marked-articles
group type
(delq nil
(mapcar
#'(lambda (art)
(when (member (cdr art) range)
(car art))) artids)))))))
(gnus-set-active group (cons 1 (nnselect-artlist-length
gnus-newsgroup-selection)))))
(declare-function gnus-search-run-query "gnus-search" (specs))
(deffoo nnselect-request-thread (header &optional group server)
(let ((group (nnselect-possibly-change-group group server)) ;; necessary?
;; find the best group for the originating article. if its a
;; pseudo-article look for real articles in the same thread
;; and see where they come from.
(artgroup (nnselect-article-group
(if (> (mail-header-number header) 0)
(mail-header-number header)
(with-current-buffer gnus-summary-buffer
(if (> (gnus-summary-article-number) 0)
(gnus-summary-article-number)
(let ((thread
(gnus-id-to-thread (mail-header-id header))))
(when thread
(cl-some #'(lambda (x)
(when (and x (> x 0)) x))
(gnus-articles-in-thread thread))))))))))
;; Check if search-based thread referral is permitted, and
;; possible.
(if (and gnus-refer-thread-use-search
(gnus-search-server-to-engine
(gnus-method-to-server
(gnus-find-method-for-group artgroup))))
;; If so we perform the query, massage the result, and return
;; the new headers back to the caller to incorporate into the
;; current summary buffer.
(let* ((group-spec
(list (delq nil (list
(or server (gnus-group-server artgroup))))))
(ids (cons (mail-header-id header)
(split-string
(or (mail-header-references header)
""))))
(query-spec
(list (cons 'query (mapconcat (lambda (i)
(format "id:%s" i))
ids " or "))
(cons 'thread t)))
(last (nnselect-artlist-length gnus-newsgroup-selection))
(first (1+ last))
(new-nnselect-artlist
(gnus-search-run-query
(list (cons 'search-query-spec query-spec)
(cons 'search-group-spec group-spec))))
old-arts seq
headers)
(mapc
#'(lambda (article)
(if
(setq seq
(cl-position article
gnus-newsgroup-selection :test 'equal))
(push (1+ seq) old-arts)
(setq gnus-newsgroup-selection
(vconcat gnus-newsgroup-selection (vector article)))
(cl-incf last)))
new-nnselect-artlist)
(setq headers
(gnus-fetch-headers
(append (sort old-arts '<)
(number-sequence first last)) nil t))
(gnus-group-set-parameter
group
'nnselect-artlist
gnus-newsgroup-selection)
(when (>= last first)
(let (new-marks)
(pcase-dolist (`(,artgroup . ,artids)
(ids-by-group (number-sequence first last)))
(pcase-dolist (`(,type . ,marked)
(gnus-info-marks (gnus-get-info artgroup)))
(setq marked (gnus-uncompress-sequence marked))
(when (setq new-marks
(delq nil
(mapcar
#'(lambda (art)
(when (member (cdr art) marked)
(car art)))
artids)))
(nconc
(symbol-value (intern (format "gnus-newsgroup-%s"
(car (rassq type gnus-article-mark-lists)))))
new-marks)))))
(setq gnus-newsgroup-active
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection)))
(gnus-set-active
group
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection))))
headers)
;; If we can't or won't use search, just warp to the original
;; article group and punt back to gnus-summary-refer-thread.
(and (gnus-warp-to-article) (gnus-summary-refer-thread)))))
(deffoo nnselect-close-group (group &optional server)
(let ((group (nnselect-possibly-change-group group server)))
(unless gnus-group-is-exiting-without-update-p
(nnselect-push-info group))
(setq nnselect-artlist nil)
(when (gnus-ephemeral-group-p group)
(gnus-kill-ephemeral-group group)
(setq gnus-ephemeral-servers
(assq-delete-all 'nnselect gnus-ephemeral-servers)))))
(deffoo nnselect-request-create-group (group &optional _server args)
(message "Creating nnselect group %s" group)
(let* ((group (gnus-group-prefixed-name group '(nnselect "nnselect")))
(specs (assq 'nnselect-specs args))
(function-spec
(or (alist-get 'nnselect-function specs)
(intern (completing-read "Function: " obarray #'functionp))))
(args-spec
(or (alist-get 'nnselect-args specs)
(read-from-minibuffer "Args: " nil nil t nil "nil")))
(nnselect-specs (list (cons 'nnselect-function function-spec)
(cons 'nnselect-args args-spec))))
(gnus-group-set-parameter group 'nnselect-specs nnselect-specs)
(gnus-group-set-parameter
group 'nnselect-artlist
(or (alist-get 'nnselect-artlist args)
(nnselect-run nnselect-specs)))
(nnselect-request-update-info group (gnus-get-info group)))
t)
(deffoo nnselect-request-type (_group &optional article)
(if (and (numberp article) (> article 0))
(gnus-request-type
(nnselect-article-group article) (nnselect-article-number article))
'unknown))
(deffoo nnselect-request-post (&optional _server)
(if (not gnus-message-group-art)
(nnheader-report 'nnselect "Can't post to an nnselect group")
(gnus-request-post
(gnus-find-method-for-group
(nnselect-article-group (cdr gnus-message-group-art))))))
(deffoo nnselect-request-rename-group (_group _new-name &optional _server)
t)
(deffoo nnselect-request-scan (_group _method)
t)
(deffoo nnselect-request-list (&optional _server)
t)
;; Add any undefined required backend functions
(nnoo-define-skeleton nnselect)
;;; Util Code:
(defun gnus-nnselect-group-p (group)
"Say whether GROUP is nnselect or not."
(or (and (gnus-group-prefixed-p group)
(eq 'nnselect (car (gnus-find-method-for-group group))))
(eq 'nnselect (car gnus-command-method))))
(defun nnselect-run (specs)
"Apply FUNCTION to ARGS and return an article list."
(let ((func (alist-get 'nnselect-function specs))
(args (alist-get 'nnselect-args specs)))
(funcall func args)))
(defun nnselect-possibly-change-group (group &optional _server)
"If GROUP method for SERVER is `nnselect' install the
`nnselect-artlist'. Return the fully prefixed group name."
;; (or (not server) (nnselect-server-opened server)
;; (nnselect-open-server server))
(let ((group (gnus-group-prefixed-name
(gnus-group-short-name group) '(nnselect "nnselect"))))
(when (gnus-nnselect-group-p group)
(setq nnselect-artlist (gnus-group-get-parameter
group
'nnselect-artlist t)))
group))
(declare-function gnus-registry-get-id-key "gnus-registry"
(id key))
(defun nnselect-search-thread (header)
"Make an nnselect group containing the thread with article HEADER.
The current server will be searched. If the registry is
installed, the server that the registry reports the current
article came from is also searched."
(let* ((ids (cons (mail-header-id header)
(split-string
(or (mail-header-references header)
""))))
(query
(list (cons 'query (mapconcat (lambda (i)
(format "id:%s" i))
ids " or "))
(cons 'thread t)))
(server
(list (list (gnus-method-to-server
(gnus-find-method-for-group gnus-newsgroup-name)))))
(registry-group (and
(bound-and-true-p gnus-registry-enabled)
(car (gnus-registry-get-id-key
(mail-header-id header) 'group))))
(registry-server
(and registry-group
(gnus-method-to-server
(gnus-find-method-for-group registry-group)))))
(when registry-server (cl-pushnew (list registry-server) server
:test 'equal))
(gnus-group-read-ephemeral-group
(concat "nnselect-" (message-unique-id))
(list 'nnselect "nnselect")
nil
(cons (current-buffer) gnus-current-window-configuration)
; nil
nil nil
(list
(cons 'nnselect-specs
(list
(cons 'nnselect-function 'gnus-search-run-query)
(cons 'nnselect-args
(list (cons 'search-query-spec query)
(cons 'search-group-spec server)))))
(cons 'nnselect-artlist nil)))
(gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header)))))
(defun nnselect-push-info (group)
"Copy read and article mark info from the nnselect group to the
originating groups."
(let ((select-unreads (numbers-by-group gnus-newsgroup-unreads))
(select-reads (numbers-by-group
(gnus-uncompress-range
(gnus-info-read (gnus-get-info group)))))
(select-unseen (numbers-by-group gnus-newsgroup-unseen))
(gnus-newsgroup-active nil)
mark-list type-list)
(pcase-dolist (`(,mark . ,type) gnus-article-mark-lists)
(when (setq type-list
(symbol-value (intern (format "gnus-newsgroup-%s" mark))))
(push (cons type
(numbers-by-group
(gnus-uncompress-range type-list))) mark-list)))
(pcase-dolist (`(,artgroup . ,artlist)
(numbers-by-group gnus-newsgroup-articles))
(let* ((group-info (gnus-get-info artgroup))
(old-unread (gnus-list-of-unread-articles artgroup))
newmarked)
(when group-info
(pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists)
(let ((select-type
(sort
(cdr (assoc artgroup (alist-get type mark-list)))
'<)) list)
(setq list
(gnus-uncompress-range
(gnus-add-to-range
(gnus-remove-from-range
(alist-get type (gnus-info-marks group-info))
artlist)
select-type)))
(when list
;; Get rid of the entries of the articles that have the
;; default score.
(when (and (eq type 'score)
gnus-save-score
list)
(let* ((arts list)
(prev (cons nil list))
(all prev))
(while arts
(if (or (not (consp (car arts)))
(= (cdar arts) gnus-summary-default-score))
(setcdr prev (cdr arts))
(setq prev arts))
(setq arts (cdr arts)))
(setq list (cdr all)))))
(when (or (eq (gnus-article-mark-to-type type) 'list)
(eq (gnus-article-mark-to-type type) 'range))
(setq list
(gnus-compress-sequence (sort list '<) t)))
;; When exiting the group, everything that's previously been
;; unseen is now seen.
(when (eq type 'seen)
(setq list (gnus-range-add
list (cdr (assoc artgroup select-unseen)))))
(when (or list (eq type 'unexist))
(push (cons type list) newmarked))))
(gnus-atomic-progn
;; Enter these new marks into the info of the group.
(if (nthcdr 3 group-info)
(setcar (nthcdr 3 group-info) newmarked)
;; Add the marks lists to the end of the info.
(when newmarked
(setcdr (nthcdr 2 group-info) (list newmarked))))
;; Cut off the end of the info if there's nothing else there.
(let ((i 5))
(while (and (> i 2)
(not (nth i group-info)))
(when (nthcdr (cl-decf i) group-info)
(setcdr (nthcdr i group-info) nil))))
;; update read and unread
(gnus-update-read-articles
artgroup
(gnus-uncompress-range
(gnus-add-to-range
(gnus-remove-from-range
old-unread
(cdr (assoc artgroup select-reads)))
(sort (cdr (assoc artgroup select-unreads)) '<))))
(gnus-get-unread-articles-in-group
group-info (gnus-active artgroup) t)
(gnus-group-update-group artgroup t)))))))
(declare-function gnus-registry-get-id-key "gnus-registry" (id key))
(defun gnus-summary-make-search-group (extra-parms)
"Search a group from the summary buffer."
(interactive "P")
(gnus-warp-to-article)
(let ((spec
(list
(cons 'search-group-spec
(list (list
(gnus-group-server gnus-newsgroup-name)
gnus-newsgroup-name))))))
(gnus-group-make-search-group extra-parms spec)))
;; The end.
(provide 'nnselect)
;;; nnselect.el ends here

View file

@ -69,17 +69,15 @@
"^\\*\\*\\* Starting TLS handshake\n\\)*"
"\\)")
"Regexp matching end of TLS client informational messages.
Client data stream begins after the last character matched by
this. The default matches `openssl s_client' (version 0.9.8c)
and `gnutls-cli' (version 2.0.1) output."
Client data stream begins after the last character this matches.
The default matches the output of \"gnutls-cli\" (version 2.0.1)."
:version "22.2"
:type 'regexp
:group 'tls)
(defcustom tls-program
'("gnutls-cli --x509cafile %t -p %p %h"
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
"openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
"List of strings containing commands to start TLS stream to a host.
Each entry in the list is tried until a connection is successful.
%h is replaced with the server hostname, %p with the port to
@ -94,24 +92,21 @@ successful negotiation."
'(choice
(const :tag "Default list of commands"
("gnutls-cli --x509cafile %t -p %p %h"
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
"openssl s_client -CAfile %t -connect %h:%p -no_ssl2 -ign_eof"))
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"))
(list :tag "Choose commands"
:value
("gnutls-cli --x509cafile %t -p %p %h"
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
"openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
(set :inline t
;; FIXME: add brief `:tag "..."' descriptions.
;; (repeat :inline t :tag "Other" (string))
;; No trust check:
(const "gnutls-cli --insecure -p %p %h")
(const "gnutls-cli --insecure -p %p %h --protocols ssl3")
(const "openssl s_client -connect %h:%p -no_ssl2 -ign_eof"))
(const "gnutls-cli --insecure -p %p %h --protocols ssl3"))
(repeat :inline t :tag "Other" (string)))
(list :tag "List of commands"
(repeat :tag "Command" (string))))
:version "22.1"
:version "26.1" ; remove s_client
:group 'tls)
(defcustom tls-process-connection-type nil
@ -122,8 +117,8 @@ successful negotiation."
(defcustom tls-success "- Handshake was completed\\|SSL handshake has read "
"Regular expression indicating completed TLS handshakes.
The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
\"openssl s_client\" outputs."
The default is what GnuTLS's \"gnutls-cli\" outputs."
;; or OpenSSL's \"openssl s_client\"
:version "22.1"
:type 'regexp
:group 'tls)
@ -138,8 +133,7 @@ consider trustworthy, e.g.:
\(setq tls-program
\\='(\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h\"
\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3\"
\"openssl s_client -connect %h:%p -CAfile /etc/ssl/certs/ca-certificates.crt -no_ssl2 -ign_eof\"))"
\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3\"))"
:type '(choice (const :tag "Always" t)
(const :tag "Never" nil)
(const :tag "Ask" ask))
@ -149,9 +143,9 @@ consider trustworthy, e.g.:
(defcustom tls-untrusted
"- Peer's certificate is NOT trusted\\|Verify return code: \\([^0] \\|.[^ ]\\)"
"Regular expression indicating failure of TLS certificate verification.
The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
\"openssl s_client\" return in the event of unsuccessful
verification."
The default is what GnuTLS's \"gnutls-cli\" returns in the event of
unsuccessful verification."
;; or OpenSSL's \"openssl s_client\"
:type 'regexp
:version "23.1" ;; No Gnus
:group 'tls)

View file

@ -302,7 +302,7 @@ - (void)dealloc
planes[1][i] = gg;
planes[2][i] = bb;
}
xbm_fg = ((rr << 16) & 0xff) + ((gg << 8) & 0xff) + (bb & 0xff);
xbm_fg = ((rr << 16) & 0xff0000) + ((gg << 8) & 0xff00) + (bb & 0xff);
}
return self;

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

View file

@ -0,0 +1,99 @@
;;; gnus-search-tests.el --- Tests for Gnus' search routines -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Free Software Foundation, Inc.
;; Author: Eric Abrahamsen <eric@ericabrahamsen.net>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Tests for the search parsing, search engines, and their
;; transformations.
;;; Code:
(require 'ert)
(require 'gnus-search)
(ert-deftest gnus-s-parse ()
"Test basic structural parsing."
(let ((pairs
'(("string" . ("string"))
("from:john" . ((from . "john")))
("here and there" . ("here" and "there"))
("here or there" . ((or "here" "there")))
("here (there or elsewhere)" . ("here" ((or "there" "elsewhere"))))
("here not there" . ("here" (not "there")))
("from:boss or not vacation" . ((or (from . "boss") (not "vacation")))))))
(dolist (p pairs)
(should (equal (gnus-search-parse-query (car p)) (cdr p))))))
(ert-deftest gnus-s-expand-keyword ()
"Test expansion of keywords"
(let ((gnus-search-expandable-keys
(default-value 'gnus-search-expandable-keys))
(pairs
'(("su" . "subject")
("f" . "from")
("co-f" . "contact-from"))))
(dolist (p pairs)
(should (equal (gnus-search-query-expand-key (car p))
(cdr p))))
(should-error (gnus-search-query-expand-key "s")
:type 'gnus-search-parse-error)
(should-error (gnus-search-query-expand-key "c-f")
:type 'gnus-search-parse-error)))
(ert-deftest gnus-s-parse-date ()
"Test parsing of date expressions."
(let ((rel-date (encode-time 0 0 0 15 4 2017))
(pairs
'(("January" . (nil 1 nil))
("2017" . (nil nil 2017))
("15" . (15 nil nil))
("January 15" . (15 1 nil))
("tuesday" . (11 4 2017))
("1d" . (14 4 2017))
("1w" . (8 4 2017)))))
(dolist (p pairs)
(should (equal (gnus-search-query-parse-date (car p) rel-date)
(cdr p))))))
(ert-deftest gnus-s-delimited-string ()
"Test proper functioning of `gnus-search-query-return-string'."
(with-temp-buffer
(insert "one\ntwo words\nthree \"words with quotes\"\n\"quotes at start\"\n/alternate \"quotes\"/\n(more bits)")
(goto-char (point-min))
(should (string= (gnus-search-query-return-string)
"one"))
(forward-line)
(should (string= (gnus-search-query-return-string)
"two"))
(forward-line)
(should (string= (gnus-search-query-return-string)
"three"))
(forward-line)
(should (string= (gnus-search-query-return-string "\"")
"\"quotes at start\""))
(forward-line)
(should (string= (gnus-search-query-return-string "/")
"/alternate \"quotes\"/"))
(forward-line)
(should (string= (gnus-search-query-return-string ")" t)
"more bits"))))
(provide 'gnus-search-tests)
;;; search-tests.el ends here

View file

@ -22,15 +22,21 @@
;;; Code:
(defmacro im-should (form)
`(unless ,form
(error "%s didn't succeed" ',form)))
(defmacro im-should (image width height &rest props)
`(let ((im (im-image ,image ,@props)))
(unless (im-compare im ,width ,height)
(error "%s didn't succeed; size is %s"
',props (image-size im t)))))
(defun im-image (&rest props)
(defun im-image (type &rest props)
(let ((image-scaling-factor 1))
(apply
#'create-image
(expand-file-name "test/data/image/blank-200x100.png" source-directory)
(expand-file-name
(if (eq type :w)
"test/data/image/blank-200x100.png"
"test/data/image/blank-100x200.png")
source-directory)
'imagemagick nil props)))
(defun im-compare (image width height)
@ -41,24 +47,46 @@
(defun image-size-tests ()
(unless (imagemagick-types)
(error "This only makes sense if ImageMagick is installed"))
;; Test the image that's wider than it is tall.
;; Default sizes.
(im-should (im-compare (im-image) 200 100))
(im-should :w 200 100)
;; Changing one dimension changes the other.
(im-should (im-compare (im-image :width 100) 100 50))
(im-should (im-compare (im-image :height 50) 100 50))
(im-should :w 100 50 :width 100)
(im-should :w 100 50 :height 50)
;; The same with :max-width etc.
(im-should (im-compare (im-image :max-width 100) 100 50))
(im-should (im-compare (im-image :max-height 50) 100 50))
(im-should :w 100 50 :max-width 100)
(im-should :w 100 50 :max-height 50)
;; :width wins over :max-width etc
(im-should (im-compare (im-image :width 300 :max-width 100) 300 150))
(im-should (im-compare (im-image :height 200 :max-height 100) 400 200))
(im-should :w 300 150 :width 300 :max-width 100)
(im-should :w 400 200 :height 200 :max-height 100)
;; Specifying both width and height is fine.
(im-should (im-compare (im-image :width 300 :height 50) 300 50))
(im-should :w 300 50 :width 300 :height 50)
;; A too-large :max-width (etc) has no effect.
(im-should (im-compare (im-image :max-width 300) 200 100))
(im-should (im-compare (im-image :max-height 300) 200 100))
(im-should :w 200 100 :max-width 300)
(im-should :w 200 100 :max-height 300)
;; Both max-width/height.
(im-should (im-compare (im-image :max-width 100 :max-height 75) 100 50))
(im-should (im-compare (im-image :max-width 100 :max-height 25) 50 25)))
(im-should :w 100 50 :max-width 100 :max-height 75)
(im-should :w 50 25 :max-width 100 :max-height 25)
;; Test the image that's taller than it is wide.
(im-should :h 100 200)
;; Changing one dimension changes the other.
(im-should :h 50 100 :width 50)
(im-should :h 50 100 :height 100)
;; The same with :max-width etc.
(im-should :h 50 100 :max-width 50)
(im-should :h 50 100 :max-height 100)
;; :width wins over :max-width etc
(im-should :h 300 600 :width 300 :max-width 100)
(im-should :h 150 300 :height 300 :max-height 100)
;; Specifying both width and height is fine.
(im-should :h 300 50 :width 300 :height 50)
;; A too-large :max-width (etc) has no effect.
(im-should :h 100 200 :max-width 300)
(im-should :h 100 200 :max-height 300)
;; Both max-width/height.
(im-should :h 50 100 :max-width 75 :max-height 100)
(im-should :h 25 50 :max-width 25 :max-height 100)
)
;;; image-size-tests.el ends here