Merge changes made in Gnus trunk
2012-03-22 Lars Magne Ingebrigtsen <larsi@gnus.org> * gnus.texi (Client-Side IMAP Splitting): Note that `nnimap-inbox' now can be a list. 2013-06-05 David Engster <deng@randomsample.de> * gnus-sum.el (gnus-update-marks): Do not remove empty 'unexist' ranges, since `nnimap-retrieve-group-data-early' also uses it as a flag to see whether the group was synced before. 2012-09-05 Martin Stjernholm <mast@lysator.liu.se> * nnimap.el (nnimap-request-move-article): Decode the group name when doing internal moves to avoid charset issues. 2012-09-05 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-request-list): Revert change that made listing synchronous. (nnimap-get-responses): Restore. 2012-08-31 Dave Abrahams <dave@boostpro.com> * nnimap.el (nnimap-change-group): Document result value. * nnimap.el (nnimap-find-article-by-message-id): Account for the fact that nnimap-change-group can return t. 2012-08-06 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-request-head): Resture to-buffer parameter, used by `nnimap-request-move-article'. * nnimap.el (nnimap-request-head): Remove to-buffer argument. * gnus-int.el (gnus-request-head): Remove to-buffer argument, only supported by nnimap actually. Reverts previous change. * gnus-int.el (gnus-request-head): Add an optional to-buffer parameter to mimic `gnus-request-article' and enjoy backends the nn*-request-head to-buffer argument that is already supported. 2012-07-24 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-get-responses): Remove, unused. 2012-06-25 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-request-articles-find-limit): Rename from `nnimap-request-move-articles-find-limit' since we do not use it only for move operations. (nnimap-request-accept-article): Use `nnimap-request-articles-find-limit' to limit search by message-id. 2012-06-19 Julien Danjou <julien@danjou.info> * nnir.el (nnir-run-imap): Fix, use `nnimap-change-group'. * nnimap.el (nnimap-log-buffer): Check that `window-point-insertion-type' is boundp, since it's not available in XEmacs. 2012-06-19 Michael Welsh Duggan <md5i@md5i.com> * nnimap.el (nnimap-log-buffer): Add this, setting `window-point-insertion-type' in the buffer to t. (nnimap-log-command): Use nnimap-log-buffer. 2012-06-19 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-find-article-by-message-id): Add an optional limit argument to be able to limit the search. (nnimap-request-move-article): Use `nnimap-request-move-articles-find-limit'. (nnimap-request-move-articles-find-limit): Add this to limit the search by Message-Id after a message move. (nnimap): Add defgroup. 2012-06-15 Julien Danjou <julien@danjou.info> * nnimap.el (nnimap-find-article-by-message-id): Use `nnimap-possibly-change-group' rather than its own EXAMINE call. (nnimap-possibly-change-group): Add read-only argument. (nnimap-request-list): Use nnimap-possibly-change-group rather than issuing EXAMINE manually. (nnimap-find-article-by-message-id): Use `nnimap-possibly-change-group' with read-only argument. (nnimap-change-group): Rename from `nnimap-possibly-change-group'. We cannot possibly change because we need to be sure that it's either read-write or read-only. 2012-06-10 Lars Magne Ingebrigtsen <larsi@gnus.org> * gnus-sum.el (gnus-summary-insert-old-articles): Don't include unexistent messages. 2012-04-10 Lars Magne Ingebrigtsen <larsi@gnus.org> * gnus-start.el (gnus-clean-old-newsrc): Remove totally bogus `unexists' entries. (gnus-clean-old-newsrc): Fix last checkin. * nnimap.el (nnimap-update-info): None of the articles below the active low-water mark exist. 2012-03-27 Katsumi Yamaoka <yamaoka@jpl.org> * nnimap.el (gnus-refer-thread-use-nnir): Silence the byte compiler. 2012-03-22 Sergio Martinez <samf0xb58@gmail.com> (tiny change) * nnimap.el (nnimap-request-scan): Allow `nnimap-inbox' to be a list of inboxes. 2012-03-10 Lars Magne Ingebrigtsen <larsi@gnus.org> * gnus-group.el (gnus-group-expire-articles-1): Don't try to expire messages that don't exist. * gnus-sum.el (gnus-summary-expire-articles): Ditto. 2012-02-20 Lars Ingebrigtsen <larsi@gnus.org> * gnus-start.el (gnus-clean-old-newsrc): Allow a FORCE parameter. 2012-02-15 Lars Ingebrigtsen <larsi@gnus.org> * gnus-start.el (gnus-clean-old-newsrc): Delete `unexist' from pre-Ma Gnus 0.3. 2012-02-15 Lars Ingebrigtsen <larsi@gnus.org> * gnus-sum.el (gnus-summary-local-variables): Make `gnus-newsgroup-unexist' into a local variable. 2012-02-11 Lars Ingebrigtsen <larsi@gnus.org> * gnus-sum.el (gnus-adjust-marked-articles): Add to `gnus-newsgroup-unexist'. * gnus.el (gnus-article-mark-lists): Add `unexist' to the list of marks. (gnus-article-special-mark-lists): Put the `unexist' in the special marks list instead. * gnus-sum.el (gnus-articles-to-read): Don't include unexisting articles in the list of articles to be selected. * nnimap.el (nnimap-retrieve-group-data-early): Query for unexisting articles. (nnimap-update-info): Keep track of unexisting articles. (nnimap-update-qresync-info): Ditto. 2012-02-01 Lars Ingebrigtsen <larsi@gnus.org> * gnus-start.el (gnus-clean-old-newsrc): New function. (gnus-read-newsrc-file): Use it.
This commit is contained in:
parent
646b949918
commit
eaa610c3b4
9 changed files with 371 additions and 95 deletions
|
@ -1,3 +1,8 @@
|
|||
2013-07-02 Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus.texi (Client-Side IMAP Splitting):
|
||||
Note that `nnimap-inbox' now can be a list.
|
||||
|
||||
2013-06-24 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* eshell.texi: Fix cross-references to other manuals.
|
||||
|
|
|
@ -14240,7 +14240,8 @@ variables are relevant:
|
|||
|
||||
@table @code
|
||||
@item nnimap-inbox
|
||||
This is the @acronym{IMAP} mail box that will be scanned for new mail.
|
||||
This is the @acronym{IMAP} mail box that will be scanned for new
|
||||
mail. This can also be a list of mail box names.
|
||||
|
||||
@item nnimap-split-methods
|
||||
Uses the same syntax as @code{nnmail-split-methods} (@pxref{Splitting
|
||||
|
|
|
@ -1,3 +1,157 @@
|
|||
2013-07-02 David Engster <deng@randomsample.de>
|
||||
|
||||
* gnus-sum.el (gnus-update-marks): Do not remove empty 'unexist'
|
||||
ranges, since `nnimap-retrieve-group-data-early' also uses it as a flag
|
||||
to see whether the group was synced before.
|
||||
|
||||
2013-07-02 Martin Stjernholm <mast@lysator.liu.se>
|
||||
|
||||
* nnimap.el (nnimap-request-move-article): Decode the group name when
|
||||
doing internal moves to avoid charset issues.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-request-list):
|
||||
Revert change that made listing synchronous.
|
||||
(nnimap-get-responses): Restore.
|
||||
|
||||
2013-07-02 Dave Abrahams <dave@boostpro.com>
|
||||
|
||||
* nnimap.el (nnimap-change-group): Document result value.
|
||||
|
||||
* nnimap.el (nnimap-find-article-by-message-id):
|
||||
Account for the fact that nnimap-change-group can return t.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-request-head):
|
||||
Resture to-buffer parameter, used by `nnimap-request-move-article'.
|
||||
|
||||
* nnimap.el (nnimap-request-head): Remove to-buffer argument.
|
||||
|
||||
* gnus-int.el (gnus-request-head): Remove to-buffer argument, only
|
||||
supported by nnimap actually. Reverts previous change.
|
||||
|
||||
* gnus-int.el (gnus-request-head): Add an optional to-buffer parameter
|
||||
to mimic `gnus-request-article' and enjoy backends the nn*-request-head
|
||||
to-buffer argument that is already supported.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-get-responses): Remove, unused.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-request-articles-find-limit): Rename from
|
||||
`nnimap-request-move-articles-find-limit' since we do not use it
|
||||
only for move operations.
|
||||
(nnimap-request-accept-article):
|
||||
Use `nnimap-request-articles-find-limit' to limit search by message-id.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnir.el (nnir-run-imap): Fix, use `nnimap-change-group'.
|
||||
|
||||
* nnimap.el (nnimap-log-buffer):
|
||||
Check that `window-point-insertion-type' is boundp, since it's not
|
||||
available in XEmacs.
|
||||
|
||||
2013-07-02 Michael Welsh Duggan <md5i@md5i.com>
|
||||
|
||||
* nnimap.el (nnimap-log-buffer):
|
||||
Add this, setting `window-point-insertion-type' in the buffer to t.
|
||||
(nnimap-log-command): Use nnimap-log-buffer.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-find-article-by-message-id):
|
||||
Add an optional limit argument to be able to limit the search.
|
||||
(nnimap-request-move-article):
|
||||
Use `nnimap-request-move-articles-find-limit'.
|
||||
(nnimap-request-move-articles-find-limit):
|
||||
Add this to limit the search by Message-Id after a message move.
|
||||
(nnimap): Add defgroup.
|
||||
|
||||
2013-07-02 Julien Danjou <julien@danjou.info>
|
||||
|
||||
* nnimap.el (nnimap-find-article-by-message-id):
|
||||
Use `nnimap-possibly-change-group' rather than its own EXAMINE call.
|
||||
(nnimap-possibly-change-group): Add read-only argument.
|
||||
(nnimap-request-list): Use nnimap-possibly-change-group rather than
|
||||
issuing EXAMINE manually.
|
||||
(nnimap-find-article-by-message-id):
|
||||
Use `nnimap-possibly-change-group' with read-only argument.
|
||||
(nnimap-change-group): Rename from `nnimap-possibly-change-group'.
|
||||
We cannot possibly change because we need to be sure that it's either
|
||||
read-write or read-only.
|
||||
|
||||
2013-07-02 Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-sum.el (gnus-summary-insert-old-articles):
|
||||
Don't include unexistent messages.
|
||||
|
||||
2013-07-02 Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-start.el (gnus-clean-old-newsrc):
|
||||
Remove totally bogus `unexists' entries.
|
||||
(gnus-clean-old-newsrc): Fix last checkin.
|
||||
|
||||
* nnimap.el (nnimap-update-info):
|
||||
None of the articles below the active low-water mark exist.
|
||||
|
||||
2013-07-02 Katsumi Yamaoka <yamaoka@jpl.org>
|
||||
|
||||
* nnimap.el (gnus-refer-thread-use-nnir): Silence the byte compiler.
|
||||
|
||||
2013-07-02 Sergio Martinez <samf0xb58@gmail.com> (tiny change)
|
||||
|
||||
* nnimap.el (nnimap-request-scan):
|
||||
Allow `nnimap-inbox' to be a list of inboxes.
|
||||
|
||||
2013-07-02 Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-group.el (gnus-group-expire-articles-1):
|
||||
Don't try to expire messages that don't exist.
|
||||
|
||||
* gnus-sum.el (gnus-summary-expire-articles): Ditto.
|
||||
|
||||
2013-07-02 Lars Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-start.el (gnus-clean-old-newsrc): Allow a FORCE parameter.
|
||||
|
||||
2013-07-02 Lars Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-start.el (gnus-clean-old-newsrc):
|
||||
Delete `unexist' from pre-Ma Gnus 0.3.
|
||||
|
||||
2013-07-02 Lars Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-sum.el (gnus-summary-local-variables):
|
||||
Make `gnus-newsgroup-unexist' into a local variable.
|
||||
|
||||
2013-07-02 Lars Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-sum.el (gnus-adjust-marked-articles):
|
||||
Add to `gnus-newsgroup-unexist'.
|
||||
|
||||
* gnus.el (gnus-article-mark-lists):
|
||||
Add `unexist' to the list of marks.
|
||||
(gnus-article-special-mark-lists):
|
||||
Put the `unexist' in the special marks list instead.
|
||||
|
||||
* gnus-sum.el (gnus-articles-to-read): Don't include unexisting
|
||||
articles in the list of articles to be selected.
|
||||
|
||||
* nnimap.el (nnimap-retrieve-group-data-early):
|
||||
Query for unexisting articles.
|
||||
(nnimap-update-info): Keep track of unexisting articles.
|
||||
(nnimap-update-qresync-info): Ditto.
|
||||
|
||||
2013-07-02 Lars Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
* gnus-start.el (gnus-clean-old-newsrc): New function.
|
||||
(gnus-read-newsrc-file): Use it.
|
||||
|
||||
2013-07-02 Daiki Ueno <ueno@gnu.org>
|
||||
|
||||
* mml2015.el (mml2015-epg-key-image): Use 'gnus-create-image' instead
|
||||
|
|
|
@ -3654,6 +3654,10 @@ Uses the process/prefix convention."
|
|||
(expirable (if (gnus-group-total-expirable-p group)
|
||||
(cons nil (gnus-list-of-read-articles group))
|
||||
(assq 'expire (gnus-info-marks info))))
|
||||
(articles-to-expire
|
||||
(gnus-list-range-difference
|
||||
(gnus-uncompress-sequence (cdr expirable))
|
||||
(cdr (assq 'unexist (gnus-info-marks info)))))
|
||||
(expiry-wait (gnus-group-find-parameter group 'expiry-wait))
|
||||
(nnmail-expiry-target
|
||||
(or (gnus-group-find-parameter group 'expiry-target)
|
||||
|
@ -3668,11 +3672,9 @@ Uses the process/prefix convention."
|
|||
;; parameter.
|
||||
(let ((nnmail-expiry-wait-function nil)
|
||||
(nnmail-expiry-wait expiry-wait))
|
||||
(gnus-request-expire-articles
|
||||
(gnus-uncompress-sequence (cdr expirable)) group))
|
||||
(gnus-request-expire-articles articles-to-expire group))
|
||||
;; Just expire using the normal expiry values.
|
||||
(gnus-request-expire-articles
|
||||
(gnus-uncompress-sequence (cdr expirable)) group))))
|
||||
(gnus-request-expire-articles articles-to-expire group))))
|
||||
(gnus-close-group group))
|
||||
(gnus-message 6 "Expiring articles in %s...done"
|
||||
(gnus-group-decoded-name group))
|
||||
|
|
|
@ -2301,7 +2301,27 @@ If FORCE is non-nil, the .newsrc file is read."
|
|||
(gnus-message 5 "Reading %s...done" newsrc-file)))
|
||||
|
||||
;; Convert old to new.
|
||||
(gnus-convert-old-newsrc))))
|
||||
(gnus-convert-old-newsrc)
|
||||
(gnus-clean-old-newsrc))))
|
||||
|
||||
(defun gnus-clean-old-newsrc (&optional force)
|
||||
(when gnus-newsrc-file-version
|
||||
;; Remove totally bogus `unexists' entries. The name is
|
||||
;; `unexist'.
|
||||
(dolist (info (cdr gnus-newsrc-alist))
|
||||
(let ((exist (assoc 'unexists (gnus-info-marks info))))
|
||||
(when exist
|
||||
(gnus-info-set-marks
|
||||
info (delete exist (gnus-info-marks info))))))
|
||||
(when (or force
|
||||
(< (gnus-continuum-version gnus-newsrc-file-version)
|
||||
(gnus-continuum-version "Ma Gnus v0.03")))
|
||||
;; Remove old `exist' marks from old nnimap groups.
|
||||
(dolist (info (cdr gnus-newsrc-alist))
|
||||
(let ((exist (assoc 'unexist (gnus-info-marks info))))
|
||||
(when exist
|
||||
(gnus-info-set-marks
|
||||
info (delete exist (gnus-info-marks info)))))))))
|
||||
|
||||
(defun gnus-convert-old-newsrc ()
|
||||
"Convert old newsrc formats into the current format, if needed."
|
||||
|
|
|
@ -1524,6 +1524,9 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
|
|||
(defvar gnus-newsgroup-seen nil
|
||||
"Range of seen articles in the current newsgroup.")
|
||||
|
||||
(defvar gnus-newsgroup-unexist nil
|
||||
"Range of unexistent articles in the current newsgroup.")
|
||||
|
||||
(defvar gnus-newsgroup-articles nil
|
||||
"List of articles in the current newsgroup.")
|
||||
|
||||
|
@ -1571,6 +1574,7 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
|
|||
gnus-newsgroup-killed
|
||||
gnus-newsgroup-unseen
|
||||
gnus-newsgroup-seen
|
||||
gnus-newsgroup-unexist
|
||||
gnus-newsgroup-cached
|
||||
gnus-newsgroup-downloadable
|
||||
gnus-newsgroup-undownloaded
|
||||
|
@ -5789,6 +5793,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
|||
"Find out what articles the user wants to read."
|
||||
(let* ((only-read-p t)
|
||||
(articles
|
||||
(gnus-list-range-difference
|
||||
;; Select all articles if `read-all' is non-nil, or if there
|
||||
;; are no unread articles.
|
||||
(if (or read-all
|
||||
|
@ -5815,7 +5820,8 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
|||
(setq only-read-p nil)
|
||||
(gnus-sorted-nunion
|
||||
(gnus-sorted-union gnus-newsgroup-dormant gnus-newsgroup-marked)
|
||||
gnus-newsgroup-unreads)))
|
||||
gnus-newsgroup-unreads))
|
||||
(cdr (assq 'unexist (gnus-info-marks (gnus-get-info group))))))
|
||||
(scored-list (gnus-killed-articles gnus-newsgroup-killed articles))
|
||||
(scored (length scored-list))
|
||||
(number (length articles))
|
||||
|
@ -5985,7 +5991,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
|||
(and (numberp (car articles))
|
||||
(> min (car articles)))))
|
||||
(pop articles))
|
||||
(set var articles))))))))
|
||||
(set var articles))
|
||||
((eq mark 'unexist)
|
||||
(set var (cdr marks)))))))))
|
||||
|
||||
(defun gnus-update-missing-marks (missing)
|
||||
"Go through the list of MISSING articles and remove them from the mark lists."
|
||||
|
@ -6061,7 +6069,8 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
|||
(gnus-active gnus-newsgroup-name) del))
|
||||
(push (list del 'del (list (cdr type))) delta-marks))))
|
||||
|
||||
(when list
|
||||
(when (or list
|
||||
(eq (cdr type) 'unexist))
|
||||
(push (cons (cdr type) list) newmarked)))
|
||||
|
||||
(when delta-marks
|
||||
|
@ -10305,16 +10314,19 @@ This will be the case if the article has both been mailed and posted."
|
|||
'request-expire-articles gnus-newsgroup-name))
|
||||
;; This backend supports expiry.
|
||||
(let* ((total (gnus-group-total-expirable-p gnus-newsgroup-name))
|
||||
(expirable (if total
|
||||
(progn
|
||||
;; We need to update the info for
|
||||
;; this group for `gnus-list-of-read-articles'
|
||||
;; to give us the right answer.
|
||||
(gnus-run-hooks 'gnus-exit-group-hook)
|
||||
(gnus-summary-update-info)
|
||||
(gnus-list-of-read-articles gnus-newsgroup-name))
|
||||
(setq gnus-newsgroup-expirable
|
||||
(sort gnus-newsgroup-expirable '<))))
|
||||
(expirable
|
||||
(gnus-list-range-difference
|
||||
(if total
|
||||
(progn
|
||||
;; We need to update the info for
|
||||
;; this group for `gnus-list-of-read-articles'
|
||||
;; to give us the right answer.
|
||||
(gnus-run-hooks 'gnus-exit-group-hook)
|
||||
(gnus-summary-update-info)
|
||||
(gnus-list-of-read-articles gnus-newsgroup-name))
|
||||
(setq gnus-newsgroup-expirable
|
||||
(sort gnus-newsgroup-expirable '<)))
|
||||
gnus-newsgroup-unexist))
|
||||
(expiry-wait (if now 'immediate
|
||||
(gnus-group-find-parameter
|
||||
gnus-newsgroup-name 'expiry-wait)))
|
||||
|
@ -12847,7 +12859,9 @@ If ALL is a number, fetch this number of articles."
|
|||
;; Some nntp servers lie about their active range. When
|
||||
;; this happens, the active range can be in the millions.
|
||||
;; Use a compressed range to avoid creating a huge list.
|
||||
(gnus-range-difference (list gnus-newsgroup-active) old))
|
||||
(gnus-range-difference
|
||||
(gnus-range-difference (list gnus-newsgroup-active) old)
|
||||
gnus-newsgroup-unexist))
|
||||
(setq len (gnus-range-length older))
|
||||
(cond
|
||||
((null older) nil)
|
||||
|
|
|
@ -2636,10 +2636,11 @@ a string, be sure to use a valid format, see RFC 2616."
|
|||
(scored . score) (saved . save)
|
||||
(cached . cache) (downloadable . download)
|
||||
(unsendable . unsend) (forwarded . forward)
|
||||
(seen . seen)))
|
||||
(seen . seen) (unexist . unexist)))
|
||||
|
||||
(defconst gnus-article-special-mark-lists
|
||||
'((seen range)
|
||||
(unexist range)
|
||||
(killed range)
|
||||
(bookmark tuple)
|
||||
(uid tuple)
|
||||
|
@ -2654,7 +2655,7 @@ a string, be sure to use a valid format, see RFC 2616."
|
|||
;; `score' is not a proper mark
|
||||
;; `bookmark': don't propagated it, or fix the bug in update-mark.
|
||||
(defconst gnus-article-unpropagated-mark-lists
|
||||
'(seen cache download unsend score bookmark)
|
||||
'(seen cache download unsend score bookmark unexist)
|
||||
"Marks that shouldn't be propagated to back ends.
|
||||
Typical marks are those that make no sense in a standalone back end,
|
||||
such as a mark that says whether an article is stored in the cache
|
||||
|
|
|
@ -82,7 +82,8 @@ back on `network'.")
|
|||
|
||||
(defvoo nnimap-inbox nil
|
||||
"The mail box where incoming mail arrives and should be split out of.
|
||||
For example, \"INBOX\".")
|
||||
This can be a string or a list of strings
|
||||
For example, \"INBOX\" or (\"INBOX\" \"SENT\").")
|
||||
|
||||
(defvoo nnimap-split-methods nil
|
||||
"How mail is split.
|
||||
|
@ -123,6 +124,16 @@ will fetch all parts that have types that match that string. A
|
|||
likely value would be \"text/\" to automatically fetch all
|
||||
textual parts.")
|
||||
|
||||
(defgroup nnimap nil
|
||||
"IMAP for Gnus."
|
||||
:group 'gnus)
|
||||
|
||||
(defcustom nnimap-request-articles-find-limit nil
|
||||
"Limit the number of articles to look for after moving an article."
|
||||
:type 'integer
|
||||
:version "24.3"
|
||||
:group 'nnimap)
|
||||
|
||||
(defvar nnimap-process nil)
|
||||
|
||||
(defvar nnimap-status-string "")
|
||||
|
@ -173,7 +184,7 @@ textual parts.")
|
|||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(erase-buffer)
|
||||
(when (nnimap-possibly-change-group group server)
|
||||
(when (nnimap-change-group group server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(erase-buffer)
|
||||
(nnimap-wait-for-response
|
||||
|
@ -567,10 +578,10 @@ textual parts.")
|
|||
(when group
|
||||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(let ((result (nnimap-possibly-change-group group server))
|
||||
(let ((result (nnimap-change-group group server))
|
||||
parts structure)
|
||||
(when (stringp article)
|
||||
(setq article (nnimap-find-article-by-message-id group article)))
|
||||
(setq article (nnimap-find-article-by-message-id group server article)))
|
||||
(when (and result
|
||||
article)
|
||||
(erase-buffer)
|
||||
|
@ -599,10 +610,10 @@ textual parts.")
|
|||
(deffoo nnimap-request-head (article &optional group server to-buffer)
|
||||
(when group
|
||||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(when (nnimap-possibly-change-group group server)
|
||||
(when (nnimap-change-group group server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(when (stringp article)
|
||||
(setq article (nnimap-find-article-by-message-id group article)))
|
||||
(setq article (nnimap-find-article-by-message-id group server article)))
|
||||
(if (null article)
|
||||
nil
|
||||
(nnimap-get-whole-article
|
||||
|
@ -751,7 +762,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-group (group &optional server dont-check info)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(let ((result (nnimap-possibly-change-group
|
||||
(let ((result (nnimap-change-group
|
||||
;; Don't SELECT the group if we're going to select it
|
||||
;; later, anyway.
|
||||
(if (and (not dont-check)
|
||||
|
@ -801,19 +812,19 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-create-group (group &optional server args)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(car (nnimap-command "CREATE %S" (utf7-encode group t))))))
|
||||
|
||||
(deffoo nnimap-request-delete-group (group &optional force server)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(car (nnimap-command "DELETE %S" (utf7-encode group t))))))
|
||||
|
||||
(deffoo nnimap-request-rename-group (group new-name &optional server)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(nnimap-unselect-group)
|
||||
(car (nnimap-command "RENAME %S %S"
|
||||
|
@ -828,7 +839,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-expunge-group (group &optional server)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group group server)
|
||||
(when (nnimap-change-group group server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(car (nnimap-command "EXPUNGE")))))
|
||||
|
||||
|
@ -856,6 +867,8 @@ textual parts.")
|
|||
(deffoo nnimap-request-move-article (article group server accept-form
|
||||
&optional last internal-move-group)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when internal-move-group
|
||||
(setq internal-move-group (nnimap-decode-gnus-group internal-move-group)))
|
||||
(with-temp-buffer
|
||||
(mm-disable-multibyte)
|
||||
(when (funcall (if internal-move-group
|
||||
|
@ -876,11 +889,12 @@ textual parts.")
|
|||
(cons internal-move-group
|
||||
(or (nnimap-find-uid-response "COPYUID" (cadr result))
|
||||
(nnimap-find-article-by-message-id
|
||||
internal-move-group message-id)))))
|
||||
internal-move-group server message-id
|
||||
nnimap-request-articles-find-limit)))))
|
||||
;; Move the article to a different method.
|
||||
(let ((result (eval accept-form)))
|
||||
(when result
|
||||
(nnimap-possibly-change-group group server)
|
||||
(nnimap-change-group group server)
|
||||
(nnimap-delete-article article)
|
||||
result)))))))
|
||||
|
||||
|
@ -889,7 +903,7 @@ textual parts.")
|
|||
(cond
|
||||
((null articles)
|
||||
nil)
|
||||
((not (nnimap-possibly-change-group group server))
|
||||
((not (nnimap-change-group group server))
|
||||
articles)
|
||||
((and force
|
||||
(eq nnmail-expiry-target 'delete))
|
||||
|
@ -926,7 +940,7 @@ textual parts.")
|
|||
(gnus-server-equal (gnus-group-method nnmail-expiry-target)
|
||||
(gnus-server-to-method
|
||||
(format "nnimap:%s" server))))
|
||||
(and (nnimap-possibly-change-group group server)
|
||||
(and (nnimap-change-group group server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(nnheader-message 7 "Expiring articles from %s: %s" group articles)
|
||||
(nnimap-command
|
||||
|
@ -956,7 +970,7 @@ textual parts.")
|
|||
(when target
|
||||
(push article deleted-articles))))))))
|
||||
;; Change back to the current group again.
|
||||
(nnimap-possibly-change-group group server)
|
||||
(nnimap-change-group group server)
|
||||
(setq deleted-articles (nreverse deleted-articles))
|
||||
(nnimap-delete-article (gnus-compress-sequence deleted-articles))
|
||||
deleted-articles))
|
||||
|
@ -978,23 +992,37 @@ textual parts.")
|
|||
(cdr (assoc "SEARCH" (cdr result))))))))))
|
||||
|
||||
|
||||
(defun nnimap-find-article-by-message-id (group message-id)
|
||||
(defun nnimap-find-article-by-message-id (group server message-id
|
||||
&optional limit)
|
||||
"Search for message with MESSAGE-ID in GROUP from SERVER.
|
||||
If LIMIT, first try to limit the search to the N last articles."
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(erase-buffer)
|
||||
(unless (or (not group) (equal group (nnimap-group nnimap-object)))
|
||||
(setf (nnimap-group nnimap-object) nil)
|
||||
(setf (nnimap-examined nnimap-object) group)
|
||||
(nnimap-send-command "EXAMINE %S" (utf7-encode group t)))
|
||||
(let ((sequence
|
||||
(nnimap-send-command "UID SEARCH HEADER Message-Id %S" message-id))
|
||||
article result)
|
||||
(setq result (nnimap-wait-for-response sequence))
|
||||
(when (and result
|
||||
(car (setq result (nnimap-parse-response))))
|
||||
;; Select the last instance of the message in the group.
|
||||
(and (setq article
|
||||
(car (last (cdr (assoc "SEARCH" (cdr result))))))
|
||||
(string-to-number article))))))
|
||||
(let* ((change-group-result (nnimap-change-group group server nil t))
|
||||
(number-of-article
|
||||
(and (listp change-group-result)
|
||||
(catch 'found
|
||||
(dolist (result (cdr change-group-result))
|
||||
(when (equal "EXISTS" (cadr result))
|
||||
(throw 'found (car result)))))))
|
||||
(sequence
|
||||
(nnimap-send-command
|
||||
"UID SEARCH%s HEADER Message-Id %S"
|
||||
(if (and limit number-of-article)
|
||||
;; The -1 is because IMAP message
|
||||
;; numbers are one-based rather than
|
||||
;; zero-based.
|
||||
(format " %s:*" (- (string-to-number number-of-article)
|
||||
limit -1))
|
||||
"")
|
||||
message-id)))
|
||||
(when (nnimap-wait-for-response sequence)
|
||||
(let ((article (car (last (cdr (assoc "SEARCH"
|
||||
(nnimap-parse-response)))))))
|
||||
(if article
|
||||
(string-to-number article)
|
||||
(when (and limit number-of-article)
|
||||
(nnimap-find-article-by-message-id group server message-id))))))))
|
||||
|
||||
(defun nnimap-delete-article (articles)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
|
@ -1015,11 +1043,14 @@ textual parts.")
|
|||
(deffoo nnimap-request-scan (&optional group server)
|
||||
(when group
|
||||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(when (and (nnimap-possibly-change-group nil server)
|
||||
(when (and (nnimap-change-group nil server)
|
||||
nnimap-inbox
|
||||
nnimap-split-methods)
|
||||
(nnheader-message 7 "nnimap %s splitting mail..." server)
|
||||
(nnimap-split-incoming-mail)
|
||||
(if (listp nnimap-inbox)
|
||||
(dolist (nnimap-inbox nnimap-inbox)
|
||||
(nnimap-split-incoming-mail))
|
||||
(nnimap-split-incoming-mail))
|
||||
(nnheader-message 7 "nnimap %s splitting mail...done" server)))
|
||||
|
||||
(defun nnimap-marks-to-flags (marks)
|
||||
|
@ -1031,7 +1062,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-update-group-status (group status &optional server)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(let ((command (assoc
|
||||
status
|
||||
'((subscribe "SUBSCRIBE")
|
||||
|
@ -1042,7 +1073,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-set-mark (group actions &optional server)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group group server)
|
||||
(when (nnimap-change-group group server)
|
||||
(let (sequence)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(erase-buffer)
|
||||
|
@ -1067,7 +1098,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-request-accept-article (group &optional server last)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(nnmail-check-syntax)
|
||||
(let ((message-id (message-field-value "message-id"))
|
||||
sequence message)
|
||||
|
@ -1099,7 +1130,8 @@ textual parts.")
|
|||
(cons group
|
||||
(or (nnimap-find-uid-response "APPENDUID" (car result))
|
||||
(nnimap-find-article-by-message-id
|
||||
group message-id))))))))))
|
||||
group server message-id
|
||||
nnimap-request-articles-find-limit))))))))))
|
||||
|
||||
(defun nnimap-process-quirk (greeting-match type data)
|
||||
(when (and (nnimap-greeting nnimap-object)
|
||||
|
@ -1145,7 +1177,7 @@ textual parts.")
|
|||
(deffoo nnimap-request-replace-article (article group buffer)
|
||||
(setq group (nnimap-decode-gnus-group group))
|
||||
(let (group-art)
|
||||
(when (and (nnimap-possibly-change-group group nil)
|
||||
(when (and (nnimap-change-group group)
|
||||
;; Put the article into the group.
|
||||
(with-current-buffer buffer
|
||||
(setq group-art
|
||||
|
@ -1180,8 +1212,17 @@ textual parts.")
|
|||
groups))))
|
||||
(nreverse groups)))
|
||||
|
||||
(defun nnimap-get-responses (sequences)
|
||||
(let (responses)
|
||||
(dolist (sequence sequences)
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward (format "^%d " sequence) nil t)
|
||||
(push (list sequence (nnimap-parse-response))
|
||||
responses)))
|
||||
responses))
|
||||
|
||||
(deffoo nnimap-request-list (&optional server)
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(erase-buffer)
|
||||
(let ((groups
|
||||
|
@ -1228,7 +1269,7 @@ textual parts.")
|
|||
t)))))
|
||||
|
||||
(deffoo nnimap-request-newgroups (date &optional server)
|
||||
(when (nnimap-possibly-change-group nil server)
|
||||
(when (nnimap-change-group nil server)
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(erase-buffer)
|
||||
(dolist (group (with-current-buffer (nnimap-buffer)
|
||||
|
@ -1239,14 +1280,15 @@ textual parts.")
|
|||
t)))
|
||||
|
||||
(deffoo nnimap-retrieve-group-data-early (server infos)
|
||||
(when (and (nnimap-possibly-change-group nil server)
|
||||
(when (and (nnimap-change-group nil server)
|
||||
infos)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(erase-buffer)
|
||||
(setf (nnimap-group nnimap-object) nil)
|
||||
(setf (nnimap-initial-resync nnimap-object) 0)
|
||||
(let ((qresyncp (nnimap-capability "QRESYNC"))
|
||||
params groups sequences active uidvalidity modseq group)
|
||||
params groups sequences active uidvalidity modseq group
|
||||
unexist)
|
||||
;; Go through the infos and gather the data needed to know
|
||||
;; what and how to request the data.
|
||||
(dolist (info infos)
|
||||
|
@ -1254,13 +1296,15 @@ textual parts.")
|
|||
group (nnimap-decode-gnus-group
|
||||
(gnus-group-real-name (gnus-info-group info)))
|
||||
active (cdr (assq 'active params))
|
||||
unexist (assq 'unexist (gnus-info-marks info))
|
||||
uidvalidity (cdr (assq 'uidvalidity params))
|
||||
modseq (cdr (assq 'modseq params)))
|
||||
(setf (nnimap-examined nnimap-object) group)
|
||||
(if (and qresyncp
|
||||
uidvalidity
|
||||
active
|
||||
modseq)
|
||||
modseq
|
||||
unexist)
|
||||
(push
|
||||
(list (nnimap-send-command "EXAMINE %S (%s (%s %s))"
|
||||
(utf7-encode group t)
|
||||
|
@ -1279,11 +1323,10 @@ textual parts.")
|
|||
;; is read-only or not.
|
||||
"SELECT"))
|
||||
start)
|
||||
(if (and active uidvalidity)
|
||||
(if (and active uidvalidity unexist)
|
||||
;; Fetch the last 100 flags.
|
||||
(setq start (max 1 (- (cdr active) 100)))
|
||||
(setf (nnimap-initial-resync nnimap-object)
|
||||
(1+ (nnimap-initial-resync nnimap-object)))
|
||||
(incf (nnimap-initial-resync nnimap-object))
|
||||
(setq start 1))
|
||||
(push (list (nnimap-send-command "%s %S" command
|
||||
(utf7-encode group t))
|
||||
|
@ -1303,7 +1346,7 @@ textual parts.")
|
|||
|
||||
(deffoo nnimap-finish-retrieve-group-infos (server infos sequences)
|
||||
(when (and sequences
|
||||
(nnimap-possibly-change-group nil server t)
|
||||
(nnimap-change-group nil server t)
|
||||
;; Check that the process is still alive.
|
||||
(get-buffer-process (nnimap-buffer))
|
||||
(memq (process-status (get-buffer-process (nnimap-buffer)))
|
||||
|
@ -1462,6 +1505,25 @@ textual parts.")
|
|||
(setq new-marks (gnus-range-nconcat old-marks new-marks)))
|
||||
(when new-marks
|
||||
(push (cons (car type) new-marks) marks)))))
|
||||
;; Keep track of non-existing articles.
|
||||
(let* ((old-unexists (assq 'unexist marks))
|
||||
(active (gnus-active group))
|
||||
(unexists
|
||||
(if completep
|
||||
(gnus-range-difference
|
||||
active
|
||||
(gnus-compress-sequence existing))
|
||||
(gnus-add-to-range
|
||||
(cdr old-unexists)
|
||||
(gnus-list-range-difference
|
||||
existing (gnus-active group))))))
|
||||
(when (> (car active) 1)
|
||||
(setq unexists (gnus-range-add
|
||||
(cons 1 (1- (car active)))
|
||||
unexists)))
|
||||
(if old-unexists
|
||||
(setcdr old-unexists unexists)
|
||||
(push (cons 'unexist unexists) marks)))
|
||||
(gnus-info-set-marks info marks t))))
|
||||
;; Tell Gnus whether there are any \Recent messages in any of
|
||||
;; the groups.
|
||||
|
@ -1505,6 +1567,14 @@ textual parts.")
|
|||
(gnus-sorted-complement existing new-marks))))
|
||||
(when ticks
|
||||
(push (cons (car type) ticks) marks)))
|
||||
(gnus-info-set-marks info marks t))
|
||||
;; Add vanished to the list of unexisting articles.
|
||||
(when vanished
|
||||
(let* ((old-unexists (assq 'unexist marks))
|
||||
(unexists (gnus-range-add (cdr old-unexists) vanished)))
|
||||
(if old-unexists
|
||||
(setcdr old-unexists unexists)
|
||||
(push (cons 'unexist unexists) marks)))
|
||||
(gnus-info-set-marks info marks t))))
|
||||
|
||||
(defun nnimap-imap-ranges-to-gnus-ranges (irange)
|
||||
|
@ -1642,7 +1712,7 @@ textual parts.")
|
|||
(setq nnimap-status-string "Read-only server")
|
||||
nil)
|
||||
|
||||
(defvar gnus-refer-thread-use-nnir) ; gnus-sum
|
||||
(defvar gnus-refer-thread-use-nnir) ;; gnus-sum.el
|
||||
(declare-function gnus-fetch-headers "gnus-sum"
|
||||
(articles &optional limit force-new dependencies))
|
||||
|
||||
|
@ -1653,7 +1723,7 @@ textual parts.")
|
|||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(if gnus-refer-thread-use-nnir
|
||||
(nnir-search-thread header)
|
||||
(when (nnimap-possibly-change-group group server)
|
||||
(when (nnimap-change-group group server)
|
||||
(let* ((cmd (nnimap-make-thread-query header))
|
||||
(result (with-current-buffer (nnimap-buffer)
|
||||
(nnimap-command "UID SEARCH %s" cmd))))
|
||||
|
@ -1664,7 +1734,14 @@ textual parts.")
|
|||
(cdr (assoc "SEARCH" (cdr result))))))
|
||||
nil t))))))
|
||||
|
||||
(defun nnimap-possibly-change-group (group server &optional no-reconnect)
|
||||
(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
|
||||
to reconnect, unless NO-RECONNECT is set to t. Return nil if
|
||||
unsuccessful in connecting.
|
||||
If GROUP is nil, return t.
|
||||
If READ-ONLY is set, send EXAMINE rather than SELECT to the server.
|
||||
Return the server's response to the SELECT or EXAMINE command."
|
||||
(let ((open-result t))
|
||||
(when (and server
|
||||
(not (nnimap-server-opened server)))
|
||||
|
@ -1676,13 +1753,15 @@ textual parts.")
|
|||
t)
|
||||
(t
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(if (equal group (nnimap-group nnimap-object))
|
||||
t
|
||||
(let ((result (nnimap-command "SELECT %S" (utf7-encode group t))))
|
||||
(when (car result)
|
||||
(setf (nnimap-group nnimap-object) group
|
||||
(nnimap-select-result nnimap-object) result)
|
||||
result))))))))
|
||||
(let ((result (nnimap-command "%s %S"
|
||||
(if read-only
|
||||
"EXAMINE"
|
||||
"SELECT")
|
||||
(utf7-encode group t))))
|
||||
(when (car result)
|
||||
(setf (nnimap-group nnimap-object) group
|
||||
(nnimap-select-result nnimap-object) result)
|
||||
result)))))))
|
||||
|
||||
(defun nnimap-find-connection (buffer)
|
||||
"Find the connection delivering to BUFFER."
|
||||
|
@ -1718,15 +1797,24 @@ textual parts.")
|
|||
(defvar nnimap-record-commands nil
|
||||
"If non-nil, log commands to the \"*imap log*\" buffer.")
|
||||
|
||||
(defun nnimap-log-buffer ()
|
||||
(let ((name "*imap log*"))
|
||||
(or (get-buffer name)
|
||||
(with-current-buffer (get-buffer-create name)
|
||||
(when (boundp 'window-point-insertion-type)
|
||||
(make-local-variable 'window-point-insertion-type)
|
||||
(setq window-point-insertion-type t))
|
||||
(current-buffer)))))
|
||||
|
||||
(defun nnimap-log-command (command)
|
||||
(when nnimap-record-commands
|
||||
(with-current-buffer (get-buffer-create "*imap log*")
|
||||
(with-current-buffer (nnimap-log-buffer)
|
||||
(goto-char (point-max))
|
||||
(insert (format-time-string "%H:%M:%S")
|
||||
" [" nnimap-address "] "
|
||||
(if nnimap-inhibit-logging
|
||||
"(inhibited)\n"
|
||||
command))))
|
||||
" [" nnimap-address "] "
|
||||
(if nnimap-inhibit-logging
|
||||
"(inhibited)\n"
|
||||
command))))
|
||||
command)
|
||||
|
||||
(defun nnimap-command (&rest args)
|
||||
|
@ -1865,15 +1953,6 @@ textual parts.")
|
|||
(forward-line 1)))
|
||||
(buffer-substring (point) end))))
|
||||
|
||||
(defun nnimap-get-responses (sequences)
|
||||
(let (responses)
|
||||
(dolist (sequence sequences)
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward (format "^%d " sequence) nil t)
|
||||
(push (list sequence (nnimap-parse-response))
|
||||
responses)))
|
||||
responses))
|
||||
|
||||
(defvar nnimap-incoming-split-list nil)
|
||||
|
||||
(defun nnimap-fetch-inbox (articles)
|
||||
|
|
|
@ -288,7 +288,7 @@ is `(valuefunc member)'."
|
|||
(eval-when-compile
|
||||
(autoload 'nnimap-buffer "nnimap")
|
||||
(autoload 'nnimap-command "nnimap")
|
||||
(autoload 'nnimap-possibly-change-group "nnimap")
|
||||
(autoload 'nnimap-change-group "nnimap")
|
||||
(autoload 'nnimap-make-thread-query "nnimap")
|
||||
(autoload 'gnus-registry-action "gnus-registry")
|
||||
(autoload 'gnus-registry-get-id-key "gnus-registry")
|
||||
|
@ -973,7 +973,7 @@ details on the language and supported extensions."
|
|||
#'(lambda (group)
|
||||
(let (artlist)
|
||||
(condition-case ()
|
||||
(when (nnimap-possibly-change-group
|
||||
(when (nnimap-change-group
|
||||
(gnus-group-short-name group) server)
|
||||
(with-current-buffer (nnimap-buffer)
|
||||
(message "Searching %s..." group)
|
||||
|
|
Loading…
Add table
Reference in a new issue