gnus-int.el 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. ;;; gnus-int.el --- backend interface functions for Gnus
  2. ;; Copyright (C) 1996-2012 Free Software Foundation, Inc.
  3. ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
  4. ;; Keywords: news
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;; Code:
  18. (eval-when-compile (require 'cl))
  19. (require 'gnus)
  20. (require 'message)
  21. (require 'gnus-range)
  22. (autoload 'gnus-run-hook-with-args "gnus-util")
  23. (autoload 'gnus-agent-expire "gnus-agent")
  24. (autoload 'gnus-agent-regenerate-group "gnus-agent")
  25. (autoload 'gnus-agent-read-servers-validate-native "gnus-agent")
  26. (autoload 'gnus-agent-possibly-synchronize-flags-server "gnus-agent")
  27. (defcustom gnus-open-server-hook nil
  28. "Hook called just before opening connection to the news server."
  29. :group 'gnus-start
  30. :type 'hook)
  31. (defcustom gnus-after-set-mark-hook nil
  32. "Hook called just after marks are set in a group."
  33. :version "24.1"
  34. :group 'gnus-start
  35. :type 'hook)
  36. (defcustom gnus-before-update-mark-hook nil
  37. "Hook called just before marks are updated in a group."
  38. :version "24.1"
  39. :group 'gnus-start
  40. :type 'hook)
  41. (defcustom gnus-server-unopen-status nil
  42. "The default status if the server is not able to open.
  43. If the server is covered by Gnus agent, the possible values are
  44. `denied', set the server denied; `offline', set the server offline;
  45. nil, ask user. If the server is not covered by Gnus agent, set the
  46. server denied."
  47. :version "22.1"
  48. :group 'gnus-start
  49. :type '(choice (const :tag "Ask" nil)
  50. (const :tag "Deny server" denied)
  51. (const :tag "Unplug Agent" offline)))
  52. (defcustom gnus-nntp-server nil
  53. "The name of the host running the NNTP server."
  54. :group 'gnus-server
  55. :type '(choice (const :tag "disable" nil)
  56. string))
  57. (make-obsolete-variable 'gnus-nntp-server 'gnus-select-method "24.1")
  58. (defvar gnus-internal-registry-spool-current-method nil
  59. "The current method, for the registry.")
  60. (defun gnus-server-opened (gnus-command-method)
  61. "Check whether a connection to GNUS-COMMAND-METHOD has been opened."
  62. (unless (eq (gnus-server-status gnus-command-method)
  63. 'denied)
  64. (when (stringp gnus-command-method)
  65. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  66. (funcall (inline (gnus-get-function gnus-command-method 'server-opened))
  67. (nth 1 gnus-command-method))))
  68. (defun gnus-status-message (gnus-command-method)
  69. "Return the status message from GNUS-COMMAND-METHOD.
  70. If GNUS-COMMAND-METHOD is a string, it is interpreted as a group
  71. name. The method this group uses will be queried."
  72. (let ((gnus-command-method
  73. (if (stringp gnus-command-method)
  74. (gnus-find-method-for-group gnus-command-method)
  75. gnus-command-method)))
  76. (funcall (gnus-get-function gnus-command-method 'status-message)
  77. (nth 1 gnus-command-method))))
  78. ;;;
  79. ;;; Server Communication
  80. ;;;
  81. (defun gnus-start-news-server (&optional confirm)
  82. "Open a method for getting news.
  83. If CONFIRM is non-nil, the user will be asked for an NNTP server."
  84. (let (how)
  85. (if gnus-current-select-method
  86. ;; Stream is already opened.
  87. nil
  88. ;; Open NNTP server.
  89. (when confirm
  90. ;; Read server name with completion.
  91. (setq gnus-nntp-server
  92. (gnus-completing-read "NNTP server"
  93. (cons gnus-nntp-server
  94. gnus-secondary-servers)
  95. nil gnus-nntp-server)))
  96. (when (and gnus-nntp-server
  97. (stringp gnus-nntp-server)
  98. (not (string= gnus-nntp-server "")))
  99. (setq gnus-select-method
  100. (cond ((or (string= gnus-nntp-server "")
  101. (string= gnus-nntp-server "::"))
  102. (list 'nnspool (system-name)))
  103. ((string-match "^:" gnus-nntp-server)
  104. (list 'nnmh gnus-nntp-server
  105. (list 'nnmh-directory
  106. (file-name-as-directory
  107. (expand-file-name
  108. (substring gnus-nntp-server 1) "~/")))
  109. (list 'nnmh-get-new-mail nil)))
  110. (t
  111. (list 'nntp gnus-nntp-server)))))
  112. (setq how (car gnus-select-method))
  113. (cond
  114. ((eq how 'nnspool)
  115. (require 'nnspool)
  116. (gnus-message 5 "Looking up local news spool..."))
  117. ((eq how 'nnmh)
  118. (require 'nnmh)
  119. (gnus-message 5 "Looking up mh spool..."))
  120. (t
  121. (require 'nntp)))
  122. (setq gnus-current-select-method gnus-select-method)
  123. (gnus-run-hooks 'gnus-open-server-hook)
  124. ;; Partially validate agent covered methods now that the
  125. ;; gnus-select-method is known.
  126. (if gnus-agent
  127. ;; NOTE: This is here for one purpose only. By validating
  128. ;; the current select method, it converts the old 5.10.3,
  129. ;; and earlier, format to the current format. That enables
  130. ;; the agent code within gnus-open-server to function
  131. ;; correctly.
  132. (gnus-agent-read-servers-validate-native gnus-select-method))
  133. (or
  134. ;; gnus-open-server-hook might have opened it
  135. (gnus-server-opened gnus-select-method)
  136. (gnus-open-server gnus-select-method)
  137. gnus-batch-mode
  138. (gnus-y-or-n-p
  139. (format
  140. "%s (%s) open error: '%s'. Continue? "
  141. (car gnus-select-method) (cadr gnus-select-method)
  142. (gnus-status-message gnus-select-method)))
  143. (gnus-error 1 "Couldn't open server on %s"
  144. (nth 1 gnus-select-method))))))
  145. (defun gnus-check-group (group)
  146. "Try to make sure that the server where GROUP exists is alive."
  147. (let ((method (gnus-find-method-for-group group)))
  148. (or (gnus-server-opened method)
  149. (gnus-open-server method))))
  150. (defun gnus-check-server (&optional method silent)
  151. "Check whether the connection to METHOD is down.
  152. If METHOD is nil, use `gnus-select-method'.
  153. If it is down, start it up (again)."
  154. (let ((method (or method gnus-select-method))
  155. result)
  156. ;; Transform virtual server names into select methods.
  157. (when (stringp method)
  158. (setq method (gnus-server-to-method method)))
  159. (if (gnus-server-opened method)
  160. ;; The stream is already opened.
  161. t
  162. ;; Open the server.
  163. (unless silent
  164. (gnus-message 5 "Opening %s server%s..." (car method)
  165. (if (equal (nth 1 method) "") ""
  166. (format " on %s" (nth 1 method)))))
  167. (gnus-run-hooks 'gnus-open-server-hook)
  168. (prog1
  169. (setq result (gnus-open-server method))
  170. (unless silent
  171. (gnus-message
  172. (if result 5 3)
  173. "Opening %s server%s...%s" (car method)
  174. (if (equal (nth 1 method) "") ""
  175. (format " on %s" (nth 1 method)))
  176. (if result
  177. "done"
  178. (format "failed: %s"
  179. (nnheader-get-report-string (car method))))))))))
  180. (defun gnus-get-function (method function &optional noerror)
  181. "Return a function symbol based on METHOD and FUNCTION."
  182. ;; Translate server names into methods.
  183. (unless method
  184. (error "Attempted use of a nil select method"))
  185. (when (stringp method)
  186. (setq method (gnus-server-to-method method)))
  187. ;; Check cache of constructed names.
  188. (let* ((method-sym (if gnus-agent
  189. (inline (gnus-agent-get-function method))
  190. (car method)))
  191. (method-fns (get method-sym 'gnus-method-functions))
  192. (func (let ((method-fnlist-elt (assq function method-fns)))
  193. (unless method-fnlist-elt
  194. (setq method-fnlist-elt
  195. (cons function
  196. (intern (format "%s-%s" method-sym function))))
  197. (put method-sym 'gnus-method-functions
  198. (cons method-fnlist-elt method-fns)))
  199. (cdr method-fnlist-elt))))
  200. ;; Maybe complain if there is no function.
  201. (unless (fboundp func)
  202. (unless (car method)
  203. (error "Trying to require a method that doesn't exist"))
  204. (require (car method))
  205. (when (not (fboundp func))
  206. (if noerror
  207. (setq func nil)
  208. (error "No such function: %s" func))))
  209. func))
  210. ;;;
  211. ;;; Interface functions to the backends.
  212. ;;;
  213. (defun gnus-method-denied-p (method)
  214. (eq (nth 1 (assoc method gnus-opened-servers))
  215. 'denied))
  216. (defvar gnus-backend-trace nil)
  217. (defun gnus-open-server (gnus-command-method)
  218. "Open a connection to GNUS-COMMAND-METHOD."
  219. (when (stringp gnus-command-method)
  220. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  221. (when gnus-backend-trace
  222. (with-current-buffer (get-buffer-create "*gnus trace*")
  223. (buffer-disable-undo)
  224. (goto-char (point-max))
  225. (insert (format-time-string "%H:%M:%S")
  226. (format " %S\n" gnus-command-method))))
  227. (let ((elem (assoc gnus-command-method gnus-opened-servers))
  228. (server (gnus-method-to-server-name gnus-command-method)))
  229. ;; If this method was previously denied, we just return nil.
  230. (if (eq (nth 1 elem) 'denied)
  231. (progn
  232. (gnus-message
  233. 1 "Server %s previously determined to be down; not retrying" server)
  234. nil)
  235. ;; Open the server.
  236. (let* ((open-server-function
  237. (gnus-get-function gnus-command-method 'open-server))
  238. (result
  239. (condition-case err
  240. (funcall open-server-function
  241. (nth 1 gnus-command-method)
  242. (nthcdr 2 gnus-command-method))
  243. (error
  244. (gnus-message 1 "Unable to open server %s due to: %s"
  245. server (error-message-string err))
  246. nil)
  247. (quit
  248. (if debug-on-quit
  249. (debug "Quit")
  250. (gnus-message 1 "Quit trying to open server %s" server))
  251. nil)))
  252. open-offline)
  253. ;; If this hasn't been opened before, we add it to the list.
  254. (unless elem
  255. (setq elem (list gnus-command-method nil)
  256. gnus-opened-servers (cons elem gnus-opened-servers)))
  257. ;; Set the status of this server.
  258. (setcar
  259. (cdr elem)
  260. (cond (result
  261. (if (eq open-server-function #'nnagent-open-server)
  262. ;; The agent's backend has a "special" status
  263. 'offline
  264. 'ok))
  265. ((and gnus-agent
  266. (gnus-agent-method-p gnus-command-method))
  267. (cond
  268. (gnus-server-unopen-status
  269. ;; Set the server's status to the unopen
  270. ;; status. If that status is offline,
  271. ;; recurse to open the agent's backend.
  272. (setq open-offline (eq gnus-server-unopen-status 'offline))
  273. gnus-server-unopen-status)
  274. ((not gnus-batch-mode)
  275. (setq open-offline t)
  276. 'offline)
  277. (t
  278. ;; This agentized server was still denied
  279. 'denied)))
  280. (t
  281. ;; This unagentized server must be denied
  282. 'denied)))
  283. ;; NOTE: I MUST set the server's status to offline before this
  284. ;; recursive call as this status will drive the
  285. ;; gnus-get-function (called above) to return the agent's
  286. ;; backend.
  287. (if open-offline
  288. ;; Recursively open this offline server to perform the
  289. ;; open-server function of the agent's backend.
  290. (let ((gnus-server-unopen-status 'denied))
  291. ;; Bind gnus-server-unopen-status to avoid recursively
  292. ;; prompting with "go offline?". This is only a concern
  293. ;; when the agent's backend fails to open the server.
  294. (gnus-open-server gnus-command-method))
  295. (when (and (eq (cadr elem) 'ok) gnus-agent
  296. (gnus-agent-method-p gnus-command-method))
  297. (save-excursion
  298. (gnus-agent-possibly-synchronize-flags-server
  299. gnus-command-method)))
  300. result)))))
  301. (defun gnus-close-server (gnus-command-method)
  302. "Close the connection to GNUS-COMMAND-METHOD."
  303. (when (stringp gnus-command-method)
  304. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  305. (funcall (gnus-get-function gnus-command-method 'close-server)
  306. (nth 1 gnus-command-method)))
  307. (defun gnus-request-list (gnus-command-method)
  308. "Request the active file from GNUS-COMMAND-METHOD."
  309. (when (stringp gnus-command-method)
  310. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  311. (funcall (gnus-get-function gnus-command-method 'request-list)
  312. (nth 1 gnus-command-method)))
  313. (defun gnus-finish-retrieve-group-infos (gnus-command-method infos data)
  314. "Read and update infos from GNUS-COMMAND-METHOD."
  315. (when (stringp gnus-command-method)
  316. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  317. (funcall (gnus-get-function gnus-command-method 'finish-retrieve-group-infos)
  318. (nth 1 gnus-command-method)
  319. infos data))
  320. (defun gnus-retrieve-group-data-early (gnus-command-method infos)
  321. "Start early async retrieval of data from GNUS-COMMAND-METHOD."
  322. (when (stringp gnus-command-method)
  323. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  324. (funcall (gnus-get-function gnus-command-method 'retrieve-group-data-early)
  325. (nth 1 gnus-command-method)
  326. infos))
  327. (defun gnus-request-list-newsgroups (gnus-command-method)
  328. "Request the newsgroups file from GNUS-COMMAND-METHOD."
  329. (when (stringp gnus-command-method)
  330. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  331. (funcall (gnus-get-function gnus-command-method 'request-list-newsgroups)
  332. (nth 1 gnus-command-method)))
  333. (defun gnus-request-newgroups (date gnus-command-method)
  334. "Request all new groups since DATE from GNUS-COMMAND-METHOD."
  335. (when (stringp gnus-command-method)
  336. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  337. (let ((func (gnus-get-function gnus-command-method 'request-newgroups t)))
  338. (when func
  339. (funcall func date (nth 1 gnus-command-method)))))
  340. (defun gnus-request-regenerate (gnus-command-method)
  341. "Request a data generation from GNUS-COMMAND-METHOD."
  342. (when (stringp gnus-command-method)
  343. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  344. (funcall (gnus-get-function gnus-command-method 'request-regenerate)
  345. (nth 1 gnus-command-method)))
  346. (defun gnus-request-compact-group (group)
  347. (let* ((method (gnus-find-method-for-group group))
  348. (gnus-command-method method)
  349. (result
  350. (funcall (gnus-get-function gnus-command-method
  351. 'request-compact-group)
  352. (gnus-group-real-name group)
  353. (nth 1 gnus-command-method) t)))
  354. result))
  355. (defun gnus-request-compact (gnus-command-method)
  356. "Request groups compaction from GNUS-COMMAND-METHOD."
  357. (when (stringp gnus-command-method)
  358. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  359. (funcall (gnus-get-function gnus-command-method 'request-compact)
  360. (nth 1 gnus-command-method)))
  361. (defun gnus-request-group (group &optional dont-check gnus-command-method info)
  362. "Request GROUP. If DONT-CHECK, no information is required."
  363. (let ((gnus-command-method
  364. (or gnus-command-method (inline (gnus-find-method-for-group group)))))
  365. (when (stringp gnus-command-method)
  366. (setq gnus-command-method
  367. (inline (gnus-server-to-method gnus-command-method))))
  368. (funcall (inline (gnus-get-function gnus-command-method 'request-group))
  369. (gnus-group-real-name group) (nth 1 gnus-command-method)
  370. dont-check
  371. info)))
  372. (defun gnus-list-active-group (group)
  373. "Request active information on GROUP."
  374. (let ((gnus-command-method (gnus-find-method-for-group group))
  375. (func 'list-active-group))
  376. (when (gnus-check-backend-function func group)
  377. (funcall (gnus-get-function gnus-command-method func)
  378. (gnus-group-real-name group) (nth 1 gnus-command-method)))))
  379. (defun gnus-request-group-description (group)
  380. "Request a description of GROUP."
  381. (let ((gnus-command-method (gnus-find-method-for-group group))
  382. (func 'request-group-description))
  383. (when (gnus-check-backend-function func group)
  384. (funcall (gnus-get-function gnus-command-method func)
  385. (gnus-group-real-name group) (nth 1 gnus-command-method)))))
  386. (defun gnus-request-group-articles (group)
  387. "Request a list of existing articles in GROUP."
  388. (let ((gnus-command-method (gnus-find-method-for-group group))
  389. (func 'request-group-articles))
  390. (when (gnus-check-backend-function func group)
  391. (funcall (gnus-get-function gnus-command-method func)
  392. (gnus-group-real-name group) (nth 1 gnus-command-method)))))
  393. (defun gnus-close-group (group)
  394. "Request the GROUP be closed."
  395. (let ((gnus-command-method (inline (gnus-find-method-for-group group))))
  396. (funcall (gnus-get-function gnus-command-method 'close-group)
  397. (gnus-group-real-name group) (nth 1 gnus-command-method))))
  398. (defun gnus-retrieve-headers (articles group &optional fetch-old)
  399. "Request headers for ARTICLES in GROUP.
  400. If FETCH-OLD, retrieve all headers (or some subset thereof) in the group."
  401. (let ((gnus-command-method (gnus-find-method-for-group group)))
  402. (cond
  403. ((and gnus-use-cache (numberp (car articles)))
  404. (gnus-cache-retrieve-headers articles group fetch-old))
  405. ((and gnus-agent (gnus-online gnus-command-method)
  406. (gnus-agent-method-p gnus-command-method))
  407. (gnus-agent-retrieve-headers articles group fetch-old))
  408. (t
  409. (funcall (gnus-get-function gnus-command-method 'retrieve-headers)
  410. articles (gnus-group-real-name group)
  411. (nth 1 gnus-command-method) fetch-old)))))
  412. (defun gnus-retrieve-articles (articles group)
  413. "Request ARTICLES in GROUP."
  414. (let ((gnus-command-method (gnus-find-method-for-group group)))
  415. (funcall (gnus-get-function gnus-command-method 'retrieve-articles)
  416. articles (gnus-group-real-name group)
  417. (nth 1 gnus-command-method))))
  418. (defun gnus-retrieve-groups (groups gnus-command-method)
  419. "Request active information on GROUPS from GNUS-COMMAND-METHOD."
  420. (when (stringp gnus-command-method)
  421. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  422. (funcall (gnus-get-function gnus-command-method 'retrieve-groups)
  423. groups (nth 1 gnus-command-method)))
  424. (defun gnus-request-type (group &optional article)
  425. "Return the type (`post' or `mail') of GROUP (and ARTICLE)."
  426. (let ((gnus-command-method (gnus-find-method-for-group group)))
  427. (if (not (gnus-check-backend-function
  428. 'request-type (car gnus-command-method)))
  429. 'unknown
  430. (funcall (gnus-get-function gnus-command-method 'request-type)
  431. (gnus-group-real-name group) article))))
  432. (defun gnus-request-update-group-status (group status)
  433. "Change the status of a group.
  434. Valid statuses include `subscribe' and `unsubscribe'."
  435. (let ((gnus-command-method (gnus-find-method-for-group group)))
  436. (if (not (gnus-check-backend-function
  437. 'request-update-group-status (car gnus-command-method)))
  438. nil
  439. (funcall
  440. (gnus-get-function gnus-command-method 'request-update-group-status)
  441. (gnus-group-real-name group) status
  442. (nth 1 gnus-command-method)))))
  443. (defun gnus-request-set-mark (group action)
  444. "Set marks on articles in the back end."
  445. (let ((gnus-command-method (gnus-find-method-for-group group)))
  446. (if (not (gnus-check-backend-function
  447. 'request-set-mark (car gnus-command-method)))
  448. action
  449. (funcall (gnus-get-function gnus-command-method 'request-set-mark)
  450. (gnus-group-real-name group) action
  451. (nth 1 gnus-command-method))
  452. (gnus-run-hook-with-args gnus-after-set-mark-hook group action))))
  453. (defun gnus-request-update-mark (group article mark)
  454. "Allow the back end to change the mark the user tries to put on an article."
  455. (let ((gnus-command-method (gnus-find-method-for-group group)))
  456. (if (not (gnus-check-backend-function
  457. 'request-update-mark (car gnus-command-method)))
  458. mark
  459. (gnus-run-hook-with-args gnus-before-update-mark-hook group article mark)
  460. (funcall (gnus-get-function gnus-command-method 'request-update-mark)
  461. (gnus-group-real-name group) article mark))))
  462. (defun gnus-request-article (article group &optional buffer)
  463. "Request the ARTICLE in GROUP.
  464. ARTICLE can either be an article number or an article Message-ID.
  465. If BUFFER, insert the article in that group."
  466. (let ((gnus-command-method (gnus-find-method-for-group group)))
  467. (funcall (gnus-get-function gnus-command-method 'request-article)
  468. article (gnus-group-real-name group)
  469. (nth 1 gnus-command-method) buffer)))
  470. (defun gnus-request-thread (header group)
  471. "Request the headers in the thread containing the article specified by HEADER."
  472. (let ((gnus-command-method (gnus-find-method-for-group group)))
  473. (funcall (gnus-get-function gnus-command-method 'request-thread)
  474. header
  475. (gnus-group-real-name group))))
  476. (defun gnus-warp-to-article ()
  477. "Warps from an article in a virtual group to the article in its
  478. real group. Does nothing on a real group."
  479. (interactive)
  480. (let ((gnus-command-method
  481. (gnus-find-method-for-group gnus-newsgroup-name)))
  482. (when (gnus-check-backend-function
  483. 'warp-to-article (car gnus-command-method))
  484. (funcall (gnus-get-function gnus-command-method 'warp-to-article)))))
  485. (defun gnus-request-head (article group)
  486. "Request the head of ARTICLE in GROUP."
  487. (let* ((gnus-command-method (gnus-find-method-for-group group))
  488. (head (gnus-get-function gnus-command-method 'request-head t))
  489. res clean-up)
  490. (cond
  491. ;; Check the cache.
  492. ((and gnus-use-cache
  493. (numberp article)
  494. (gnus-cache-request-article article group))
  495. (setq res (cons group article)
  496. clean-up t))
  497. ;; Check the agent cache.
  498. ((gnus-agent-request-article article group)
  499. (setq res (cons group article)
  500. clean-up t))
  501. ;; Use `head' function.
  502. ((fboundp head)
  503. (setq res (funcall head article (gnus-group-real-name group)
  504. (nth 1 gnus-command-method))))
  505. ;; Use `article' function.
  506. (t
  507. (setq res (gnus-request-article article group)
  508. clean-up t)))
  509. (when clean-up
  510. (with-current-buffer nntp-server-buffer
  511. (goto-char (point-min))
  512. (when (search-forward "\n\n" nil t)
  513. (delete-region (1- (point)) (point-max)))
  514. (nnheader-fold-continuation-lines)))
  515. res))
  516. (defun gnus-request-body (article group)
  517. "Request the body of ARTICLE in GROUP."
  518. (let* ((gnus-command-method (gnus-find-method-for-group group))
  519. (head (gnus-get-function gnus-command-method 'request-body t))
  520. res clean-up)
  521. (cond
  522. ;; Check the cache.
  523. ((and gnus-use-cache
  524. (numberp article)
  525. (gnus-cache-request-article article group))
  526. (setq res (cons group article)
  527. clean-up t))
  528. ;; Check the agent cache.
  529. ((gnus-agent-request-article article group)
  530. (setq res (cons group article)
  531. clean-up t))
  532. ;; Use `head' function.
  533. ((fboundp head)
  534. (setq res (funcall head article (gnus-group-real-name group)
  535. (nth 1 gnus-command-method))))
  536. ;; Use `article' function.
  537. (t
  538. (setq res (gnus-request-article article group)
  539. clean-up t)))
  540. (when clean-up
  541. (with-current-buffer nntp-server-buffer
  542. (goto-char (point-min))
  543. (when (search-forward "\n\n" nil t)
  544. (delete-region (point-min) (1- (point))))))
  545. res))
  546. (defun gnus-request-post (gnus-command-method)
  547. "Post the current buffer using GNUS-COMMAND-METHOD."
  548. (when (stringp gnus-command-method)
  549. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  550. (funcall (gnus-get-function gnus-command-method 'request-post)
  551. (nth 1 gnus-command-method)))
  552. (defun gnus-request-expunge-group (group gnus-command-method)
  553. "Expunge GROUP, which is removing articles that have been marked as deleted."
  554. (when (stringp gnus-command-method)
  555. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  556. (funcall (gnus-get-function gnus-command-method 'request-expunge-group)
  557. (gnus-group-real-name group)
  558. (nth 1 gnus-command-method)))
  559. (defun gnus-request-scan (group gnus-command-method)
  560. "Request a SCAN being performed in GROUP from GNUS-COMMAND-METHOD.
  561. If GROUP is nil, all groups on GNUS-COMMAND-METHOD are scanned."
  562. (let ((gnus-command-method
  563. (if group (gnus-find-method-for-group group) gnus-command-method))
  564. (gnus-inhibit-demon t)
  565. (mail-source-plugged gnus-plugged))
  566. (when (or gnus-plugged
  567. (not (gnus-agent-method-p gnus-command-method)))
  568. (setq gnus-internal-registry-spool-current-method gnus-command-method)
  569. (funcall (gnus-get-function gnus-command-method 'request-scan)
  570. (and group (gnus-group-real-name group))
  571. (nth 1 gnus-command-method)))))
  572. (defun gnus-request-update-info (info gnus-command-method)
  573. (when (gnus-check-backend-function
  574. 'request-update-info (car gnus-command-method))
  575. (when (stringp gnus-command-method)
  576. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  577. (funcall (gnus-get-function gnus-command-method 'request-update-info)
  578. (gnus-group-real-name (gnus-info-group info)) info
  579. (nth 1 gnus-command-method))))
  580. (defsubst gnus-request-marks (info gnus-command-method)
  581. "Request that GNUS-COMMAND-METHOD update INFO."
  582. (when (stringp gnus-command-method)
  583. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  584. (when (gnus-check-backend-function
  585. 'request-marks (car gnus-command-method))
  586. (let ((group (gnus-info-group info)))
  587. (and (funcall (gnus-get-function gnus-command-method 'request-marks)
  588. (gnus-group-real-name group)
  589. info (nth 1 gnus-command-method))
  590. ;; If the minimum article number is greater than 1, then all
  591. ;; smaller article numbers are known not to exist; we'll
  592. ;; artificially add those to the 'read range.
  593. (let* ((active (gnus-active group))
  594. (min (car active)))
  595. (when (> min 1)
  596. (let* ((range (if (= min 2) 1 (cons 1 (1- min))))
  597. (read (gnus-info-read info))
  598. (new-read (gnus-range-add read (list range))))
  599. (gnus-info-set-read info new-read)))
  600. info)))))
  601. (defun gnus-request-expire-articles (articles group &optional force)
  602. (let* ((gnus-command-method (gnus-find-method-for-group group))
  603. (gnus-inhibit-demon t)
  604. (not-deleted
  605. (funcall
  606. (gnus-get-function gnus-command-method 'request-expire-articles)
  607. articles (gnus-group-real-name group) (nth 1 gnus-command-method)
  608. force)))
  609. (when (and gnus-agent
  610. (gnus-agent-method-p gnus-command-method))
  611. (let ((expired-articles (gnus-sorted-difference articles not-deleted)))
  612. (when expired-articles
  613. (gnus-agent-expire expired-articles group 'force))))
  614. not-deleted))
  615. (defun gnus-request-move-article (article group server accept-function
  616. &optional last move-is-internal)
  617. (let* ((gnus-command-method (gnus-find-method-for-group group))
  618. (result (funcall (gnus-get-function gnus-command-method
  619. 'request-move-article)
  620. article (gnus-group-real-name group)
  621. (nth 1 gnus-command-method) accept-function
  622. last move-is-internal)))
  623. (when (and result gnus-agent
  624. (gnus-agent-method-p gnus-command-method))
  625. (gnus-agent-unfetch-articles group (list article)))
  626. result))
  627. (defun gnus-request-accept-article (group &optional gnus-command-method last
  628. no-encode)
  629. ;; Make sure there's a newline at the end of the article.
  630. (when (stringp gnus-command-method)
  631. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  632. (when (and (not gnus-command-method)
  633. (stringp group))
  634. (setq gnus-command-method (or (gnus-find-method-for-group group)
  635. (gnus-group-name-to-method group))))
  636. (goto-char (point-max))
  637. (unless (bolp)
  638. (insert "\n"))
  639. (unless no-encode
  640. (let ((message-options message-options))
  641. (message-options-set-recipient)
  642. (save-restriction
  643. (message-narrow-to-head)
  644. (let ((mail-parse-charset message-default-charset))
  645. (mail-encode-encoded-word-buffer)))
  646. (message-encode-message-body)))
  647. (let ((gnus-command-method (or gnus-command-method
  648. (gnus-find-method-for-group group)))
  649. (result
  650. (funcall
  651. (gnus-get-function gnus-command-method 'request-accept-article)
  652. (if (stringp group) (gnus-group-real-name group) group)
  653. (cadr gnus-command-method)
  654. last)))
  655. (when (and gnus-agent
  656. (gnus-agent-method-p gnus-command-method)
  657. (cdr result))
  658. (gnus-agent-regenerate-group group (list (cdr result))))
  659. result))
  660. (defun gnus-request-replace-article (article group buffer &optional no-encode)
  661. (unless no-encode
  662. (let ((message-options message-options))
  663. (message-options-set-recipient)
  664. (save-restriction
  665. (message-narrow-to-head)
  666. (let ((mail-parse-charset message-default-charset))
  667. (mail-encode-encoded-word-buffer)))
  668. (message-encode-message-body)))
  669. (let* ((func (car (gnus-group-name-to-method group)))
  670. (result (funcall (intern (format "%s-request-replace-article" func))
  671. article (gnus-group-real-name group) buffer)))
  672. (when (and gnus-agent (gnus-agent-method-p gnus-command-method))
  673. (gnus-agent-regenerate-group group (list article)))
  674. result))
  675. (defun gnus-request-associate-buffer (group)
  676. (let ((gnus-command-method (gnus-find-method-for-group group)))
  677. (funcall (gnus-get-function gnus-command-method 'request-associate-buffer)
  678. (gnus-group-real-name group))))
  679. (defun gnus-request-restore-buffer (article group)
  680. "Request a new buffer restored to the state of ARTICLE."
  681. (let ((gnus-command-method (gnus-find-method-for-group group)))
  682. (funcall (gnus-get-function gnus-command-method 'request-restore-buffer)
  683. article (gnus-group-real-name group)
  684. (nth 1 gnus-command-method))))
  685. (defun gnus-request-create-group (group &optional gnus-command-method args)
  686. (when (stringp gnus-command-method)
  687. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  688. (let ((gnus-command-method
  689. (or gnus-command-method (gnus-find-method-for-group group))))
  690. (funcall (gnus-get-function gnus-command-method 'request-create-group)
  691. (gnus-group-real-name group) (nth 1 gnus-command-method) args)))
  692. (defun gnus-request-delete-group (group &optional force)
  693. (let* ((gnus-command-method (gnus-find-method-for-group group))
  694. (result
  695. (funcall (gnus-get-function gnus-command-method 'request-delete-group)
  696. (gnus-group-real-name group) force (nth 1 gnus-command-method))))
  697. (when result
  698. (gnus-cache-delete-group group)
  699. (gnus-agent-delete-group group))
  700. result))
  701. (defun gnus-request-rename-group (group new-name)
  702. (let* ((gnus-command-method (gnus-find-method-for-group group))
  703. (result
  704. (funcall (gnus-get-function gnus-command-method 'request-rename-group)
  705. (gnus-group-real-name group)
  706. (gnus-group-real-name new-name) (nth 1 gnus-command-method))))
  707. (when result
  708. (gnus-cache-rename-group group new-name)
  709. (gnus-agent-rename-group group new-name))
  710. result))
  711. (defun gnus-close-backends ()
  712. ;; Send a close request to all backends that support such a request.
  713. (let ((methods gnus-valid-select-methods)
  714. (gnus-inhibit-demon t)
  715. func gnus-command-method)
  716. (while (setq gnus-command-method (pop methods))
  717. (when (fboundp (setq func (intern
  718. (concat (car gnus-command-method)
  719. "-request-close"))))
  720. (funcall func)))))
  721. (defun gnus-asynchronous-p (gnus-command-method)
  722. (let ((func (gnus-get-function gnus-command-method 'asynchronous-p t)))
  723. (when (fboundp func)
  724. (funcall func))))
  725. (defun gnus-remove-denial (gnus-command-method)
  726. (when (stringp gnus-command-method)
  727. (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
  728. (let* ((elem (assoc gnus-command-method gnus-opened-servers))
  729. (status (cadr elem)))
  730. ;; If this hasn't been opened before, we add it to the list.
  731. (when (eq status 'denied)
  732. ;; Set the status of this server.
  733. (setcar (cdr elem) 'closed))))
  734. (provide 'gnus-int)
  735. ;;; gnus-int.el ends here