1 ;;; nntp.el --- nntp access for Gnus
3 ;; Copyright (C) 1987, 1988, 1989, 1990, 1992, 1993,
4 ;; 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
5 ;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
7 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published
14 ;; by the Free Software Foundation; either version 2, or (at your
15 ;; option) any later version.
17 ;; GNU Emacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
25 ;; MA 02110-1301, USA.
38 (eval-when-compile (require 'cl))
41 "NNTP access for Gnus."
44 (defvoo nntp-address nil
45 "Address of the physical nntp server.")
47 (defvoo nntp-port-number "nntp"
48 "Port number on the physical nntp server.")
50 (defvoo nntp-server-opened-hook '(nntp-send-mode-reader)
51 "*Hook used for sending commands to the server at startup.
52 The default value is `nntp-send-mode-reader', which makes an innd
53 server spawn an nnrpd server.")
55 (defvoo nntp-authinfo-function 'nntp-send-authinfo
56 "Function used to send AUTHINFO to the server.
57 It is called with no parameters.")
59 (defvoo nntp-server-action-alist
60 '(("nntpd 1\\.5\\.11t"
61 (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader))
62 ("NNRP server Netscape"
63 (setq nntp-server-list-active-group nil)))
64 "Alist of regexps to match on server types and actions to be taken.
65 For instance, if you want Gnus to beep every time you connect
66 to innd, you could say something like:
68 \(setq nntp-server-action-alist
71 You probably don't want to do that, though.")
73 (defvoo nntp-open-connection-function 'nntp-open-network-stream
74 "*Function used for connecting to a remote system.
75 It will be called with the buffer to output in as argument.
77 Currently, five such functions are provided (please refer to their
78 respective doc string for more information), three of them establishing
79 direct connections to the nntp server, and two of them using an indirect
83 - `nntp-open-network-stream' (the default),
84 - `nntp-open-ssl-stream',
85 - `nntp-open-tls-stream',
86 - `nntp-open-telnet-stream'.
89 - `nntp-open-via-rlogin-and-telnet',
90 - `nntp-open-via-rlogin-and-netcat',
91 - `nntp-open-via-telnet-and-telnet'.")
93 (defvoo nntp-never-echoes-commands nil
94 "*Non-nil means the nntp server never echoes commands.
95 It is reported that some nntps server doesn't echo commands. So, you
96 may want to set this to non-nil in the method for such a server setting
97 `nntp-open-connection-function' to `nntp-open-ssl-stream' for example.
98 Note that the `nntp-open-connection-functions-never-echo-commands'
99 variable overrides the nil value of this variable.")
101 (defvoo nntp-open-connection-functions-never-echo-commands
102 '(nntp-open-network-stream)
103 "*List of functions that never echo commands.
104 Add or set a function which you set to `nntp-open-connection-function'
105 to this list if it does not echo commands. Note that a non-nil value
106 of the `nntp-never-echoes-commands' variable overrides this variable.")
108 (defvoo nntp-pre-command nil
109 "*Pre-command to use with the various nntp-open-via-* methods.
110 This is where you would put \"runsocks\" or stuff like that.")
112 (defvoo nntp-telnet-command "telnet"
113 "*Telnet command used to connect to the nntp server.
114 This command is used by the methods `nntp-open-telnet-stream',
115 `nntp-open-via-rlogin-and-telnet' and `nntp-open-via-telnet-and-telnet'.")
117 (defvoo nntp-telnet-switches '("-8")
118 "*Switches given to the telnet command `nntp-telnet-command'.")
120 (defvoo nntp-end-of-line "\r\n"
121 "*String to use on the end of lines when talking to the NNTP server.
122 This is \"\\r\\n\" by default, but should be \"\\n\" when using an indirect
123 connection method (nntp-open-via-*).")
125 (defvoo nntp-via-rlogin-command "rsh"
126 "*Rlogin command used to connect to an intermediate host.
127 This command is used by the methods `nntp-open-via-rlogin-and-telnet'
128 and `nntp-open-via-rlogin-and-netcat'. The default is \"rsh\", but \"ssh\"
129 is a popular alternative.")
131 (defvoo nntp-via-rlogin-command-switches nil
132 "*Switches given to the rlogin command `nntp-via-rlogin-command'.
133 If you use \"ssh\" for `nntp-via-rlogin-command', you may set this to
134 \(\"-C\") in order to compress all data connections, otherwise set this
135 to \(\"-t\" \"-e\" \"none\") or (\"-C\" \"-t\" \"-e\" \"none\") if the telnet
136 command requires a pseudo-tty allocation on an intermediate host.")
138 (defvoo nntp-via-telnet-command "telnet"
139 "*Telnet command used to connect to an intermediate host.
140 This command is used by the `nntp-open-via-telnet-and-telnet' method.")
142 (defvoo nntp-via-telnet-switches '("-8")
143 "*Switches given to the telnet command `nntp-via-telnet-command'.")
145 (defvoo nntp-via-netcat-command "nc"
146 "*Netcat command used to connect to the nntp server.
147 This command is used by the `nntp-open-via-rlogin-and-netcat' method.")
149 (defvoo nntp-via-netcat-switches nil
150 "*Switches given to the netcat command `nntp-via-netcat-command'.")
152 (defvoo nntp-via-user-name nil
153 "*User name to log in on an intermediate host with.
154 This variable is used by the various nntp-open-via-* methods.")
156 (defvoo nntp-via-user-password nil
157 "*Password to use to log in on an intermediate host with.
158 This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
160 (defvoo nntp-via-address nil
161 "*Address of an intermediate host to connect to.
162 This variable is used by the various nntp-open-via-* methods.")
164 (defvoo nntp-via-envuser nil
165 "*Whether both telnet client and server support the ENVIRON option.
166 If non-nil, there will be no prompt for a login name.")
168 (defvoo nntp-via-shell-prompt "bash\\|\$ *\r?$\\|> *\r?"
169 "*Regular expression to match the shell prompt on an intermediate host.
170 This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
172 (defvoo nntp-large-newsgroup 50
173 "*The number of articles which indicates a large newsgroup.
174 If the number of articles is greater than the value, verbose
175 messages will be shown to indicate the current status.")
177 (defvoo nntp-maximum-request 400
178 "*The maximum number of the requests sent to the NNTP server at one time.
179 If Emacs hangs up while retrieving headers, set the variable to a
182 (defvoo nntp-nov-is-evil nil
183 "*If non-nil, nntp will never attempt to use XOVER when talking to the server.")
185 (defvoo nntp-xover-commands '("XOVER" "XOVERVIEW")
186 "*List of strings that are used as commands to fetch NOV lines from a server.
187 The strings are tried in turn until a positive response is gotten. If
188 none of the commands are successful, nntp will just grab headers one
191 (defvoo nntp-nov-gap 5
192 "*Maximum allowed gap between two articles.
193 If the gap between two consecutive articles is bigger than this
194 variable, split the XOVER request into two requests.")
196 (defvoo nntp-prepare-server-hook nil
197 "*Hook run before a server is opened.
198 If can be used to set up a server remotely, for instance. Say you
199 have an account at the machine \"other.machine\". This machine has
200 access to an NNTP server that you can't access locally. You could
201 then use this hook to rsh to the remote machine and start a proxy NNTP
202 server there that you can connect to. See also
203 `nntp-open-connection-function'")
205 (defvoo nntp-coding-system-for-read 'binary
206 "*Coding system to read from NNTP.")
208 (defvoo nntp-coding-system-for-write 'binary
209 "*Coding system to write to NNTP.")
212 (defvoo nntp-marks-is-evil nil
213 "*If non-nil, Gnus will never generate and use marks file for nntp groups.
214 See `nnml-marks-is-evil' for more information.")
216 (defvoo nntp-marks-file-name ".marks")
217 (defvoo nntp-marks nil)
218 (defvar nntp-marks-modtime (gnus-make-hashtable))
220 (defcustom nntp-marks-directory
221 (nnheader-concat gnus-directory "marks/")
222 "*The directory where marks for nntp groups will be stored."
226 (defcustom nntp-authinfo-file "~/.authinfo"
227 ".netrc-like file that holds nntp authinfo passwords."
231 (repeat :tag "Entries"
234 :value ("" ("login" . "") ("password" . ""))
238 (const :format "" "login")
239 (string :format "Login: %v"))
241 (const :format "" "password")
242 (string :format "Password: %v")))))))
246 (defvoo nntp-connection-timeout nil
247 "*Number of seconds to wait before an nntp connection times out.
248 If this variable is nil, which is the default, no timers are set.
249 NOTE: This variable is never seen to work in Emacs 20 and XEmacs 21.")
251 (defvoo nntp-prepare-post-hook nil
252 "*Hook run just before posting an article. It is supposed to be used
253 to insert Cancel-Lock headers.")
255 ;;; Internal variables.
257 (defvar nntp-record-commands nil
258 "*If non-nil, nntp will record all commands in the \"*nntp-log*\" buffer.")
260 (defvar nntp-have-messaged nil)
262 (defvar nntp-process-wait-for nil)
263 (defvar nntp-process-to-buffer nil)
264 (defvar nntp-process-callback nil)
265 (defvar nntp-process-decode nil)
266 (defvar nntp-process-start-point nil)
267 (defvar nntp-inside-change-function nil)
268 (defvoo nntp-last-command-time nil)
269 (defvoo nntp-last-command nil)
270 (defvoo nntp-authinfo-password nil)
271 (defvoo nntp-authinfo-user nil)
272 (defvoo nntp-authinfo-force nil)
274 (defvar nntp-connection-list nil)
276 (defvoo nntp-server-type nil)
277 (defvoo nntp-connection-alist nil)
278 (defvoo nntp-status-string "")
279 (defconst nntp-version "nntp 5.0")
280 (defvoo nntp-inhibit-erase nil)
281 (defvoo nntp-inhibit-output nil)
283 (defvoo nntp-server-xover 'try)
284 (defvoo nntp-server-list-active-group 'try)
286 (defvar nntp-async-needs-kluge
287 (string-match "^GNU Emacs 20\\.3\\." (emacs-version))
288 "*When non-nil, nntp will poll asynchronous connections
289 once a second. By default, this is turned on only for Emacs
290 20.3, which has a bug that breaks nntp's normal method of
291 noticing asynchronous data.")
293 (defvar nntp-async-timer nil)
294 (defvar nntp-async-process-list nil)
296 (defvar nntp-ssl-program
297 "openssl s_client -quiet -ssl3 -connect %s:%p"
298 "A string containing commands for SSL connections.
299 Within a string, %s is replaced with the server address and %p with
300 port number on server. The program should accept IMAP commands on
301 stdin and return responses to stdout.")
303 (defvar nntp-authinfo-rejected nil
304 "A custom error condition used to report 'Authentication Rejected' errors.
305 Condition handlers that match just this condition ensure that the nntp
306 backend doesn't catch this error.")
307 (put 'nntp-authinfo-rejected 'error-conditions '(error nntp-authinfo-rejected))
308 (put 'nntp-authinfo-rejected 'error-message "Authorization Rejected")
312 ;;; Internal functions.
314 (defsubst nntp-send-string (process string)
315 "Send STRING to PROCESS."
316 ;; We need to store the time to provide timeouts, and
317 ;; to store the command so the we can replay the command
318 ;; if the server gives us an AUTHINFO challenge.
319 (setq nntp-last-command-time (current-time)
320 nntp-last-command string)
321 (when nntp-record-commands
322 (nntp-record-command string))
323 (process-send-string process (concat string nntp-end-of-line))
324 (or (memq (process-status process) '(open run))
325 (nntp-report "Server closed connection")))
327 (defun nntp-record-command (string)
328 "Record the command STRING."
330 (set-buffer (get-buffer-create "*nntp-log*"))
331 (goto-char (point-max))
332 (let ((time (current-time)))
333 (insert (format-time-string "%Y%m%dT%H%M%S" time)
334 "." (format "%03d" (/ (nth 2 time) 1000))
335 " " nntp-address " " string "\n"))))
337 (defun nntp-report (&rest args)
338 "Report an error from the nntp backend. The first string in ARGS
339 can be a format string. For some commands, the failed command may be
340 retried once before actually displaying the error report."
342 (when nntp-record-commands
343 (nntp-record-command "*** CALLED nntp-report ***"))
345 (nnheader-report 'nntp args)
349 (defun nntp-report-1 (&rest args)
350 "Throws out to nntp-with-open-group-error so that the connection may
351 be restored and the command retried."
353 (when nntp-record-commands
354 (nntp-record-command "*** CONNECTION LOST ***"))
356 (throw 'nntp-with-open-group-error t))
358 (defsubst nntp-wait-for (process wait-for buffer &optional decode discard)
359 "Wait for WAIT-FOR to arrive from PROCESS."
362 (set-buffer (process-buffer process))
363 (goto-char (point-min))
365 (while (and (or (not (memq (char-after (point)) '(?2 ?3 ?4 ?5)))
366 (looking-at "48[02]"))
367 (memq (process-status process) '(open run)))
368 (cond ((looking-at "480")
369 (nntp-handle-authinfo process))
371 (nnheader-report 'nntp (get 'nntp-authinfo-rejected 'error-message))
372 (signal 'nntp-authinfo-rejected nil))
373 ((looking-at "^.*\n")
374 (delete-region (point) (progn (forward-line 1) (point)))))
375 (nntp-accept-process-output process)
376 (goto-char (point-min)))
381 (nntp-snarf-error-message)
383 ((not (memq (process-status process) '(open run)))
384 (nntp-report "Server closed connection"))
386 (goto-char (point-max))
387 (let ((limit (point-min))
389 (while (not (re-search-backward wait-for limit t))
390 (nntp-accept-process-output process)
391 ;; We assume that whatever we wait for is less than 1000
393 (setq limit (max (- (point-max) 1000) (point-min)))
394 (goto-char (point-max)))
395 (setq response (match-string 0))
396 (with-current-buffer nntp-server-buffer
397 (setq nntp-process-response response)))
398 (nntp-decode-text (not decode))
402 (goto-char (point-max))
403 (insert-buffer-substring (process-buffer process))
404 ;; Nix out "nntp reading...." message.
405 (when nntp-have-messaged
406 (setq nntp-have-messaged nil)
407 (nnheader-message 5 ""))))
412 (defun nntp-kill-buffer (buffer)
413 (when (buffer-name buffer)
415 (nnheader-init-server-buffer)))
417 (defun nntp-erase-buffer (buffer)
418 "Erase contents of BUFFER."
419 (with-current-buffer buffer
422 (defsubst nntp-find-connection (buffer)
423 "Find the connection delivering to BUFFER."
424 (let ((alist nntp-connection-alist)
425 (buffer (if (stringp buffer) (get-buffer buffer) buffer))
427 (while (and alist (setq entry (pop alist)))
428 (when (eq buffer (cadr entry))
429 (setq process (car entry)
432 (if (memq (process-status process) '(open run))
434 (nntp-kill-buffer (process-buffer process))
435 (setq nntp-connection-alist (delq entry nntp-connection-alist))