Mercurial > hg > xemacs-beta
comparison lisp/gnus/nntp.el @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | 8d2a9b52c682 |
children | 0d2f883870bc |
comparison
equal
deleted
inserted
replaced
69:804d1389bcd6 | 70:131b0175ea99 |
---|---|
1 ;;; nntp.el --- nntp access for Gnus | 1 ;;; nntp.el --- nntp access for Gnus |
2 ;;; Copyright (C) 1987,88,89,90,92,93,94,95,96,97 Free Software Foundation, Inc. | 2 ;; Copyright (C) 1987,88,89,90,92,93,94,95,96 Free Software Foundation, Inc. |
3 | 3 |
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> | 4 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> |
5 ;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no> | |
5 ;; Keywords: news | 6 ;; Keywords: news |
6 | 7 |
7 ;; This file is part of GNU Emacs. | 8 ;; This file is part of GNU Emacs. |
8 | 9 |
9 ;; GNU Emacs is free software; you can redistribute it and/or modify | 10 ;; GNU Emacs is free software; you can redistribute it and/or modify |
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 ;; GNU General Public License for more details. | 18 ;; GNU General Public License for more details. |
18 | 19 |
19 ;; You should have received a copy of the GNU General Public License | 20 ;; You should have received a copy of the GNU General Public License |
20 ;; along with GNU Emacs; see the file COPYING. If not, write to | 21 ;; along with GNU Emacs; see the file COPYING. If not, write to the |
21 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
23 ;; Boston, MA 02111-1307, USA. | |
22 | 24 |
23 ;;; Commentary: | 25 ;;; Commentary: |
24 | 26 |
25 ;;; Code: | 27 ;;; Code: |
26 | 28 |
27 (require 'nnheader) | 29 (require 'nnheader) |
28 (require 'nnoo) | 30 (require 'nnoo) |
29 (require 'gnus-util) | 31 (eval-when-compile (require 'cl)) |
30 | 32 |
31 (nnoo-declare nntp) | 33 (nnoo-declare nntp) |
32 | 34 |
33 (eval-and-compile | 35 (eval-and-compile |
34 (unless (fboundp 'open-network-stream) | 36 (unless (fboundp 'open-network-stream) |
35 (require 'tcp))) | 37 (require 'tcp))) |
36 | 38 |
37 (eval-when-compile (require 'cl)) | 39 (eval-when-compile (require 'cl)) |
38 | 40 |
39 (defvoo nntp-address nil | 41 (eval-and-compile |
40 "Address of the physical nntp server.") | 42 (autoload 'cancel-timer "timer") |
41 | 43 (autoload 'telnet "telnet" nil t) |
42 (defvoo nntp-port-number "nntp" | 44 (autoload 'telnet-send-input "telnet" nil t) |
43 "Port number on the physical nntp server.") | 45 (autoload 'timezone-parse-date "timezone")) |
46 | |
47 (defvoo nntp-server-hook nil | |
48 "*Hooks for the NNTP server. | |
49 If the kanji code of the NNTP server is different from the local kanji | |
50 code, the correct kanji code of the buffer associated with the NNTP | |
51 server must be specified as follows: | |
52 | |
53 \(setq nntp-server-hook | |
54 (function | |
55 (lambda () | |
56 ;; Server's Kanji code is EUC (NEmacs hack). | |
57 (make-local-variable 'kanji-fileio-code) | |
58 (setq kanji-fileio-code 0)))) | |
59 | |
60 If you'd like to change something depending on the server in this | |
61 hook, use the variable `nntp-address'.") | |
44 | 62 |
45 (defvoo nntp-server-opened-hook '(nntp-send-mode-reader) | 63 (defvoo nntp-server-opened-hook '(nntp-send-mode-reader) |
46 "*Hook used for sending commands to the server at startup. | 64 "*Hook used for sending commands to the server at startup. |
47 The default value is `nntp-send-mode-reader', which makes an innd | 65 The default value is `nntp-send-mode-reader', which makes an innd |
48 server spawn an nnrpd server. Another useful function to put in this | 66 server spawn an nnrpd server. Another useful function to put in this |
49 hook might be `nntp-send-authinfo', which will prompt for a password | 67 hook might be `nntp-send-authinfo', which will prompt for a password |
50 to allow posting from the server. Note that this is only necessary to | 68 to allow posting from the server. Note that this is only necessary to |
51 do on servers that use strict access control.") | 69 do on servers that use strict access control.") |
52 | 70 (add-hook 'nntp-server-opened-hook 'nntp-send-mode-reader) |
53 (defvoo nntp-authinfo-function 'nntp-send-authinfo | 71 |
54 "Function used to send AUTHINFO to the server.") | 72 (defvoo nntp-server-action-alist |
55 | 73 '(("nntpd 1\\.5\\.11t" |
56 (defvoo nntp-server-action-alist | 74 (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader))) |
57 '(("nntpd 1\\.5\\.11t" | |
58 (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader)) | |
59 ("NNRP server Netscape" | |
60 (setq nntp-server-list-active-group nil))) | |
61 "Alist of regexps to match on server types and actions to be taken. | 75 "Alist of regexps to match on server types and actions to be taken. |
62 For instance, if you want Gnus to beep every time you connect | 76 For instance, if you want Gnus to beep every time you connect |
63 to innd, you could say something like: | 77 to innd, you could say something like: |
64 | 78 |
65 \(setq nntp-server-action-alist | 79 \(setq nntp-server-action-alist |
66 '((\"innd\" (ding)))) | 80 '((\"innd\" (ding)))) |
67 | 81 |
68 You probably don't want to do that, though.") | 82 You probably don't want to do that, though.") |
69 | 83 |
70 (defvoo nntp-open-connection-function 'nntp-open-network-stream | 84 (defvoo nntp-open-server-function 'nntp-open-network-stream |
71 "*Function used for connecting to a remote system. | 85 "*Function used for connecting to a remote system. |
72 It will be called with the buffer to output in. | 86 It will be called with the address of the remote system. |
73 | 87 |
74 Two pre-made functions are `nntp-open-network-stream', which is the | 88 Two pre-made functions are `nntp-open-network-stream', which is the |
75 default, and simply connects to some port or other on the remote | 89 default, and simply connects to some port or other on the remote |
76 system (see nntp-port-number). The other are `nntp-open-rlogin', which | 90 system (see nntp-port-number). The other is `nntp-open-rlogin', which |
77 does an rlogin on the remote system, and then does a telnet to the | 91 does an rlogin on the remote system, and then does a telnet to the |
78 NNTP server available there (see nntp-rlogin-parameters) and `nntp-open-telnet' which | 92 NNTP server available there (see nntp-rlogin-parameters).") |
79 telnets to a remote system, logs in and does the same") | 93 |
80 | 94 (defvoo nntp-rlogin-parameters '("telnet" "${NNTPSERVER:=localhost}" "nntp") |
81 (defvoo nntp-rlogin-parameters '("telnet" "-8" "${NNTPSERVER:=news}" "nntp") | 95 "*Parameters to `nntp-open-rlogin'. |
82 "*Parameters to `nntp-open-login'. | 96 That function may be used as `nntp-open-server-function'. In that |
83 That function may be used as `nntp-open-connection-function'. In that | |
84 case, this list will be used as the parameter list given to rsh.") | 97 case, this list will be used as the parameter list given to rsh.") |
85 | 98 |
86 (defvoo nntp-rlogin-user-name nil | 99 (defvoo nntp-rlogin-user-name nil |
87 "*User name on remote system when using the rlogin connect method.") | 100 "*User name on remote system when using the rlogin connect method.") |
88 | 101 |
89 (defvoo nntp-telnet-parameters '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp") | 102 (defvoo nntp-telnet-parameters '("exec" "telnet" "-8" "${NNTPSERVER:=localhost}" "nntp") |
90 "*Parameters to `nntp-open-telnet'. | 103 "*Parameters to `nntp-open-telnet'. |
91 That function may be used as `nntp-open-connection-function'. In that | 104 That function may be used as `nntp-open-server-function'. In that |
92 case, this list will be executed as a command after logging in | 105 case, this list will be executed as a command after logging in |
93 via telnet.") | 106 via telnet.") |
94 | 107 |
95 (defvoo nntp-telnet-user-name nil | 108 (defvoo nntp-telnet-user-name nil |
96 "User name to log in via telnet with.") | 109 "User name to log in via telnet with.") |
97 | 110 |
98 (defvoo nntp-telnet-passwd nil | 111 (defvoo nntp-telnet-passwd nil |
99 "Password to use to log in via telnet with.") | 112 "Password to use to log in via telnet with.") |
113 | |
114 (defvoo nntp-address nil | |
115 "*The name of the NNTP server.") | |
116 | |
117 (defvoo nntp-port-number "nntp" | |
118 "*Port number to connect to.") | |
100 | 119 |
101 (defvoo nntp-end-of-line "\r\n" | 120 (defvoo nntp-end-of-line "\r\n" |
102 "String to use on the end of lines when talking to the NNTP server. | 121 "String to use on the end of lines when talking to the NNTP server. |
103 This is \"\\r\\n\" by default, but should be \"\\n\" when | 122 This is \"\\r\\n\" by default, but should be \"\\n\" when |
104 using rlogin or telnet to communicate with the server.") | 123 using rlogin or telnet to communicate with the server.") |
106 (defvoo nntp-large-newsgroup 50 | 125 (defvoo nntp-large-newsgroup 50 |
107 "*The number of the articles which indicates a large newsgroup. | 126 "*The number of the articles which indicates a large newsgroup. |
108 If the number of the articles is greater than the value, verbose | 127 If the number of the articles is greater than the value, verbose |
109 messages will be shown to indicate the current status.") | 128 messages will be shown to indicate the current status.") |
110 | 129 |
130 (defvoo nntp-buggy-select (memq system-type '(fujitsu-uts)) | |
131 "*t if your select routine is buggy. | |
132 If the select routine signals error or fall into infinite loop while | |
133 waiting for the server response, the variable must be set to t. In | |
134 case of Fujitsu UTS, it is set to T since `accept-process-output' | |
135 doesn't work properly.") | |
136 | |
111 (defvoo nntp-maximum-request 400 | 137 (defvoo nntp-maximum-request 400 |
112 "*The maximum number of the requests sent to the NNTP server at one time. | 138 "*The maximum number of the requests sent to the NNTP server at one time. |
113 If Emacs hangs up while retrieving headers, set the variable to a | 139 If Emacs hangs up while retrieving headers, set the variable to a |
114 lower value.") | 140 lower value.") |
115 | 141 |
142 (defvoo nntp-debug-read 10000 | |
143 "*Display '...' every 10Kbytes of a message being received if it is non-nil. | |
144 If it is a number, dots are displayed per the number.") | |
145 | |
116 (defvoo nntp-nov-is-evil nil | 146 (defvoo nntp-nov-is-evil nil |
117 "*If non-nil, nntp will never attempt to use XOVER when talking to the server.") | 147 "*If non-nil, nntp will never attempt to use XOVER when talking to the server.") |
118 | 148 |
119 (defvoo nntp-xover-commands '("XOVER" "XOVERVIEW") | 149 (defvoo nntp-xover-commands '("XOVER" "XOVERVIEW") |
120 "*List of strings that are used as commands to fetch NOV lines from a server. | 150 "*List of strings that are used as commands to fetch NOV lines from a server. |
121 The strings are tried in turn until a positive response is gotten. If | 151 The strings are tried in turn until a positive response is gotten. If |
122 none of the commands are successful, nntp will just grab headers one | 152 none of the commands are successful, nntp will just grab headers one |
123 by one.") | 153 by one.") |
124 | 154 |
125 (defvoo nntp-nov-gap 20 | 155 (defvoo nntp-nov-gap 20 |
126 "*Maximum allowed gap between two articles. | 156 "*Maximum allowed gap between two articles. |
128 variable, split the XOVER request into two requests.") | 158 variable, split the XOVER request into two requests.") |
129 | 159 |
130 (defvoo nntp-connection-timeout nil | 160 (defvoo nntp-connection-timeout nil |
131 "*Number of seconds to wait before an nntp connection times out. | 161 "*Number of seconds to wait before an nntp connection times out. |
132 If this variable is nil, which is the default, no timers are set.") | 162 If this variable is nil, which is the default, no timers are set.") |
163 | |
164 (defvoo nntp-command-timeout nil | |
165 "*Number of seconds to wait for a response when sending a command. | |
166 If this variable is nil, which is the default, no timers are set.") | |
167 | |
168 (defvoo nntp-retry-on-break nil | |
169 "*If non-nil, re-send the command when the user types `C-g'.") | |
170 | |
171 (defvoo nntp-news-default-headers nil | |
172 "*If non-nil, override `mail-default-headers' when posting news.") | |
133 | 173 |
134 (defvoo nntp-prepare-server-hook nil | 174 (defvoo nntp-prepare-server-hook nil |
135 "*Hook run before a server is opened. | 175 "*Hook run before a server is opened. |
136 If can be used to set up a server remotely, for instance. Say you | 176 If can be used to set up a server remotely, for instance. Say you |
137 have an account at the machine \"other.machine\". This machine has | 177 have an account at the machine \"other.machine\". This machine has |
138 access to an NNTP server that you can't access locally. You could | 178 access to an NNTP server that you can't access locally. You could |
139 then use this hook to rsh to the remote machine and start a proxy NNTP | 179 then use this hook to rsh to the remote machine and start a proxy NNTP |
140 server there that you can connect to. See also `nntp-open-connection-function'") | 180 server there that you can connect to.") |
181 | |
182 (defvoo nntp-async-number 5 | |
183 "*How many articles should be prefetched when in asynchronous mode.") | |
141 | 184 |
142 (defvoo nntp-warn-about-losing-connection t | 185 (defvoo nntp-warn-about-losing-connection t |
143 "*If non-nil, beep when a server closes connection.") | 186 "*If non-nil, beep when a server closes connection.") |
144 | 187 |
145 | 188 |
146 | 189 |
147 ;;; Internal variables. | 190 (defconst nntp-version "nntp 4.0" |
148 | 191 "Version numbers of this version of NNTP.") |
149 (defvar nntp-have-messaged nil) | 192 |
150 | 193 (defvar nntp-server-buffer nil |
151 (defvar nntp-process-wait-for nil) | 194 "Buffer associated with the NNTP server process.") |
152 (defvar nntp-process-to-buffer nil) | 195 |
153 (defvar nntp-process-callback nil) | 196 (defvoo nntp-server-process nil |
154 (defvar nntp-process-decode nil) | 197 "The NNTP server process. |
155 (defvar nntp-process-start-point nil) | 198 You'd better not use this variable in NNTP front-end program, but |
156 (defvar nntp-inside-change-function nil) | 199 instead use `nntp-server-buffer'.") |
157 | 200 |
158 (defvar nntp-connection-list nil) | 201 (defvoo nntp-status-string nil |
159 | 202 "Save the server response message.") |
160 (defvoo nntp-server-type nil) | 203 |
161 (defvoo nntp-connection-alist nil) | 204 (defvar nntp-opened-connections nil |
162 (defvoo nntp-status-string "") | 205 "All (possibly) opened connections.") |
163 (defconst nntp-version "nntp 5.0") | |
164 (defvoo nntp-inhibit-erase nil) | |
165 (defvoo nntp-inhibit-output nil) | |
166 | 206 |
167 (defvoo nntp-server-xover 'try) | 207 (defvoo nntp-server-xover 'try) |
168 (defvoo nntp-server-list-active-group 'try) | 208 (defvoo nntp-server-list-active-group 'try) |
169 | 209 (defvoo nntp-current-group "") |
170 (eval-and-compile | 210 (defvoo nntp-server-type nil) |
171 (autoload 'nnmail-read-passwd "nnmail")) | 211 |
212 (defvoo nntp-async-process nil) | |
213 (defvoo nntp-async-buffer nil) | |
214 (defvoo nntp-async-articles nil) | |
215 (defvoo nntp-async-fetched nil) | |
216 (defvoo nntp-async-group-alist nil) | |
172 | 217 |
173 | 218 |
174 | |
175 ;;; Internal functions. | |
176 | |
177 (defsubst nntp-send-string (process string) | |
178 "Send STRING to PROCESS." | |
179 (process-send-string process (concat string nntp-end-of-line))) | |
180 | |
181 (defsubst nntp-wait-for (process wait-for buffer &optional decode discard) | |
182 "Wait for WAIT-FOR to arrive from PROCESS." | |
183 (save-excursion | |
184 (set-buffer (process-buffer process)) | |
185 (goto-char (point-min)) | |
186 (while (or (not (memq (following-char) '(?2 ?3 ?4 ?5))) | |
187 (looking-at "480")) | |
188 (when (looking-at "480") | |
189 (erase-buffer) | |
190 (funcall nntp-authinfo-function)) | |
191 (nntp-accept-process-output process) | |
192 (goto-char (point-min))) | |
193 (prog1 | |
194 (if (looking-at "[45]") | |
195 (progn | |
196 (nntp-snarf-error-message) | |
197 nil) | |
198 (goto-char (point-max)) | |
199 (let ((limit (point-min))) | |
200 (while (not (re-search-backward wait-for limit t)) | |
201 ;; We assume that whatever we wait for is less than 1000 | |
202 ;; characters long. | |
203 (setq limit (max (- (point-max) 1000) (point-min))) | |
204 (nntp-accept-process-output process) | |
205 (goto-char (point-max)))) | |
206 (nntp-decode-text (not decode)) | |
207 (unless discard | |
208 (save-excursion | |
209 (set-buffer buffer) | |
210 (goto-char (point-max)) | |
211 (insert-buffer-substring (process-buffer process)) | |
212 ;; Nix out "nntp reading...." message. | |
213 (when nntp-have-messaged | |
214 (setq nntp-have-messaged nil) | |
215 (message "")) | |
216 t))) | |
217 (unless discard | |
218 (erase-buffer))))) | |
219 | |
220 (defsubst nntp-find-connection (buffer) | |
221 "Find the connection delivering to BUFFER." | |
222 (let ((alist nntp-connection-alist) | |
223 (buffer (if (stringp buffer) (get-buffer buffer) buffer)) | |
224 process entry) | |
225 (while (setq entry (pop alist)) | |
226 (when (eq buffer (cadr entry)) | |
227 (setq process (car entry) | |
228 alist nil))) | |
229 (when process | |
230 (if (memq (process-status process) '(open run)) | |
231 process | |
232 (when (buffer-name (process-buffer process)) | |
233 (kill-buffer (process-buffer process))) | |
234 (setq nntp-connection-alist (delq entry nntp-connection-alist)) | |
235 nil)))) | |
236 | |
237 (defsubst nntp-find-connection-entry (buffer) | |
238 "Return the entry for the connection to BUFFER." | |
239 (assq (nntp-find-connection buffer) nntp-connection-alist)) | |
240 | |
241 (defun nntp-find-connection-buffer (buffer) | |
242 "Return the process connection buffer tied to BUFFER." | |
243 (let ((process (nntp-find-connection buffer))) | |
244 (when process | |
245 (process-buffer process)))) | |
246 | |
247 (defsubst nntp-retrieve-data (command address port buffer | |
248 &optional wait-for callback decode) | |
249 "Use COMMAND to retrieve data into BUFFER from PORT on ADDRESS." | |
250 (let ((process (or (nntp-find-connection buffer) | |
251 (nntp-open-connection buffer)))) | |
252 (if (not process) | |
253 (nnheader-report 'nntp "Couldn't open connection to %s" address) | |
254 (unless (or nntp-inhibit-erase nnheader-callback-function) | |
255 (save-excursion | |
256 (set-buffer (process-buffer process)) | |
257 (erase-buffer))) | |
258 (when command | |
259 (nntp-send-string process command)) | |
260 (cond | |
261 ((eq callback 'ignore) | |
262 t) | |
263 ((and callback wait-for) | |
264 (save-excursion | |
265 (set-buffer (process-buffer process)) | |
266 (unless nntp-inside-change-function | |
267 (erase-buffer)) | |
268 (setq nntp-process-decode decode | |
269 nntp-process-to-buffer buffer | |
270 nntp-process-wait-for wait-for | |
271 nntp-process-callback callback | |
272 nntp-process-start-point (point-max) | |
273 after-change-functions | |
274 (list 'nntp-after-change-function-callback))) | |
275 t) | |
276 (wait-for | |
277 (nntp-wait-for process wait-for buffer decode)) | |
278 (t t))))) | |
279 | |
280 (defsubst nntp-send-command (wait-for &rest strings) | |
281 "Send STRINGS to server and wait until WAIT-FOR returns." | |
282 (when (and (not nnheader-callback-function) | |
283 (not nntp-inhibit-output)) | |
284 (save-excursion | |
285 (set-buffer nntp-server-buffer) | |
286 (erase-buffer))) | |
287 (nntp-retrieve-data | |
288 (mapconcat 'identity strings " ") | |
289 nntp-address nntp-port-number nntp-server-buffer | |
290 wait-for nnheader-callback-function)) | |
291 | |
292 (defun nntp-send-command-nodelete (wait-for &rest strings) | |
293 "Send STRINGS to server and wait until WAIT-FOR returns." | |
294 (nntp-retrieve-data | |
295 (mapconcat 'identity strings " ") | |
296 nntp-address nntp-port-number nntp-server-buffer | |
297 wait-for nnheader-callback-function)) | |
298 | |
299 (defun nntp-send-command-and-decode (wait-for &rest strings) | |
300 "Send STRINGS to server and wait until WAIT-FOR returns." | |
301 (when (and (not nnheader-callback-function) | |
302 (not nntp-inhibit-output)) | |
303 (save-excursion | |
304 (set-buffer nntp-server-buffer) | |
305 (erase-buffer))) | |
306 (nntp-retrieve-data | |
307 (mapconcat 'identity strings " ") | |
308 nntp-address nntp-port-number nntp-server-buffer | |
309 wait-for nnheader-callback-function t)) | |
310 | |
311 (defun nntp-send-buffer (wait-for) | |
312 "Send the current buffer to server and wait until WAIT-FOR returns." | |
313 (when (and (not nnheader-callback-function) | |
314 (not nntp-inhibit-output)) | |
315 (save-excursion | |
316 (set-buffer (nntp-find-connection-buffer nntp-server-buffer)) | |
317 (erase-buffer))) | |
318 (nntp-encode-text) | |
319 (process-send-region (nntp-find-connection nntp-server-buffer) | |
320 (point-min) (point-max)) | |
321 (nntp-retrieve-data | |
322 nil nntp-address nntp-port-number nntp-server-buffer | |
323 wait-for nnheader-callback-function)) | |
324 | |
325 | |
326 | |
327 ;;; Interface functions. | 219 ;;; Interface functions. |
328 | 220 |
329 (nnoo-define-basics nntp) | 221 (nnoo-define-basics nntp) |
330 | 222 |
331 (deffoo nntp-retrieve-headers (articles &optional group server fetch-old) | 223 (deffoo nntp-retrieve-headers (articles &optional group server fetch-old) |
332 "Retrieve the headers of ARTICLES." | 224 "Retrieve the headers of ARTICLES." |
333 (nntp-possibly-change-group group server) | 225 (nntp-possibly-change-server group server) |
334 (save-excursion | 226 (save-excursion |
335 (set-buffer (nntp-find-connection-buffer nntp-server-buffer)) | 227 (set-buffer nntp-server-buffer) |
336 (erase-buffer) | 228 (erase-buffer) |
337 (if (and (not gnus-nov-is-evil) | 229 (if (and (not gnus-nov-is-evil) |
338 (not nntp-nov-is-evil) | 230 (not nntp-nov-is-evil) |
339 (nntp-retrieve-headers-with-xover articles fetch-old)) | 231 (nntp-retrieve-headers-with-xover articles fetch-old)) |
340 ;; We successfully retrieved the headers via XOVER. | 232 ;; We successfully retrieved the headers via XOVER. |
341 'nov | 233 'nov |
342 ;; XOVER didn't work, so we do it the hard, slow and inefficient | 234 ;; XOVER didn't work, so we do it the hard, slow and inefficient |
343 ;; way. | 235 ;; way. |
344 (let ((number (length articles)) | 236 (let ((number (length articles)) |
345 (count 0) | 237 (count 0) |
346 (received 0) | 238 (received 0) |
347 (last-point (point-min)) | 239 (message-log-max nil) |
348 (buf (nntp-find-connection-buffer nntp-server-buffer)) | 240 (last-point (point-min))) |
349 (nntp-inhibit-erase t)) | |
350 ;; Send HEAD command. | 241 ;; Send HEAD command. |
351 (while articles | 242 (while articles |
352 (nntp-send-command | 243 (nntp-send-strings-to-server |
353 nil | 244 "HEAD" (if (numberp (car articles)) |
354 "HEAD" (if (numberp (car articles)) | |
355 (int-to-string (car articles)) | 245 (int-to-string (car articles)) |
356 ;; `articles' is either a list of article numbers | 246 ;; `articles' is either a list of article numbers |
357 ;; or a list of article IDs. | 247 ;; or a list of article IDs. |
358 (car articles))) | 248 (car articles))) |
359 (setq articles (cdr articles) | 249 (setq articles (cdr articles) |
362 ;; order to avoid deadlocks. | 252 ;; order to avoid deadlocks. |
363 (when (or (null articles) ;All requests have been sent. | 253 (when (or (null articles) ;All requests have been sent. |
364 (zerop (% count nntp-maximum-request))) | 254 (zerop (% count nntp-maximum-request))) |
365 (nntp-accept-response) | 255 (nntp-accept-response) |
366 (while (progn | 256 (while (progn |
367 (progn | 257 (goto-char last-point) |
368 (set-buffer buf) | |
369 (goto-char last-point)) | |
370 ;; Count replies. | 258 ;; Count replies. |
371 (while (re-search-forward "^[0-9]" nil t) | 259 (while (re-search-forward "^[0-9]" nil t) |
372 (incf received)) | 260 (setq received (1+ received))) |
373 (setq last-point (point)) | 261 (setq last-point (point)) |
374 (< received count)) | 262 (< received count)) |
375 ;; If number of headers is greater than 100, give | 263 ;; If number of headers is greater than 100, give |
376 ;; informative messages. | 264 ;; informative messages. |
377 (and (numberp nntp-large-newsgroup) | 265 (and (numberp nntp-large-newsgroup) |
378 (> number nntp-large-newsgroup) | 266 (> number nntp-large-newsgroup) |
379 (zerop (% received 20)) | 267 (zerop (% received 20)) |
380 (nnheader-message 6 "NNTP: Receiving headers... %d%%" | 268 (nnheader-message 7 "NNTP: Receiving headers... %d%%" |
381 (/ (* received 100) number))) | 269 (/ (* received 100) number))) |
382 (nntp-accept-response)))) | 270 (nntp-accept-response)))) |
383 ;; Wait for text of last command. | 271 ;; Wait for text of last command. |
384 (goto-char (point-max)) | 272 (goto-char (point-max)) |
385 (re-search-backward "^[0-9]" nil t) | 273 (re-search-backward "^[0-9]" nil t) |
386 (when (looking-at "^[23]") | 274 (when (looking-at "^[23]") |
387 (while (progn | 275 (while (progn |
388 (goto-char (point-max)) | 276 (goto-char (- (point-max) 3)) |
389 (forward-line -1) | |
390 (not (looking-at "^\\.\r?\n"))) | 277 (not (looking-at "^\\.\r?\n"))) |
391 (nntp-accept-response))) | 278 (nntp-accept-response))) |
392 (and (numberp nntp-large-newsgroup) | 279 (and (numberp nntp-large-newsgroup) |
393 (> number nntp-large-newsgroup) | 280 (> number nntp-large-newsgroup) |
394 (nnheader-message 6 "NNTP: Receiving headers...done")) | 281 (nnheader-message 7 "NNTP: Receiving headers...done")) |
395 | 282 |
396 ;; Now all of replies are received. Fold continuation lines. | 283 ;; Now all of replies are received. Fold continuation lines. |
397 (nnheader-fold-continuation-lines) | 284 (nnheader-fold-continuation-lines) |
398 ;; Remove all "\r"'s. | 285 ;; Remove all "\r"'s. |
399 (nnheader-strip-cr) | 286 (goto-char (point-min)) |
400 (copy-to-buffer nntp-server-buffer (point-min) (point-max)) | 287 (while (search-forward "\r" nil t) |
288 (replace-match "" t t)) | |
401 'headers)))) | 289 'headers)))) |
290 | |
402 | 291 |
403 (deffoo nntp-retrieve-groups (groups &optional server) | 292 (deffoo nntp-retrieve-groups (groups &optional server) |
404 "Retrieve group info on GROUPS." | 293 "Retrieve group info on GROUPS." |
405 (nntp-possibly-change-group nil server) | 294 (nntp-possibly-change-server nil server) |
406 (save-excursion | 295 (save-excursion |
407 (set-buffer (nntp-find-connection-buffer nntp-server-buffer)) | 296 (set-buffer nntp-server-buffer) |
408 ;; The first time this is run, this variable is `try'. So we | 297 ;; The first time this is run, this variable is `try'. So we |
409 ;; try. | 298 ;; try. |
410 (when (eq nntp-server-list-active-group 'try) | 299 (when (eq nntp-server-list-active-group 'try) |
411 (nntp-try-list-active (car groups))) | 300 (nntp-try-list-active (car groups))) |
412 (erase-buffer) | 301 (erase-buffer) |
413 (let ((count 0) | 302 (let ((count 0) |
414 (received 0) | 303 (received 0) |
415 (last-point (point-min)) | 304 (last-point (point-min)) |
416 (nntp-inhibit-erase t) | |
417 (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP"))) | 305 (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP"))) |
418 (while groups | 306 (while groups |
419 ;; Send the command to the server. | 307 ;; Send the command to the server. |
420 (nntp-send-command nil command (pop groups)) | 308 (nntp-send-strings-to-server command (car groups)) |
421 (incf count) | 309 (setq groups (cdr groups)) |
310 (setq count (1+ count)) | |
422 ;; Every 400 requests we have to read the stream in | 311 ;; Every 400 requests we have to read the stream in |
423 ;; order to avoid deadlocks. | 312 ;; order to avoid deadlocks. |
424 (when (or (null groups) ;All requests have been sent. | 313 (when (or (null groups) ;All requests have been sent. |
425 (zerop (% count nntp-maximum-request))) | 314 (zerop (% count nntp-maximum-request))) |
426 (nntp-accept-response) | 315 (nntp-accept-response) |
427 (while (progn | 316 (while (progn |
428 (goto-char last-point) | 317 (goto-char last-point) |
429 ;; Count replies. | 318 ;; Count replies. |
430 (while (re-search-forward "^[0-9]" nil t) | 319 (while (re-search-forward "^[0-9]" nil t) |
431 (incf received)) | 320 (setq received (1+ received))) |
432 (setq last-point (point)) | 321 (setq last-point (point)) |
433 (< received count)) | 322 (< received count)) |
434 (nntp-accept-response)))) | 323 (nntp-accept-response)))) |
435 | 324 |
436 ;; Wait for the reply from the final command. | 325 ;; Wait for the reply from the final command. |
437 (goto-char (point-max)) | 326 (when nntp-server-list-active-group |
438 (re-search-backward "^[0-9]" nil t) | 327 (goto-char (point-max)) |
439 (when (looking-at "^[23]") | 328 (re-search-backward "^[0-9]" nil t) |
440 (while (progn | 329 (when (looking-at "^[23]") |
441 (goto-char (point-max)) | 330 (while (progn |
442 (if (not nntp-server-list-active-group) | 331 (goto-char (- (point-max) 3)) |
443 (not (re-search-backward "\r?\n" (- (point) 3) t)) | 332 (not (looking-at "^\\.\r?\n"))) |
444 (not (re-search-backward "^\\.\r?\n" (- (point) 4) t)))) | 333 (nntp-accept-response)))) |
445 (nntp-accept-response))) | 334 |
446 | 335 ;; Now all replies are received. We remove CRs. |
447 ;; Now all replies are received. We remove CRs. | |
448 (goto-char (point-min)) | 336 (goto-char (point-min)) |
449 (while (search-forward "\r" nil t) | 337 (while (search-forward "\r" nil t) |
450 (replace-match "" t t)) | 338 (replace-match "" t t)) |
451 | 339 |
452 (if (not nntp-server-list-active-group) | 340 (if (not nntp-server-list-active-group) |
453 (progn | 341 'group |
454 (copy-to-buffer nntp-server-buffer (point-min) (point-max)) | |
455 'group) | |
456 ;; We have read active entries, so we just delete the | 342 ;; We have read active entries, so we just delete the |
457 ;; superfluous gunk. | 343 ;; superfluos gunk. |
458 (goto-char (point-min)) | 344 (goto-char (point-min)) |
459 (while (re-search-forward "^[.2-5]" nil t) | 345 (while (re-search-forward "^[.2-5]" nil t) |
460 (delete-region (match-beginning 0) | 346 (delete-region (match-beginning 0) |
461 (progn (forward-line 1) (point)))) | 347 (progn (forward-line 1) (point)))) |
462 (copy-to-buffer nntp-server-buffer (point-min) (point-max)) | |
463 'active)))) | 348 'active)))) |
464 | 349 |
465 (deffoo nntp-retrieve-articles (articles &optional group server) | 350 (deffoo nntp-open-server (server &optional defs connectionless) |
466 (nntp-possibly-change-group group server) | 351 "Open the virtual server SERVER. |
467 (save-excursion | 352 If CONNECTIONLESS is non-nil, don't attempt to connect to any physical |
468 (let ((number (length articles)) | 353 servers." |
469 (count 0) | 354 (nnheader-init-server-buffer) |
470 (received 0) | 355 ;; Called with just a port number as the defs. |
471 (last-point (point-min)) | 356 (when (or (stringp (car defs)) |
472 (buf (nntp-find-connection-buffer nntp-server-buffer)) | 357 (numberp (car defs))) |
473 (nntp-inhibit-erase t) | 358 (setq defs `((nntp-port-number ,(car defs))))) |
474 (map (apply 'vector articles)) | 359 (unless (assq 'nntp-address defs) |
475 (point 1) | 360 (setq defs (append defs `((nntp-address ,server))))) |
476 article alist) | 361 (nnoo-change-server 'nntp server defs) |
477 (set-buffer buf) | 362 (if (nntp-server-opened server) |
478 (erase-buffer) | 363 t |
479 ;; Send HEAD command. | 364 (or (nntp-server-opened server) |
480 (while (setq article (pop articles)) | 365 connectionless |
481 (nntp-send-command | 366 (prog2 |
482 nil | 367 (run-hooks 'nntp-prepare-server-hook) |
483 "ARTICLE" (if (numberp article) | 368 (nntp-open-server-semi-internal nntp-address nntp-port-number) |
484 (int-to-string article) | 369 (nnheader-insert ""))))) |
485 ;; `articles' is either a list of article numbers | 370 |
486 ;; or a list of article IDs. | 371 (deffoo nntp-close-server (&optional server) |
487 article)) | 372 "Close connection to SERVER." |
488 (incf count) | 373 (nntp-possibly-change-server nil server t) |
489 ;; Every 400 requests we have to read the stream in | 374 (unwind-protect |
490 ;; order to avoid deadlocks. | 375 (progn |
491 (when (or (null articles) ;All requests have been sent. | 376 ;; Un-set default sentinel function before closing connection. |
492 (zerop (% count nntp-maximum-request))) | 377 (and nntp-server-process |
493 (nntp-accept-response) | 378 (eq 'nntp-default-sentinel |
494 (while (progn | 379 (process-sentinel nntp-server-process)) |
495 (progn | 380 (set-process-sentinel nntp-server-process nil)) |
496 (set-buffer buf) | 381 ;; We cannot send QUIT command unless the process is running. |
497 (goto-char last-point)) | 382 (when (nntp-server-opened server) |
498 ;; Count replies. | 383 (nntp-send-command nil "QUIT") |
499 (while (nntp-next-result-arrived-p) | 384 ;; Give the QUIT time to arrive. |
500 (aset map received (cons (aref map received) (point))) | 385 (sleep-for 1))) |
501 (incf received)) | 386 (nntp-close-server-internal server))) |
502 (setq last-point (point)) | 387 |
503 (< received count)) | 388 (deffoo nntp-request-close () |
504 ;; If number of headers is greater than 100, give | 389 "Close all server connections." |
505 ;; informative messages. | 390 (let (proc) |
506 (and (numberp nntp-large-newsgroup) | 391 (while nntp-opened-connections |
507 (> number nntp-large-newsgroup) | 392 (when (setq proc (pop nntp-opened-connections)) |
508 (zerop (% received 20)) | 393 ;; Un-set default sentinel function before closing connection. |
509 (nnheader-message 6 "NNTP: Receiving articles... %d%%" | 394 (when (eq 'nntp-default-sentinel (process-sentinel proc)) |
510 (/ (* received 100) number))) | 395 (set-process-sentinel proc nil)) |
511 (nntp-accept-response)))) | 396 (condition-case () |
512 (and (numberp nntp-large-newsgroup) | 397 (process-send-string proc (concat "QUIT" nntp-end-of-line)) |
513 (> number nntp-large-newsgroup) | 398 (error nil)) |
514 (nnheader-message 6 "NNTP: Receiving headers...done")) | 399 ;; Give the QUIT time to reach the server before we close |
515 | 400 ;; down the process. |
516 ;; Now we have all the responses. We go through the results, | 401 (sleep-for 1) |
517 ;; washes it and copies it over to the server buffer. | 402 (delete-process proc))) |
518 (set-buffer nntp-server-buffer) | 403 (and nntp-async-buffer |
519 (erase-buffer) | 404 (buffer-name nntp-async-buffer) |
520 (mapcar | 405 (kill-buffer nntp-async-buffer)) |
521 (lambda (entry) | 406 (let ((alist (cddr (assq 'nntp nnoo-state-alist))) |
522 (narrow-to-region | 407 entry) |
523 (setq point (goto-char (point-max))) | 408 (while (setq entry (pop alist)) |
524 (progn | 409 (and (setq proc (cdr (assq 'nntp-async-buffer entry))) |
525 (insert-buffer-substring buf last-point (cdr entry)) | 410 (buffer-name proc) |
526 (point-max))) | 411 (kill-buffer proc)))) |
527 (nntp-decode-text) | 412 (nnoo-close-server 'nntp) |
528 (widen) | 413 (setq nntp-async-group-alist nil |
529 (cons (car entry) point)) | 414 nntp-async-articles nil))) |
530 map)))) | |
531 | |
532 (defun nntp-next-result-arrived-p () | |
533 (let ((point (point))) | |
534 (cond | |
535 ((looking-at "2") | |
536 (if (re-search-forward "\n.\r?\n" nil t) | |
537 t | |
538 (goto-char point) | |
539 nil)) | |
540 ((looking-at "[34]") | |
541 (forward-line 1) | |
542 t) | |
543 (t | |
544 nil)))) | |
545 | |
546 (defun nntp-try-list-active (group) | |
547 (nntp-list-active-group group) | |
548 (save-excursion | |
549 (set-buffer nntp-server-buffer) | |
550 (goto-char (point-min)) | |
551 (cond ((or (eobp) | |
552 (looking-at "5[0-9]+")) | |
553 (setq nntp-server-list-active-group nil)) | |
554 (t | |
555 (setq nntp-server-list-active-group t))))) | |
556 | |
557 (deffoo nntp-list-active-group (group &optional server) | |
558 "Return the active info on GROUP (which can be a regexp." | |
559 (nntp-possibly-change-group nil server) | |
560 (nntp-send-command "^.*\r?\n" "LIST ACTIVE" group)) | |
561 | |
562 (deffoo nntp-request-article (article &optional group server buffer command) | |
563 (nntp-possibly-change-group group server) | |
564 (when (nntp-send-command-and-decode | |
565 "\r?\n\\.\r?\n" "ARTICLE" | |
566 (if (numberp article) (int-to-string article) article)) | |
567 (when (and buffer | |
568 (not (equal buffer nntp-server-buffer))) | |
569 (save-excursion | |
570 (set-buffer nntp-server-buffer) | |
571 (copy-to-buffer buffer (point-min) (point-max)) | |
572 (nntp-find-group-and-number))) | |
573 (nntp-find-group-and-number))) | |
574 | |
575 (deffoo nntp-request-head (article &optional group server) | |
576 (nntp-possibly-change-group group server) | |
577 (when (nntp-send-command-and-decode | |
578 "\r?\n\\.\r?\n" "HEAD" | |
579 (if (numberp article) (int-to-string article) article)) | |
580 (nntp-find-group-and-number))) | |
581 | |
582 (deffoo nntp-request-body (article &optional group server) | |
583 (nntp-possibly-change-group group server) | |
584 (nntp-send-command-and-decode | |
585 "\r?\n\\.\r?\n" "BODY" | |
586 (if (numberp article) (int-to-string article) article))) | |
587 | |
588 (deffoo nntp-request-group (group &optional server dont-check) | |
589 (nntp-possibly-change-group nil server) | |
590 (when (nntp-send-command "^2.*\n" "GROUP" group) | |
591 (let ((entry (nntp-find-connection-entry nntp-server-buffer))) | |
592 (setcar (cddr entry) group)))) | |
593 | |
594 (deffoo nntp-close-group (group &optional server) | |
595 t) | |
596 | 415 |
597 (deffoo nntp-server-opened (&optional server) | 416 (deffoo nntp-server-opened (&optional server) |
598 "Say whether a connection to SERVER has been opened." | 417 "Say whether a connection to SERVER has been opened." |
599 (and (nnoo-current-server-p 'nntp server) | 418 (and (nnoo-current-server-p 'nntp server) |
600 nntp-server-buffer | 419 nntp-server-buffer |
601 (gnus-buffer-live-p nntp-server-buffer) | 420 (buffer-name nntp-server-buffer) |
602 (nntp-find-connection nntp-server-buffer))) | 421 nntp-server-process |
603 | 422 (memq (process-status nntp-server-process) '(open run)))) |
604 (deffoo nntp-open-server (server &optional defs connectionless) | 423 |
605 (nnheader-init-server-buffer) | 424 (deffoo nntp-status-message (&optional server) |
606 (if (nntp-server-opened server) | 425 "Return server status as a string." |
607 t | 426 (if (and nntp-status-string |
608 (when (or (stringp (car defs)) | 427 ;; NNN MESSAGE |
609 (numberp (car defs))) | 428 (string-match "[0-9][0-9][0-9][ \t]+\\([^\r]*\\).*$" |
610 (setq defs (cons (list 'nntp-port-number (car defs)) (cdr defs)))) | 429 nntp-status-string)) |
611 (unless (assq 'nntp-address defs) | 430 (substring nntp-status-string (match-beginning 1) (match-end 1)) |
612 (setq defs (append defs (list (list 'nntp-address server))))) | 431 ;; Empty message if nothing. |
613 (nnoo-change-server 'nntp server defs) | 432 (or nntp-status-string ""))) |
614 (unless connectionless | 433 |
615 (or (nntp-find-connection nntp-server-buffer) | 434 (deffoo nntp-request-article (id &optional group server buffer) |
616 (nntp-open-connection nntp-server-buffer))))) | 435 "Request article ID (Message-ID or number)." |
617 | 436 (nntp-possibly-change-server group server) |
618 (deffoo nntp-close-server (&optional server) | 437 |
619 (nntp-possibly-change-group nil server t) | 438 (let (found) |
620 (let (process) | 439 |
621 (while (setq process (car (pop nntp-connection-alist))) | 440 ;; First we see whether we can get the article from the async buffer. |
622 (when (memq (process-status process) '(open run)) | 441 (when (and (numberp id) |
623 (set-process-sentinel process nil) | 442 nntp-async-articles |
624 (nntp-send-string process "QUIT")) | 443 (memq id nntp-async-fetched)) |
625 (when (buffer-name (process-buffer process)) | 444 (save-excursion |
626 (kill-buffer (process-buffer process)))) | 445 (set-buffer nntp-async-buffer) |
627 (nnoo-close-server 'nntp))) | 446 (let ((opoint (point)) |
628 | 447 (art (if (numberp id) (int-to-string id) id)) |
629 (deffoo nntp-request-close () | 448 beg end) |
630 (let (process) | 449 (when (and (or (re-search-forward (concat "^2.. +" art) nil t) |
631 (while (setq process (pop nntp-connection-list)) | 450 (progn |
632 (when (memq (process-status process) '(open run)) | 451 (goto-char (point-min)) |
633 (set-process-sentinel process nil) | 452 (re-search-forward (concat "^2.. +" art) opoint t))) |
634 (ignore-errors | 453 (progn |
635 (nntp-send-string process "QUIT"))) | 454 (beginning-of-line) |
636 (when (buffer-name (process-buffer process)) | 455 (setq beg (point) |
637 (kill-buffer (process-buffer process)))))) | 456 end (re-search-forward "^\\.\r?\n" nil t)))) |
457 (setq found t) | |
458 (save-excursion | |
459 (set-buffer (or buffer nntp-server-buffer)) | |
460 (erase-buffer) | |
461 (insert-buffer-substring nntp-async-buffer beg end) | |
462 (let ((nntp-server-buffer (current-buffer))) | |
463 (nntp-decode-text))) | |
464 (delete-region beg end) | |
465 (when nntp-async-articles | |
466 (nntp-async-fetch-articles id)))))) | |
467 | |
468 (if found | |
469 id | |
470 ;; The article was not in the async buffer, so we fetch it now. | |
471 (unwind-protect | |
472 (progn | |
473 (if buffer (set-process-buffer nntp-server-process buffer)) | |
474 (let ((nntp-server-buffer (or buffer nntp-server-buffer)) | |
475 (art (or (and (numberp id) (int-to-string id)) id))) | |
476 (prog1 | |
477 (and (nntp-send-command | |
478 ;; A bit odd regexp to ensure working over rlogin. | |
479 "^\\.\r?\n" "ARTICLE" art) | |
480 (if (numberp id) | |
481 (cons nntp-current-group id) | |
482 ;; We find out what the article number was. | |
483 (nntp-find-group-and-number))) | |
484 (nntp-decode-text) | |
485 (and nntp-async-articles (nntp-async-fetch-articles id))))) | |
486 (when buffer | |
487 (set-process-buffer nntp-server-process nntp-server-buffer)))))) | |
488 | |
489 (deffoo nntp-request-body (id &optional group server) | |
490 "Request body of article ID (Message-ID or number)." | |
491 (nntp-possibly-change-server group server) | |
492 (prog1 | |
493 ;; If NEmacs, end of message may look like: "\256\215" (".^M") | |
494 (nntp-send-command | |
495 "^\\.\r?\n" "BODY" (or (and (numberp id) (int-to-string id)) id)) | |
496 (nntp-decode-text))) | |
497 | |
498 (deffoo nntp-request-head (id &optional group server) | |
499 "Request head of article ID (Message-ID or number)." | |
500 (nntp-possibly-change-server group server) | |
501 (prog1 | |
502 (when (nntp-send-command | |
503 "^\\.\r?\n" "HEAD" (if (numberp id) (int-to-string id) id)) | |
504 (if (numberp id) id | |
505 ;; We find out what the article number was. | |
506 (nntp-find-group-and-number))) | |
507 (nntp-decode-text) | |
508 (save-excursion | |
509 (set-buffer nntp-server-buffer) | |
510 (nnheader-fold-continuation-lines)))) | |
511 | |
512 (deffoo nntp-request-stat (id &optional group server) | |
513 "Request STAT of article ID (Message-ID or number)." | |
514 (nntp-possibly-change-server group server) | |
515 (nntp-send-command | |
516 "^[23].*\r?\n" "STAT" (or (and (numberp id) (int-to-string id)) id))) | |
517 | |
518 (deffoo nntp-request-type (group &optional article) | |
519 'news) | |
520 | |
521 (deffoo nntp-request-group (group &optional server dont-check) | |
522 "Select GROUP." | |
523 (nntp-possibly-change-server nil server) | |
524 (setq nntp-current-group | |
525 (when (nntp-send-command "^2.*\r?\n" "GROUP" group) | |
526 group))) | |
527 | |
528 (deffoo nntp-request-asynchronous (group &optional server articles) | |
529 "Enable pre-fetch in GROUP." | |
530 (when nntp-async-articles | |
531 (nntp-async-request-group group)) | |
532 (when nntp-async-number | |
533 (if (not (or (nntp-async-server-opened) | |
534 (nntp-async-open-server))) | |
535 ;; Couldn't open the second connection | |
536 (progn | |
537 (message "Can't open second connection to %s" nntp-address) | |
538 (ding) | |
539 (setq nntp-async-articles nil) | |
540 (sit-for 2)) | |
541 ;; We opened the second connection (or it was opened already). | |
542 (setq nntp-async-articles articles) | |
543 (setq nntp-async-fetched nil) | |
544 ;; Clear any old data. | |
545 (save-excursion | |
546 (set-buffer nntp-async-buffer) | |
547 (erase-buffer)) | |
548 ;; Select the correct current group on this server. | |
549 (nntp-async-send-strings "GROUP" group) | |
550 t))) | |
551 | |
552 (deffoo nntp-list-active-group (group &optional server) | |
553 "Return the active info on GROUP (which can be a regexp." | |
554 (nntp-possibly-change-server group server) | |
555 (nntp-send-command "^.*\r?\n" "LIST ACTIVE" group)) | |
556 | |
557 (deffoo nntp-request-group-description (group &optional server) | |
558 "Get the description of GROUP." | |
559 (nntp-possibly-change-server nil server) | |
560 (prog1 | |
561 (nntp-send-command "^.*\r?\n" "XGTITLE" group) | |
562 (nntp-decode-text))) | |
563 | |
564 (deffoo nntp-close-group (group &optional server) | |
565 "Close GROUP." | |
566 (setq nntp-current-group nil) | |
567 t) | |
638 | 568 |
639 (deffoo nntp-request-list (&optional server) | 569 (deffoo nntp-request-list (&optional server) |
640 (nntp-possibly-change-group nil server) | 570 "List all active groups." |
641 (nntp-send-command-and-decode "\r?\n\\.\r?\n" "LIST")) | 571 (nntp-possibly-change-server nil server) |
572 (prog1 | |
573 (nntp-send-command "^\\.\r?\n" "LIST") | |
574 (nntp-decode-text))) | |
642 | 575 |
643 (deffoo nntp-request-list-newsgroups (&optional server) | 576 (deffoo nntp-request-list-newsgroups (&optional server) |
644 (nntp-possibly-change-group nil server) | 577 "Get descriptions on all groups on SERVER." |
645 (nntp-send-command "\r?\n\\.\r?\n" "LIST NEWSGROUPS")) | 578 (nntp-possibly-change-server nil server) |
579 (prog1 | |
580 (nntp-send-command "^\\.\r?\n" "LIST NEWSGROUPS") | |
581 (nntp-decode-text))) | |
646 | 582 |
647 (deffoo nntp-request-newgroups (date &optional server) | 583 (deffoo nntp-request-newgroups (date &optional server) |
648 (nntp-possibly-change-group nil server) | 584 "List groups that have arrived since DATE." |
649 (save-excursion | 585 (nntp-possibly-change-server nil server) |
650 (set-buffer nntp-server-buffer) | 586 (let* ((date (timezone-parse-date date)) |
651 (let* ((date (timezone-parse-date date)) | 587 (time-string |
652 (time-string | 588 (format "%s%02d%02d %s%s%s" |
653 (format "%s%02d%02d %s%s%s" | 589 (substring (aref date 0) 2) (string-to-int (aref date 1)) |
654 (substring (aref date 0) 2) (string-to-int (aref date 1)) | 590 (string-to-int (aref date 2)) (substring (aref date 3) 0 2) |
655 (string-to-int (aref date 2)) (substring (aref date 3) 0 2) | 591 (substring |
656 (substring | 592 (aref date 3) 3 5) (substring (aref date 3) 6 8)))) |
657 (aref date 3) 3 5) (substring (aref date 3) 6 8)))) | 593 (prog1 |
658 (prog1 | 594 (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string) |
659 (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string) | 595 (nntp-decode-text)))) |
660 (nntp-decode-text))))) | 596 |
597 (deffoo nntp-request-list-distributions (&optional server) | |
598 "List distributions." | |
599 (nntp-possibly-change-server nil server) | |
600 (prog1 | |
601 (nntp-send-command "^\\.\r?\n" "LIST DISTRIBUTIONS") | |
602 (nntp-decode-text))) | |
603 | |
604 (deffoo nntp-request-last (&optional group server) | |
605 "Decrease the current article pointer." | |
606 (nntp-possibly-change-server group server) | |
607 (nntp-send-command "^[23].*\r?\n" "LAST")) | |
608 | |
609 (deffoo nntp-request-next (&optional group server) | |
610 "Advance the current article pointer." | |
611 (nntp-possibly-change-server group server) | |
612 (nntp-send-command "^[23].*\r?\n" "NEXT")) | |
661 | 613 |
662 (deffoo nntp-request-post (&optional server) | 614 (deffoo nntp-request-post (&optional server) |
663 (nntp-possibly-change-group nil server) | 615 "Post the current buffer." |
616 (nntp-possibly-change-server nil server) | |
664 (when (nntp-send-command "^[23].*\r?\n" "POST") | 617 (when (nntp-send-command "^[23].*\r?\n" "POST") |
665 (nntp-send-buffer "^[23].*\n"))) | 618 (nnheader-insert "") |
666 | 619 (nntp-encode-text) |
667 (deffoo nntp-request-type (group article) | 620 (nntp-send-region-to-server (point-min) (point-max)) |
668 'news) | 621 ;; 1.2a NNTP's post command is buggy. "^M" (\r) is not |
669 | 622 ;; appended to end of the status message. |
670 (deffoo nntp-asynchronous-p () | 623 (nntp-wait-for-response "^[23].*\n"))) |
671 t) | 624 |
672 | 625 ;;; Internal functions. |
673 ;;; Hooky functions. | |
674 | 626 |
675 (defun nntp-send-mode-reader () | 627 (defun nntp-send-mode-reader () |
676 "Send the MODE READER command to the nntp server. | 628 "Send the MODE READER command to the nntp server. |
677 This function is supposed to be called from `nntp-server-opened-hook'. | 629 This function is supposed to be called from `nntp-server-opened-hook'. |
678 It will make innd servers spawn an nnrpd process to allow actual article | 630 It will make innd servers spawn an nnrpd process to allow actual article |
681 | 633 |
682 (defun nntp-send-nosy-authinfo () | 634 (defun nntp-send-nosy-authinfo () |
683 "Send the AUTHINFO to the nntp server. | 635 "Send the AUTHINFO to the nntp server. |
684 This function is supposed to be called from `nntp-server-opened-hook'. | 636 This function is supposed to be called from `nntp-server-opened-hook'. |
685 It will prompt for a password." | 637 It will prompt for a password." |
686 (nntp-send-command | 638 (nntp-send-command "^.*\r?\n" "AUTHINFO USER" |
687 "^.*\r?\n" "AUTHINFO USER" | 639 (read-string "NNTP user name: ")) |
688 (read-string (format "NNTP (%s) user name: " nntp-address))) | 640 (nntp-send-command "^.*\r?\n" "AUTHINFO PASS" |
689 (nntp-send-command | 641 (read-string "NNTP password: "))) |
690 "^.*\r?\n" "AUTHINFO PASS" | |
691 (nnmail-read-passwd "NNTP (%s) password: " nntp-address))) | |
692 | 642 |
693 (defun nntp-send-authinfo () | 643 (defun nntp-send-authinfo () |
694 "Send the AUTHINFO to the nntp server. | 644 "Send the AUTHINFO to the nntp server. |
695 This function is supposed to be called from `nntp-server-opened-hook'. | 645 This function is supposed to be called from `nntp-server-opened-hook'. |
696 It will prompt for a password." | 646 It will prompt for a password." |
697 (nntp-send-command "^.*\r?\n" "AUTHINFO USER" (user-login-name)) | 647 (nntp-send-command "^.*\r?\n" "AUTHINFO USER" (user-login-name)) |
698 (nntp-send-command | 648 (nntp-send-command "^.*\r?\n" "AUTHINFO PASS" |
699 "^.*\r?\n" "AUTHINFO PASS" | 649 (read-string "NNTP password: "))) |
700 (nnmail-read-passwd (format "NNTP (%s) password: " nntp-address)))) | |
701 | 650 |
702 (defun nntp-send-authinfo-from-file () | 651 (defun nntp-send-authinfo-from-file () |
703 "Send the AUTHINFO to the nntp server. | 652 "Send the AUTHINFO to the nntp server. |
704 This function is supposed to be called from `nntp-server-opened-hook'." | 653 This function is supposed to be called from `nntp-server-opened-hook'. |
654 It will prompt for a password." | |
705 (when (file-exists-p "~/.nntp-authinfo") | 655 (when (file-exists-p "~/.nntp-authinfo") |
706 (nnheader-temp-write nil | 656 (save-excursion |
657 (set-buffer (get-buffer-create " *authinfo*")) | |
658 (buffer-disable-undo (current-buffer)) | |
659 (erase-buffer) | |
707 (insert-file-contents "~/.nntp-authinfo") | 660 (insert-file-contents "~/.nntp-authinfo") |
708 (goto-char (point-min)) | 661 (goto-char (point-min)) |
709 (nntp-send-command "^.*\r?\n" "AUTHINFO USER" (user-login-name)) | 662 (nntp-send-command "^.*\r?\n" "AUTHINFO USER" (user-login-name)) |
710 (nntp-send-command | 663 (nntp-send-command |
711 "^.*\r?\n" "AUTHINFO PASS" | 664 "^.*\r?\n" "AUTHINFO PASS" |
712 (buffer-substring (point) (progn (end-of-line) (point))))))) | 665 (buffer-substring (point) (progn (end-of-line) (point)))) |
713 | 666 (kill-buffer (current-buffer))))) |
714 ;;; Internal functions. | 667 |
715 | 668 (defun nntp-default-sentinel (proc status) |
716 (defun nntp-make-process-buffer (buffer) | 669 "Default sentinel function for NNTP server process." |
717 "Create a new, fresh buffer usable for nntp process connections." | 670 (let ((servers (cddr (assq 'nntp nnoo-state-alist))) |
671 server) | |
672 ;; Go through the alist of server names and find the name of the | |
673 ;; server that the process that sent the signal is connected to. | |
674 ;; If you get my drift. | |
675 (if (equal proc nntp-server-process) | |
676 (setq server nntp-address) | |
677 (while (and servers | |
678 (not (equal proc (cdr (assq 'nntp-server-process | |
679 (car servers)))))) | |
680 (setq servers (cdr servers))) | |
681 (setq server (caar servers))) | |
682 (when (and server | |
683 nntp-warn-about-losing-connection) | |
684 (nnheader-message 3 "nntp: Connection closed to server %s" server) | |
685 (setq nntp-current-group "") | |
686 (ding)))) | |
687 | |
688 (defun nntp-kill-connection (server) | |
689 "Choke the connection to SERVER." | |
690 (let ((proc (cdr (assq 'nntp-server-process | |
691 (assoc server (cddr | |
692 (assq 'nntp nnoo-state-alist))))))) | |
693 (when proc | |
694 (delete-process (process-name proc))) | |
695 (nntp-close-server server) | |
696 (nnheader-report | |
697 'nntp (message "Connection timed out to server %s" server)) | |
698 (ding) | |
699 (sit-for 1))) | |
700 | |
701 ;; Encoding and decoding of NNTP text. | |
702 | |
703 (defun nntp-decode-text () | |
704 "Decode text transmitted by NNTP. | |
705 0. Delete status line. | |
706 1. Delete `^M' at end of line. | |
707 2. Delete `.' at end of buffer (end of text mark). | |
708 3. Delete `.' at beginning of line." | |
718 (save-excursion | 709 (save-excursion |
719 (set-buffer | 710 (set-buffer nntp-server-buffer) |
720 (generate-new-buffer | 711 ;; Insert newline at end of buffer. |
721 (format " *server %s %s %s*" | 712 (goto-char (point-max)) |
722 nntp-address nntp-port-number | 713 (or (bolp) (insert "\n")) |
723 (buffer-name (get-buffer buffer))))) | 714 ;; Delete status line. |
724 (buffer-disable-undo (current-buffer)) | 715 (delete-region (goto-char (point-min)) (progn (forward-line 1) (point))) |
725 (set (make-local-variable 'after-change-functions) nil) | 716 ;; Delete `^M's. |
726 (set (make-local-variable 'nntp-process-wait-for) nil) | 717 (while (search-forward "\r" nil t) |
727 (set (make-local-variable 'nntp-process-callback) nil) | 718 (replace-match "" t t)) |
728 (set (make-local-variable 'nntp-process-to-buffer) nil) | 719 ;; Delete `.' at end of the buffer (end of text mark). |
729 (set (make-local-variable 'nntp-process-start-point) nil) | |
730 (set (make-local-variable 'nntp-process-decode) nil) | |
731 (current-buffer))) | |
732 | |
733 (defun nntp-open-connection (buffer) | |
734 "Open a connection to PORT on ADDRESS delivering output to BUFFER." | |
735 (run-hooks 'nntp-prepare-server-hook) | |
736 (let* ((pbuffer (nntp-make-process-buffer buffer)) | |
737 (process | |
738 (condition-case () | |
739 (funcall nntp-open-connection-function pbuffer) | |
740 (error nil) | |
741 (quit nil)))) | |
742 (when process | |
743 (process-kill-without-query process) | |
744 (nntp-wait-for process "^.*\n" buffer nil t) | |
745 (if (memq (process-status process) '(open run)) | |
746 (prog1 | |
747 (caar (push (list process buffer nil) nntp-connection-alist)) | |
748 (push process nntp-connection-list) | |
749 (save-excursion | |
750 (set-buffer pbuffer) | |
751 (nntp-read-server-type) | |
752 (erase-buffer) | |
753 (set-buffer nntp-server-buffer) | |
754 (let ((nnheader-callback-function nil)) | |
755 (run-hooks 'nntp-server-opened-hook)))) | |
756 (when (buffer-name (process-buffer process)) | |
757 (kill-buffer (process-buffer process))) | |
758 nil)))) | |
759 | |
760 (defun nntp-open-network-stream (buffer) | |
761 (open-network-stream "nntpd" buffer nntp-address nntp-port-number)) | |
762 | |
763 (defun nntp-read-server-type () | |
764 "Find out what the name of the server we have connected to is." | |
765 ;; Wait for the status string to arrive. | |
766 (setq nntp-server-type (buffer-string)) | |
767 (let ((alist nntp-server-action-alist) | |
768 (case-fold-search t) | |
769 entry) | |
770 ;; Run server-specific commands. | |
771 (while alist | |
772 (setq entry (pop alist)) | |
773 (when (string-match (car entry) nntp-server-type) | |
774 (if (and (listp (cadr entry)) | |
775 (not (eq 'lambda (caadr entry)))) | |
776 (eval (cadr entry)) | |
777 (funcall (cadr entry))))))) | |
778 | |
779 (defun nntp-after-change-function-callback (beg end len) | |
780 (when nntp-process-callback | |
781 (save-match-data | |
782 (if (and (= beg (point-min)) | |
783 (memq (char-after beg) '(?4 ?5))) | |
784 ;; Report back error messages. | |
785 (save-excursion | |
786 (goto-char beg) | |
787 (if (looking-at "480") | |
788 (funcall nntp-authinfo-function) | |
789 (nntp-snarf-error-message) | |
790 (funcall nntp-process-callback nil))) | |
791 (goto-char end) | |
792 (when (and (> (point) nntp-process-start-point) | |
793 (re-search-backward nntp-process-wait-for | |
794 nntp-process-start-point t)) | |
795 (when (buffer-name (get-buffer nntp-process-to-buffer)) | |
796 (let ((cur (current-buffer)) | |
797 (start nntp-process-start-point)) | |
798 (save-excursion | |
799 (set-buffer (get-buffer nntp-process-to-buffer)) | |
800 (goto-char (point-max)) | |
801 (let ((b (point))) | |
802 (insert-buffer-substring cur start) | |
803 (narrow-to-region b (point-max)) | |
804 (nntp-decode-text) | |
805 (widen))))) | |
806 (goto-char end) | |
807 (let ((callback nntp-process-callback) | |
808 (nntp-inside-change-function t)) | |
809 (setq nntp-process-callback nil) | |
810 (save-excursion | |
811 (funcall callback (buffer-name | |
812 (get-buffer nntp-process-to-buffer)))))))))) | |
813 | |
814 (defun nntp-snarf-error-message () | |
815 "Save the error message in the current buffer." | |
816 (let ((message (buffer-string))) | |
817 (while (string-match "[\r\n]+" message) | |
818 (setq message (replace-match " " t t message))) | |
819 (nnheader-report 'nntp message) | |
820 message)) | |
821 | |
822 (defun nntp-accept-process-output (process) | |
823 "Wait for output from PROCESS and message some dots." | |
824 (save-excursion | |
825 (set-buffer (or (nntp-find-connection-buffer nntp-server-buffer) | |
826 nntp-server-buffer)) | |
827 (let ((len (/ (point-max) 1024)) | |
828 message-log-max) | |
829 (unless (< len 10) | |
830 (setq nntp-have-messaged t) | |
831 (nnheader-message 7 "nntp read: %dk" len))) | |
832 (accept-process-output process 1))) | |
833 | |
834 (defun nntp-accept-response () | |
835 "Wait for output from the process that outputs to BUFFER." | |
836 (nntp-accept-process-output (nntp-find-connection nntp-server-buffer))) | |
837 | |
838 (defun nntp-possibly-change-group (group server &optional connectionless) | |
839 (let ((nnheader-callback-function nil)) | |
840 (when server | |
841 (or (nntp-server-opened server) | |
842 (nntp-open-server server nil connectionless))) | |
843 | |
844 (unless connectionless | |
845 (or (nntp-find-connection nntp-server-buffer) | |
846 (nntp-open-connection nntp-server-buffer)))) | |
847 | |
848 (when group | |
849 (let ((entry (nntp-find-connection-entry nntp-server-buffer))) | |
850 (when (not (equal group (caddr entry))) | |
851 (save-excursion | |
852 (set-buffer (process-buffer (car entry))) | |
853 (erase-buffer) | |
854 (nntp-send-string (car entry) (concat "GROUP " group)) | |
855 (nntp-wait-for-string "^2.*\n") | |
856 (setcar (cddr entry) group) | |
857 (erase-buffer)))))) | |
858 | |
859 (defun nntp-decode-text (&optional cr-only) | |
860 "Decode the text in the current buffer." | |
861 (goto-char (point-min)) | |
862 (while (search-forward "\r" nil t) | |
863 (delete-char -1)) | |
864 (unless cr-only | |
865 ;; Remove trailing ".\n" end-of-transfer marker. | |
866 (goto-char (point-max)) | 720 (goto-char (point-max)) |
867 (forward-line -1) | 721 (forward-line -1) |
868 (when (looking-at ".\n") | 722 (when (looking-at "^\\.\n") |
869 (delete-char 2)) | 723 (delete-region (point) (progn (forward-line 1) (point)))) |
870 ;; Delete status line. | 724 ;; Replace `..' at beginning of line with `.'. |
871 (goto-char (point-min)) | 725 (goto-char (point-min)) |
872 (delete-region (point) (progn (forward-line 1) (point))) | 726 ;; (replace-regexp "^\\.\\." ".") |
873 ;; Remove "." -> ".." encoding. | |
874 (while (search-forward "\n.." nil t) | 727 (while (search-forward "\n.." nil t) |
875 (delete-char -1)))) | 728 (delete-char -1)))) |
876 | 729 |
877 (defun nntp-encode-text () | 730 (defun nntp-encode-text () |
878 "Encode the text in the current buffer." | 731 "Encode text in current buffer for NNTP transmission. |
732 1. Insert `.' at beginning of line. | |
733 2. Insert `.' at end of buffer (end of text mark)." | |
879 (save-excursion | 734 (save-excursion |
880 ;; Replace "." at beginning of line with "..". | 735 ;; Replace `.' at beginning of line with `..'. |
881 (goto-char (point-min)) | 736 (goto-char (point-min)) |
882 (while (re-search-forward "^\\." nil t) | 737 (while (re-search-forward "^\\." nil t) |
883 (insert ".")) | 738 (insert ".")) |
884 (goto-char (point-max)) | 739 (goto-char (point-max)) |
885 ;; Insert newline at the end of the buffer. | 740 ;; Insert newline at end of buffer. |
886 (unless (bolp) | 741 (or (bolp) (insert "\n")) |
887 (insert "\n")) | 742 ;(goto-char (point-min)) |
743 ;(while (not (eobp)) | |
744 ; (end-of-line) | |
745 ; (insert "\r") | |
746 ; (forward-line 1)) | |
888 ;; Insert `.' at end of buffer (end of text mark). | 747 ;; Insert `.' at end of buffer (end of text mark). |
889 (goto-char (point-max)) | 748 (goto-char (point-max)) |
890 (insert "." nntp-end-of-line))) | 749 (insert "." nntp-end-of-line))) |
891 | 750 |
751 | |
752 | |
753 ;;; | |
754 ;;; Synchronous Communication with NNTP servers. | |
755 ;;; | |
756 | |
757 (defvar nntp-retry-command) | |
758 | |
759 (defun nntp-send-command (response cmd &rest args) | |
760 "Wait for server RESPONSE after sending CMD and optional ARGS to server." | |
761 (let ((timer | |
762 (and nntp-command-timeout | |
763 (nnheader-run-at-time | |
764 nntp-command-timeout nil 'nntp-kill-command | |
765 (nnoo-current-server 'nntp)))) | |
766 (nntp-retry-command t) | |
767 result) | |
768 (unwind-protect | |
769 (save-excursion | |
770 (while nntp-retry-command | |
771 (setq nntp-retry-command nil) | |
772 ;; Clear communication buffer. | |
773 (set-buffer nntp-server-buffer) | |
774 (widen) | |
775 (erase-buffer) | |
776 (if nntp-retry-on-break | |
777 (condition-case () | |
778 (progn | |
779 (apply 'nntp-send-strings-to-server cmd args) | |
780 (setq result | |
781 (if response | |
782 (nntp-wait-for-response response) | |
783 t))) | |
784 (quit (setq nntp-retry-command t))) | |
785 (apply 'nntp-send-strings-to-server cmd args) | |
786 (setq result | |
787 (if response | |
788 (nntp-wait-for-response response) | |
789 t)))) | |
790 result) | |
791 (when timer | |
792 (nnheader-cancel-timer timer))))) | |
793 | |
794 (defun nntp-kill-command (server) | |
795 "Kill and restart the connection to SERVER." | |
796 (let ((proc (cdr (assq | |
797 'nntp-server-process | |
798 (assoc server (cddr (assq 'nntp nnoo-state-alist))))))) | |
799 (when proc | |
800 (delete-process (process-name proc))) | |
801 (nntp-close-server server) | |
802 (nntp-open-server server) | |
803 (when nntp-current-group | |
804 (nntp-request-group nntp-current-group)) | |
805 (setq nntp-retry-command t))) | |
806 | |
807 (defun nntp-send-command-old (response cmd &rest args) | |
808 "Wait for server RESPONSE after sending CMD and optional ARGS to server." | |
809 (save-excursion | |
810 ;; Clear communication buffer. | |
811 (set-buffer nntp-server-buffer) | |
812 (erase-buffer) | |
813 (apply 'nntp-send-strings-to-server cmd args) | |
814 (if response | |
815 (nntp-wait-for-response response) | |
816 t))) | |
817 | |
818 (defun nntp-wait-for-response (regexp &optional slow) | |
819 "Wait for server response which matches REGEXP." | |
820 (save-excursion | |
821 (let ((status t) | |
822 (wait t) | |
823 (dotnum 0) ;Number of "." being displayed. | |
824 (dotsize ;How often "." displayed. | |
825 (if (numberp nntp-debug-read) nntp-debug-read 10000))) | |
826 (set-buffer nntp-server-buffer) | |
827 ;; Wait for status response (RFC977). | |
828 ;; 1xx - Informative message. | |
829 ;; 2xx - Command ok. | |
830 ;; 3xx - Command ok so far, send the rest of it. | |
831 ;; 4xx - Command was correct, but couldn't be performed for some | |
832 ;; reason. | |
833 ;; 5xx - Command unimplemented, or incorrect, or a serious | |
834 ;; program error occurred. | |
835 (nntp-accept-response) | |
836 (while wait | |
837 (goto-char (point-min)) | |
838 (if slow | |
839 (progn | |
840 (cond ((re-search-forward "^[23][0-9][0-9]" nil t) | |
841 (setq wait nil)) | |
842 ((re-search-forward "^[45][0-9][0-9]" nil t) | |
843 (setq status nil) | |
844 (setq wait nil)) | |
845 (t (nntp-accept-response))) | |
846 (if (not wait) (delete-region (point-min) | |
847 (progn (beginning-of-line) | |
848 (point))))) | |
849 (cond ((looking-at "[23]") | |
850 (setq wait nil)) | |
851 ((looking-at "[45]") | |
852 (setq status nil) | |
853 (setq wait nil)) | |
854 (t (nntp-accept-response))))) | |
855 ;; Save status message. | |
856 (end-of-line) | |
857 (setq nntp-status-string | |
858 (nnheader-replace-chars-in-string | |
859 (buffer-substring (point-min) (point)) ?\r ? )) | |
860 (when status | |
861 (setq wait t) | |
862 (while wait | |
863 (goto-char (point-max)) | |
864 (if (bolp) (forward-line -1) (beginning-of-line)) | |
865 (if (looking-at regexp) | |
866 (setq wait nil) | |
867 (when nntp-debug-read | |
868 (let ((newnum (/ (buffer-size) dotsize)) | |
869 (message-log-max nil)) | |
870 (unless (= dotnum newnum) | |
871 (setq dotnum newnum) | |
872 (nnheader-message 7 "NNTP: Reading %s" | |
873 (make-string dotnum ?.))))) | |
874 (nntp-accept-response))) | |
875 ;; Remove "...". | |
876 (when (and nntp-debug-read (> dotnum 0)) | |
877 (message "")) | |
878 ;; Successfully received server response. | |
879 t)))) | |
880 | |
881 | |
882 | |
883 ;;; | |
884 ;;; Low-Level Interface to NNTP Server. | |
885 ;;; | |
886 | |
887 (defun nntp-find-group-and-number () | |
888 (save-excursion | |
889 (save-restriction | |
890 (set-buffer nntp-server-buffer) | |
891 (narrow-to-region (goto-char (point-min)) | |
892 (or (search-forward "\n\n" nil t) (point-max))) | |
893 (goto-char (point-min)) | |
894 ;; We first find the number by looking at the status line. | |
895 (let ((number (and (looking-at "2[0-9][0-9] +\\([0-9]+\\) ") | |
896 (string-to-int | |
897 (buffer-substring (match-beginning 1) | |
898 (match-end 1))))) | |
899 group newsgroups xref) | |
900 (and number (zerop number) (setq number nil)) | |
901 ;; Then we find the group name. | |
902 (setq group | |
903 (cond | |
904 ;; If there is only one group in the Newsgroups header, | |
905 ;; then it seems quite likely that this article comes | |
906 ;; from that group, I'd say. | |
907 ((and (setq newsgroups (mail-fetch-field "newsgroups")) | |
908 (not (string-match "," newsgroups))) | |
909 newsgroups) | |
910 ;; If there is more than one group in the Newsgroups | |
911 ;; header, then the Xref header should be filled out. | |
912 ;; We hazard a guess that the group that has this | |
913 ;; article number in the Xref header is the one we are | |
914 ;; looking for. This might very well be wrong if this | |
915 ;; article happens to have the same number in several | |
916 ;; groups, but that's life. | |
917 ((and (setq xref (mail-fetch-field "xref")) | |
918 number | |
919 (string-match (format "\\([^ :]+\\):%d" number) xref)) | |
920 (substring xref (match-beginning 1) (match-end 1))) | |
921 (t ""))) | |
922 (when (string-match "\r" group) | |
923 (setq group (substring group 0 (match-beginning 0)))) | |
924 (cons group number))))) | |
925 | |
892 (defun nntp-retrieve-headers-with-xover (articles &optional fetch-old) | 926 (defun nntp-retrieve-headers-with-xover (articles &optional fetch-old) |
893 (set-buffer nntp-server-buffer) | |
894 (erase-buffer) | 927 (erase-buffer) |
895 (cond | 928 (cond |
896 | 929 |
897 ;; This server does not talk NOV. | 930 ;; This server does not talk NOV. |
898 ((not nntp-server-xover) | 931 ((not nntp-server-xover) |
899 nil) | 932 nil) |
900 | 933 |
901 ;; We don't care about gaps. | 934 ;; We don't care about gaps. |
902 ((or (not nntp-nov-gap) | 935 ((or (not nntp-nov-gap) |
903 fetch-old) | 936 fetch-old) |
904 (nntp-send-xover-command | 937 (nntp-send-xover-command |
905 (if fetch-old | 938 (if fetch-old |
906 (if (numberp fetch-old) | 939 (if (numberp fetch-old) |
907 (max 1 (- (car articles) fetch-old)) | 940 (max 1 (- (car articles) fetch-old)) |
908 1) | 941 1) |
909 (car articles)) | 942 (car articles)) |
910 (car (last articles)) 'wait) | 943 (nntp-last-element articles) 'wait) |
911 | 944 |
912 (goto-char (point-min)) | 945 (goto-char (point-min)) |
913 (when (looking-at "[1-5][0-9][0-9] ") | 946 (when (looking-at "[1-5][0-9][0-9] ") |
914 (delete-region (point) (progn (forward-line 1) (point)))) | 947 (delete-region (point) (progn (forward-line 1) (point)))) |
915 (while (search-forward "\r" nil t) | 948 (while (search-forward "\r" nil t) |
926 ;; have gotten all we asked for. | 959 ;; have gotten all we asked for. |
927 ((numberp nntp-nov-gap) | 960 ((numberp nntp-nov-gap) |
928 (let ((count 0) | 961 (let ((count 0) |
929 (received 0) | 962 (received 0) |
930 (last-point (point-min)) | 963 (last-point (point-min)) |
931 (buf nntp-server-buffer) | 964 (buf (current-buffer)) |
932 ;;(process-buffer (nntp-find-connection (current-buffer)))) | |
933 first) | 965 first) |
934 ;; We have to check `nntp-server-xover'. If it gets set to nil, | 966 ;; We have to check `nntp-server-xover'. If it gets set to nil, |
935 ;; that means that the server does not understand XOVER, but we | 967 ;; that means that the server does not understand XOVER, but we |
936 ;; won't know that until we try. | 968 ;; won't know that until we try. |
937 (while (and nntp-server-xover articles) | 969 (while (and nntp-server-xover articles) |
938 (setq first (car articles)) | 970 (setq first (car articles)) |
939 ;; Search forward until we find a gap, or until we run out of | 971 ;; Search forward until we find a gap, or until we run out of |
940 ;; articles. | 972 ;; articles. |
941 (while (and (cdr articles) | 973 (while (and (cdr articles) |
942 (< (- (nth 1 articles) (car articles)) nntp-nov-gap)) | 974 (< (- (nth 1 articles) (car articles)) nntp-nov-gap)) |
943 (setq articles (cdr articles))) | 975 (setq articles (cdr articles))) |
944 | 976 |
945 (when (nntp-send-xover-command first (car articles)) | 977 (when (nntp-send-xover-command first (car articles)) |
946 (setq articles (cdr articles) | 978 (setq articles (cdr articles) |
948 | 980 |
949 ;; Every 400 requests we have to read the stream in | 981 ;; Every 400 requests we have to read the stream in |
950 ;; order to avoid deadlocks. | 982 ;; order to avoid deadlocks. |
951 (when (or (null articles) ;All requests have been sent. | 983 (when (or (null articles) ;All requests have been sent. |
952 (zerop (% count nntp-maximum-request))) | 984 (zerop (% count nntp-maximum-request))) |
953 (accept-process-output) | 985 (accept-process-output nntp-server-process 1) |
954 ;; On some Emacs versions the preceding function has | 986 ;; On some Emacs versions the preceding function has |
955 ;; a tendency to change the buffer. Perhaps. It's | 987 ;; a tendency to change the buffer. Perhaps. It's |
956 ;; quite difficult to reproduce, because it only | 988 ;; quite difficult to reproduce, because it only |
957 ;; seems to happen once in a blue moon. | 989 ;; seems to happen once in a blue moon. |
958 (set-buffer buf) | 990 (set-buffer buf) |
959 (while (progn | 991 (while (progn |
960 (goto-char last-point) | 992 (goto-char last-point) |
961 ;; Count replies. | 993 ;; Count replies. |
962 (while (re-search-forward "^[0-9][0-9][0-9] " nil t) | 994 (while (re-search-forward "^[0-9][0-9][0-9] " nil t) |
963 (setq received (1+ received))) | 995 (setq received (1+ received))) |
964 (setq last-point (point)) | 996 (setq last-point (point)) |
965 (< received count)) | 997 (< received count)) |
966 (accept-process-output) | 998 (accept-process-output nntp-server-process) |
967 (set-buffer buf))))) | 999 (set-buffer buf))))) |
968 | 1000 |
969 (when nntp-server-xover | 1001 (when nntp-server-xover |
970 ;; Wait for the reply from the final command. | 1002 ;; Wait for the reply from the final command. |
971 (goto-char (point-max)) | 1003 (goto-char (point-max)) |
974 (while (progn | 1006 (while (progn |
975 (goto-char (point-max)) | 1007 (goto-char (point-max)) |
976 (forward-line -1) | 1008 (forward-line -1) |
977 (not (looking-at "^\\.\r?\n"))) | 1009 (not (looking-at "^\\.\r?\n"))) |
978 (nntp-accept-response))) | 1010 (nntp-accept-response))) |
979 | 1011 |
980 ;; We remove any "." lines and status lines. | 1012 ;; We remove any "." lines and status lines. |
981 (goto-char (point-min)) | 1013 (goto-char (point-min)) |
982 (while (search-forward "\r" nil t) | 1014 (while (search-forward "\r" nil t) |
983 (delete-char -1)) | 1015 (delete-char -1)) |
984 (goto-char (point-min)) | 1016 (goto-char (point-min)) |
985 (delete-matching-lines "^\\.$\\|^[1-5][0-9][0-9] ") | 1017 (delete-matching-lines "^\\.$\\|^[1-5][0-9][0-9] "))))) |
986 ;;(copy-to-buffer nntp-server-buffer (point-min) (point-max)) | |
987 t)))) | |
988 | 1018 |
989 nntp-server-xover) | 1019 nntp-server-xover) |
990 | 1020 |
991 (defun nntp-send-xover-command (beg end &optional wait-for-reply) | 1021 (defun nntp-send-xover-command (beg end &optional wait-for-reply) |
992 "Send the XOVER command to the server." | 1022 "Send the XOVER command to the server." |
993 (let ((range (format "%d-%d" beg end)) | 1023 (let ((range (format "%d-%d" (or beg 1) (or end beg 1)))) |
994 (nntp-inhibit-erase t)) | |
995 (if (stringp nntp-server-xover) | 1024 (if (stringp nntp-server-xover) |
996 ;; If `nntp-server-xover' is a string, then we just send this | 1025 ;; If `nntp-server-xover' is a string, then we just send this |
997 ;; command. | 1026 ;; command. |
998 (if wait-for-reply | 1027 (if wait-for-reply |
999 (nntp-send-command-nodelete | 1028 (nntp-send-command "^\\.\r?\n" nntp-server-xover range) |
1000 "\r?\n\\.\r?\n" nntp-server-xover range) | |
1001 ;; We do not wait for the reply. | 1029 ;; We do not wait for the reply. |
1002 (nntp-send-command-nodelete "\r?\n\\.\r?\n" nntp-server-xover range)) | 1030 (nntp-send-strings-to-server nntp-server-xover range)) |
1003 (let ((commands nntp-xover-commands)) | 1031 (let ((commands nntp-xover-commands)) |
1004 ;; `nntp-xover-commands' is a list of possible XOVER commands. | 1032 ;; `nntp-xover-commands' is a list of possible XOVER commands. |
1005 ;; We try them all until we get at positive response. | 1033 ;; We try them all until we get at positive response. |
1006 (while (and commands (eq nntp-server-xover 'try)) | 1034 (while (and commands (eq nntp-server-xover 'try)) |
1007 (nntp-send-command-nodelete "\r?\n\\.\r?\n" (car commands) range) | 1035 (nntp-send-command "^\\.\r?\n" (car commands) range) |
1008 (save-excursion | 1036 (save-excursion |
1009 (set-buffer nntp-server-buffer) | 1037 (set-buffer nntp-server-buffer) |
1010 (goto-char (point-min)) | 1038 (goto-char (point-min)) |
1011 (and (looking-at "[23]") ; No error message. | 1039 (and (looking-at "[23]") ; No error message. |
1012 ;; We also have to look at the lines. Some buggy | 1040 ;; We also have to look at the lines. Some buggy |
1013 ;; servers give back simple lines with just the | 1041 ;; servers give back simple lines with just the |
1014 ;; article number. How... helpful. | 1042 ;; article number. How... helpful. |
1015 (progn | 1043 (progn |
1016 (forward-line 1) | 1044 (forward-line 1) |
1023 (set-buffer nntp-server-buffer) | 1051 (set-buffer nntp-server-buffer) |
1024 (erase-buffer) | 1052 (erase-buffer) |
1025 (setq nntp-server-xover nil))) | 1053 (setq nntp-server-xover nil))) |
1026 nntp-server-xover)))) | 1054 nntp-server-xover)))) |
1027 | 1055 |
1028 ;;; Alternative connection methods. | 1056 (defun nntp-send-strings-to-server (&rest strings) |
1057 "Send STRINGS to the server." | |
1058 (let ((cmd (concat (mapconcat 'identity strings " ") nntp-end-of-line))) | |
1059 ;; We open the nntp server if it is down. | |
1060 (or (nntp-server-opened (nnoo-current-server 'nntp)) | |
1061 (nntp-open-server (nnoo-current-server 'nntp)) | |
1062 (error "Couldn't open server: " (nntp-status-message))) | |
1063 ;; Send the strings. | |
1064 (process-send-string nntp-server-process cmd) | |
1065 t)) | |
1066 | |
1067 (defun nntp-send-region-to-server (begin end) | |
1068 "Send the current buffer region (from BEGIN to END) to the server." | |
1069 (save-excursion | |
1070 (let ((cur (current-buffer))) | |
1071 ;; Copy the buffer over to the send buffer. | |
1072 (nnheader-set-temp-buffer " *nntp send*") | |
1073 (insert-buffer-substring cur begin end) | |
1074 (save-excursion | |
1075 (set-buffer cur) | |
1076 (erase-buffer)) | |
1077 ;; `process-send-region' does not work if the text to be sent is very | |
1078 ;; large, so we send it piecemeal. | |
1079 (let ((last (point-min)) | |
1080 (size 100)) ;Size of text sent at once. | |
1081 (while (and (/= last (point-max)) | |
1082 (memq (process-status nntp-server-process) '(open run))) | |
1083 (process-send-region | |
1084 nntp-server-process | |
1085 last (setq last (min (+ last size) (point-max)))) | |
1086 ;; Read any output from the server. May be unnecessary. | |
1087 (accept-process-output))) | |
1088 (kill-buffer (current-buffer))))) | |
1089 | |
1090 (defun nntp-open-server-semi-internal (server &optional service) | |
1091 "Open SERVER. | |
1092 If SERVER is nil, use value of environment variable `NNTPSERVER'. | |
1093 If SERVICE, use this as the port number." | |
1094 (nnheader-insert "") | |
1095 (let ((server (or server (getenv "NNTPSERVER"))) | |
1096 (status nil) | |
1097 (timer | |
1098 (and nntp-connection-timeout | |
1099 (nnheader-run-at-time nntp-connection-timeout | |
1100 nil 'nntp-kill-connection server)))) | |
1101 (save-excursion | |
1102 (set-buffer nntp-server-buffer) | |
1103 (setq nntp-status-string "") | |
1104 (nnheader-message 5 "nntp: Connecting to server on %s..." nntp-address) | |
1105 (cond ((and server (nntp-open-server-internal server service)) | |
1106 (setq nntp-address server) | |
1107 (setq status | |
1108 (condition-case nil | |
1109 (nntp-wait-for-response "^[23].*\r?\n" 'slow) | |
1110 (error nil) | |
1111 ;(quit nil) | |
1112 )) | |
1113 (unless status | |
1114 (nntp-close-server-internal server) | |
1115 (nnheader-report | |
1116 'nntp "Couldn't open connection to %s" | |
1117 (if (and nntp-address | |
1118 (not (equal nntp-address ""))) | |
1119 nntp-address server))) | |
1120 (when nntp-server-process | |
1121 (set-process-sentinel | |
1122 nntp-server-process 'nntp-default-sentinel) | |
1123 ;; You can send commands at startup like AUTHINFO here. | |
1124 ;; Added by Hallvard B Furuseth <h.b.furuseth@usit.uio.no> | |
1125 (run-hooks 'nntp-server-opened-hook))) | |
1126 ((null server) | |
1127 (nnheader-report 'nntp "NNTP server is not specified.")) | |
1128 (t ; We couldn't open the server. | |
1129 (nnheader-report 'nntp (buffer-string)))) | |
1130 (when timer | |
1131 (nnheader-cancel-timer timer)) | |
1132 (message "") | |
1133 (unless status | |
1134 (nnoo-close-server 'nntp server) | |
1135 (setq nntp-async-number nil)) | |
1136 status))) | |
1137 | |
1138 (defvar nntp-default-directories '("~" "/tmp" "/") | |
1139 "Directories to as current directory in the nntp server buffer.") | |
1140 | |
1141 (defun nntp-open-server-internal (server &optional service) | |
1142 "Open connection to news server on SERVER by SERVICE (default is nntp)." | |
1143 (let (proc) | |
1144 (save-excursion | |
1145 (set-buffer nntp-server-buffer) | |
1146 ;; Make sure we have a valid current directory for the | |
1147 ;; nntp server buffer. | |
1148 (unless (file-exists-p default-directory) | |
1149 (let ((dirs nntp-default-directories)) | |
1150 (while dirs | |
1151 (when (file-exists-p (car dirs)) | |
1152 (setq default-directory (car dirs) | |
1153 dirs nil)) | |
1154 (setq dirs (cdr dirs))))) | |
1155 (cond | |
1156 ((and (setq proc | |
1157 (condition-case nil | |
1158 (funcall nntp-open-server-function server) | |
1159 (error nil))) | |
1160 (memq (process-status proc) '(open run))) | |
1161 (setq nntp-server-process proc) | |
1162 (setq nntp-address server) | |
1163 ;; Suggested by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>. | |
1164 (process-kill-without-query proc) | |
1165 (run-hooks 'nntp-server-hook) | |
1166 (push proc nntp-opened-connections) | |
1167 (condition-case () | |
1168 (nntp-read-server-type) | |
1169 (error | |
1170 (nnheader-report 'nntp "Couldn't open server %s" server) | |
1171 (nntp-close-server))) | |
1172 nntp-server-process) | |
1173 (t | |
1174 (nnheader-report 'nntp "Couldn't open server %s" server)))))) | |
1175 | |
1176 (defun nntp-read-server-type () | |
1177 "Find out what the name of the server we have connected to is." | |
1178 ;; Wait for the status string to arrive. | |
1179 (nntp-wait-for-response "^.*\n" t) | |
1180 (setq nntp-server-type (buffer-string)) | |
1181 (let ((alist nntp-server-action-alist) | |
1182 entry) | |
1183 ;; Run server-specific commmands. | |
1184 (while alist | |
1185 (setq entry (pop alist)) | |
1186 (when (string-match (car entry) nntp-server-type) | |
1187 (if (and (listp (cadr entry)) | |
1188 (not (eq 'lambda (caadr entry)))) | |
1189 (eval (cadr entry)) | |
1190 (funcall (cadr entry))))))) | |
1191 | |
1192 (defun nntp-open-network-stream (server) | |
1193 (open-network-stream | |
1194 "nntpd" nntp-server-buffer server nntp-port-number)) | |
1195 | |
1196 (defun nntp-open-rlogin (server) | |
1197 "Open a connection to SERVER using rsh." | |
1198 (let ((proc (if nntp-rlogin-user-name | |
1199 (start-process | |
1200 "nntpd" nntp-server-buffer "rsh" | |
1201 server "-l" nntp-rlogin-user-name | |
1202 (mapconcat 'identity | |
1203 nntp-rlogin-parameters " ")) | |
1204 (start-process | |
1205 "nntpd" nntp-server-buffer "rsh" server | |
1206 (mapconcat 'identity | |
1207 nntp-rlogin-parameters " "))))) | |
1208 proc)) | |
1029 | 1209 |
1030 (defun nntp-wait-for-string (regexp) | 1210 (defun nntp-wait-for-string (regexp) |
1031 "Wait until string arrives in the buffer." | 1211 "Wait until string arrives in the buffer." |
1032 (let ((buf (current-buffer))) | 1212 (let ((buf (current-buffer))) |
1033 (goto-char (point-min)) | 1213 (goto-char (point-min)) |
1034 (while (not (re-search-forward regexp nil t)) | 1214 (while (not (re-search-forward regexp nil t)) |
1035 (accept-process-output (nntp-find-connection nntp-server-buffer)) | 1215 (accept-process-output nntp-server-process) |
1036 (set-buffer buf) | 1216 (set-buffer buf) |
1037 (goto-char (point-min))))) | 1217 (goto-char (point-min))))) |
1038 | 1218 |
1039 (defun nntp-open-telnet (buffer) | 1219 (defun nntp-open-telnet (server) |
1040 (save-excursion | 1220 (save-excursion |
1041 (set-buffer buffer) | 1221 (set-buffer nntp-server-buffer) |
1042 (erase-buffer) | 1222 (erase-buffer) |
1043 (let ((proc (start-process | 1223 (let ((proc (start-process |
1044 "nntpd" buffer "telnet" "-8")) | 1224 "nntpd" nntp-server-buffer "telnet" "-8")) |
1045 (case-fold-search t)) | 1225 (case-fold-search t)) |
1046 (when (memq (process-status proc) '(open run)) | 1226 (when (memq (process-status proc) '(open run)) |
1047 (process-send-string proc "set escape \^X\n") | 1227 (process-send-string proc "set escape \^X\n") |
1048 (process-send-string proc (concat "open " nntp-address "\n")) | 1228 (process-send-string proc (concat "open " server "\n")) |
1049 (nntp-wait-for-string "^\r*.?login:") | 1229 (nntp-wait-for-string "^\r*.?login:") |
1050 (process-send-string | 1230 (process-send-string |
1051 proc (concat | 1231 proc (concat |
1052 (or nntp-telnet-user-name | 1232 (or nntp-telnet-user-name |
1053 (setq nntp-telnet-user-name (read-string "login: "))) | 1233 (setq nntp-telnet-user-name (read-string "login: "))) |
1074 (goto-char (point-min)) | 1254 (goto-char (point-min)) |
1075 (forward-line 1) | 1255 (forward-line 1) |
1076 (delete-region (point) (point-max))) | 1256 (delete-region (point) (point-max))) |
1077 proc))) | 1257 proc))) |
1078 | 1258 |
1079 (defun nntp-open-rlogin (buffer) | 1259 (defun nntp-close-server-internal (&optional server) |
1080 "Open a connection to SERVER using rsh." | 1260 "Close connection to news server." |
1081 (let ((proc (if nntp-rlogin-user-name | 1261 (nntp-possibly-change-server nil server) |
1082 (start-process | 1262 (if nntp-server-process |
1083 "nntpd" buffer "rsh" | 1263 (delete-process nntp-server-process)) |
1084 nntp-address "-l" nntp-rlogin-user-name | 1264 (setq nntp-server-process nil) |
1085 (mapconcat 'identity | 1265 ;(setq nntp-address "") |
1086 nntp-rlogin-parameters " ")) | 1266 ) |
1087 (start-process | 1267 |
1088 "nntpd" buffer "rsh" nntp-address | 1268 (defun nntp-accept-response () |
1089 (mapconcat 'identity | 1269 "Read response of server. |
1090 nntp-rlogin-parameters " "))))) | 1270 It is well-known that the communication speed will be much improved by |
1091 (set-buffer buffer) | 1271 defining this function as macro." |
1092 (nntp-wait-for-string "^\r*200") | 1272 ;; To deal with server process exiting before |
1093 (beginning-of-line) | 1273 ;; accept-process-output is called. |
1094 (delete-region (point-min) (point)) | 1274 ;; Suggested by Jason Venner <jason@violet.berkeley.edu>. |
1095 proc)) | 1275 ;; This is a copy of `nntp-default-sentinel'. |
1096 | 1276 (let ((buf (current-buffer))) |
1097 (defun nntp-find-group-and-number () | 1277 (prog1 |
1278 (if (or (not nntp-server-process) | |
1279 (not (memq (process-status nntp-server-process) '(open run)))) | |
1280 (error "nntp: Process connection closed; %s" (nntp-status-message)) | |
1281 (if nntp-buggy-select | |
1282 (progn | |
1283 ;; We cannot use `accept-process-output'. | |
1284 ;; Fujitsu UTS requires messages during sleep-for. | |
1285 ;; I don't know why. | |
1286 (nnheader-message 5 "NNTP: Reading...") | |
1287 (sleep-for 1) | |
1288 (nnheader-message 5 "")) | |
1289 (condition-case errorcode | |
1290 (accept-process-output nntp-server-process 1) | |
1291 (error | |
1292 (cond ((string-equal "select error: Invalid argument" | |
1293 (nth 1 errorcode)) | |
1294 ;; Ignore select error. | |
1295 nil) | |
1296 (t | |
1297 (signal (car errorcode) (cdr errorcode)))))))) | |
1298 (set-buffer buf)))) | |
1299 | |
1300 (defun nntp-last-element (list) | |
1301 "Return last element of LIST." | |
1302 (while (cdr list) | |
1303 (setq list (cdr list))) | |
1304 (car list)) | |
1305 | |
1306 (defun nntp-possibly-change-server (newsgroup server &optional connectionless) | |
1307 "Check whether the virtual server needs changing." | |
1308 (when (and server | |
1309 (not (nntp-server-opened server))) | |
1310 ;; This virtual server isn't open, so we (re)open it here. | |
1311 (nntp-open-server server nil t)) | |
1312 (when (and newsgroup | |
1313 (not (equal newsgroup nntp-current-group))) | |
1314 ;; Set the proper current group. | |
1315 (nntp-request-group newsgroup server))) | |
1316 | |
1317 (defun nntp-try-list-active (group) | |
1318 (nntp-list-active-group group) | |
1098 (save-excursion | 1319 (save-excursion |
1099 (save-restriction | 1320 (set-buffer nntp-server-buffer) |
1100 (set-buffer nntp-server-buffer) | 1321 (goto-char (point-min)) |
1101 (narrow-to-region (goto-char (point-min)) | 1322 (cond ((looking-at "5[0-9]+") |
1102 (or (search-forward "\n\n" nil t) (point-max))) | 1323 (setq nntp-server-list-active-group nil)) |
1103 (goto-char (point-min)) | 1324 (t |
1104 ;; We first find the number by looking at the status line. | 1325 (setq nntp-server-list-active-group t))))) |
1105 (let ((number (and (looking-at "2[0-9][0-9] +\\([0-9]+\\) ") | 1326 |
1106 (string-to-int | 1327 (defun nntp-async-server-opened () |
1107 (buffer-substring (match-beginning 1) | 1328 (and nntp-async-process |
1108 (match-end 1))))) | 1329 (memq (process-status nntp-async-process) '(open run)))) |
1109 group newsgroups xref) | 1330 |
1110 (and number (zerop number) (setq number nil)) | 1331 (defun nntp-async-open-server () |
1111 ;; Then we find the group name. | 1332 (save-excursion |
1112 (setq group | 1333 (set-buffer (generate-new-buffer " *async-nntp*")) |
1113 (cond | 1334 (setq nntp-async-buffer (current-buffer)) |
1114 ;; If there is only one group in the Newsgroups header, | 1335 (buffer-disable-undo (current-buffer))) |
1115 ;; then it seems quite likely that this article comes | 1336 (let ((nntp-server-process nil) |
1116 ;; from that group, I'd say. | 1337 (nntp-server-buffer nntp-async-buffer)) |
1117 ((and (setq newsgroups (mail-fetch-field "newsgroups")) | 1338 (nntp-open-server-semi-internal nntp-address nntp-port-number) |
1118 (not (string-match "," newsgroups))) | 1339 (if (not (setq nntp-async-process nntp-server-process)) |
1119 newsgroups) | 1340 (progn |
1120 ;; If there is more than one group in the Newsgroups | 1341 (setq nntp-async-number nil)) |
1121 ;; header, then the Xref header should be filled out. | 1342 (set-process-buffer nntp-async-process nntp-async-buffer)))) |
1122 ;; We hazard a guess that the group that has this | 1343 |
1123 ;; article number in the Xref header is the one we are | 1344 (defun nntp-async-fetch-articles (article) |
1124 ;; looking for. This might very well be wrong if this | 1345 (if (stringp article) |
1125 ;; article happens to have the same number in several | 1346 () |
1126 ;; groups, but that's life. | 1347 (let ((articles (cdr (memq (assq article nntp-async-articles) |
1127 ((and (setq xref (mail-fetch-field "xref")) | 1348 nntp-async-articles))) |
1128 number | 1349 (max (cond ((numberp nntp-async-number) |
1129 (string-match (format "\\([^ :]+\\):%d" number) xref)) | 1350 nntp-async-number) |
1130 (substring xref (match-beginning 1) (match-end 1))) | 1351 ((eq nntp-async-number t) |
1131 (t ""))) | 1352 (length nntp-async-articles)) |
1132 (when (string-match "\r" group) | 1353 (t 0))) |
1133 (setq group (substring group 0 (match-beginning 0)))) | 1354 nart) |
1134 (cons group number))))) | 1355 (while (and (>= (setq max (1- max)) 0) |
1356 articles) | |
1357 (or (memq (setq nart (caar articles)) nntp-async-fetched) | |
1358 (progn | |
1359 (nntp-async-send-strings "ARTICLE " (int-to-string nart)) | |
1360 (setq nntp-async-fetched (cons nart nntp-async-fetched)))) | |
1361 (setq articles (cdr articles)))))) | |
1362 | |
1363 (defun nntp-async-send-strings (&rest strings) | |
1364 (let ((cmd (concat (mapconcat 'identity strings " ") nntp-end-of-line))) | |
1365 (or (nntp-async-server-opened) | |
1366 (nntp-async-open-server) | |
1367 (error (nntp-status-message))) | |
1368 (process-send-string nntp-async-process cmd))) | |
1369 | |
1370 (defun nntp-async-request-group (group) | |
1371 (if (equal group nntp-current-group) | |
1372 () | |
1373 (let ((asyncs (assoc group nntp-async-group-alist))) | |
1374 ;; A new group has been selected, so we push the current state | |
1375 ;; of async articles on an alist, and pull the old state off. | |
1376 (setq nntp-async-group-alist | |
1377 (cons (list nntp-current-group | |
1378 nntp-async-articles nntp-async-fetched | |
1379 nntp-async-process) | |
1380 (delq asyncs nntp-async-group-alist))) | |
1381 (and asyncs | |
1382 (progn | |
1383 (setq nntp-async-articles (nth 1 asyncs)) | |
1384 (setq nntp-async-fetched (nth 2 asyncs)) | |
1385 (setq nntp-async-process (nth 3 asyncs))))))) | |
1135 | 1386 |
1136 (provide 'nntp) | 1387 (provide 'nntp) |
1137 | 1388 |
1138 ;;; nntp.el ends here | 1389 ;;; nntp.el ends here |