Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9dd7872

Browse files
committed
Added new exception classes:
NNTPError - derived from Exception, it's the base class for all other exceptions in this module NNTPReplyError - what used to be error_reply NNTPTemporaryError - what used to be error_temp NNTPPermanentError - what used to be error_perm NNTPProtocolError - what used to be error_proto NNTPDataError - what used to be error_data All the old names are retained for backwards compatibility; they point to the class that replaces them. Also, any code in this module that raises an exception, now does so with the exception class. NNTP.__init__(): Added a new optional argument `readermode', which is a flag that defaults to false. When set to true, the "mode reader" command is sent to the NNTP server before user authentication. Reader mode is sometimes necessary if you are connecting to an NNTP server on the local machine and intend to call reader-specific comamnds, such as `group'. If you get unexpected NNTPPermanentErrors, you might need to set readermode. Patch provided by Thomas Wouters (who include the standard disclaimer on is [email protected] submission), and inspired by Jim Tittsler.
1 parent 9abc25e commit 9dd7872

1 file changed

Lines changed: 81 additions & 28 deletions

File tree

Lib/nntplib.py

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,46 @@
3434
import string
3535

3636

37-
# Exception raised when an error or invalid response is received
38-
error_reply = 'nntplib.error_reply' # unexpected [123]xx reply
39-
error_temp = 'nntplib.error_temp' # 4xx errors
40-
error_perm = 'nntplib.error_perm' # 5xx errors
41-
error_proto = 'nntplib.error_proto' # response does not begin with [1-5]
42-
error_data = 'nntplib.error_data' # error in response data
37+
38+
# Exceptions raised when an error or invalid response is received
39+
class NNTPError(Exception):
40+
"""Base class for all nntplib exceptions"""
41+
def __init__(self, *args):
42+
apply(Exception.__init__, (self,)+args)
43+
try:
44+
self.response = args[0]
45+
except IndexError:
46+
self.response = 'No response given'
47+
48+
class NNTPReplyError(NNTPError):
49+
"""Unexpected [123]xx reply"""
50+
pass
51+
52+
class NNTPTemporaryError(NNTPError):
53+
"""4xx errors"""
54+
pass
55+
56+
class NNTPPermanentError(NNTPError):
57+
"""5xx errors"""
58+
pass
59+
60+
class NNTPProtocolError(NNTPError):
61+
"""Response does not begin with [1-5]"""
62+
pass
63+
64+
class NNTPDataError(NNTPError):
65+
"""Error in response data"""
66+
pass
4367

68+
# for backwards compatibility
69+
error_reply = NNTPReplyError
70+
error_temp = NNTPTemporaryError
71+
error_perm = NNTPPermanentError
72+
error_proto = NNTPProtocolError
73+
error_data = NNTPDataError
4474

75+
76+
4577
# Standard port used by NNTP servers
4678
NNTP_PORT = 119
4779

@@ -54,32 +86,53 @@
5486
CRLF = '\r\n'
5587

5688

89+
5790
# The class itself
58-
5991
class NNTP:
60-
61-
def __init__(self, host, port = NNTP_PORT, user=None, password=None):
92+
def __init__(self, host, port=NNTP_PORT, user=None, password=None,
93+
readermode=None):
6294
"""Initialize an instance. Arguments:
6395
- host: hostname to connect to
64-
- port: port to connect to (default the standard NNTP port)"""
65-
96+
- port: port to connect to (default the standard NNTP port)
97+
- user: username to authenticate with
98+
- password: password to use with username
99+
- readermode: if true, send 'mode reader' command after
100+
connecting.
101+
102+
readermode is sometimes necessary if you are connecting to an
103+
NNTP server on the local machine and intend to call
104+
reader-specific comamnds, such as `group'. If you get
105+
unexpected NNTPPermanentErrors, you might need to set
106+
readermode.
107+
"""
66108
self.host = host
67109
self.port = port
68110
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
69111
self.sock.connect(self.host, self.port)
70112
self.file = self.sock.makefile('rb')
71113
self.debugging = 0
72114
self.welcome = self.getresp()
115+
if readermode:
116+
try:
117+
self.welcome = self.shortcmd('mode reader')
118+
except NNTPPermanentError:
119+
# error 500, probably 'not implemented'
120+
pass
73121
if user:
74122
resp = self.shortcmd('authinfo user '+user)
75123
if resp[:3] == '381':
76124
if not password:
77-
raise error_reply, resp
125+
raise NNTPReplyError(resp)
78126
else:
79127
resp = self.shortcmd(
80128
'authinfo pass '+password)
81129
if resp[:3] != '281':
82-
raise error_perm, resp
130+
raise NNTPPermanentError(resp)
131+
132+
# Get the welcome message from the server
133+
# (this is read and squirreled away by __init__()).
134+
# If the response code is 200, posting is allowed;
135+
# if it 201, posting is not allowed
83136

84137
def getwelcome(self):
85138
"""Get the welcome message from the server
@@ -128,19 +181,19 @@ def getresp(self):
128181
if self.debugging: print '*resp*', `resp`
129182
c = resp[:1]
130183
if c == '4':
131-
raise error_temp, resp
184+
raise NNTPTemporaryError(resp)
132185
if c == '5':
133-
raise error_perm, resp
186+
raise NNTPPermanentError(resp)
134187
if c not in '123':
135-
raise error_proto, resp
188+
raise NNTPProtocolError(resp)
136189
return resp
137190

138191
def getlongresp(self):
139192
"""Internal: get a response plus following text from the server.
140193
Raise various errors if the response indicates an error."""
141194
resp = self.getresp()
142195
if resp[:3] not in LONGRESP:
143-
raise error_reply, resp
196+
raise NNTPReplyError(resp)
144197
list = []
145198
while 1:
146199
line = self.getline()
@@ -206,7 +259,7 @@ def group(self, name):
206259

207260
resp = self.shortcmd('GROUP ' + name)
208261
if resp[:3] <> '211':
209-
raise error_reply, resp
262+
raise NNTPReplyError(resp)
210263
words = string.split(resp)
211264
count = first = last = 0
212265
n = len(words)
@@ -230,7 +283,7 @@ def help(self):
230283
def statparse(self, resp):
231284
"""Internal: parse the response of a STAT, NEXT or LAST command."""
232285
if resp[:2] <> '22':
233-
raise error_reply, resp
286+
raise NNTPReplyError(resp)
234287
words = string.split(resp)
235288
nr = 0
236289
id = ''
@@ -349,7 +402,7 @@ def xover(self,start,end):
349402
elem[6],
350403
elem[7]))
351404
except IndexError:
352-
raise error_data,line
405+
raise NNTPDataError(line)
353406
return resp,xover_lines
354407

355408
def xgtitle(self, group):
@@ -377,11 +430,11 @@ def xpath(self,id):
377430

378431
resp = self.shortcmd("XPATH " + id)
379432
if resp[:3] <> '223':
380-
raise error_reply, resp
433+
raise NNTPReplyError(resp)
381434
try:
382435
[resp_num, path] = string.split(resp)
383436
except ValueError:
384-
raise error_reply, resp
437+
raise NNTPReplyError(resp)
385438
else:
386439
return resp, path
387440

@@ -395,14 +448,14 @@ def date (self):
395448

396449
resp = self.shortcmd("DATE")
397450
if resp[:3] <> '111':
398-
raise error_reply, resp
451+
raise NNTPReplyError(resp)
399452
elem = string.split(resp)
400453
if len(elem) != 2:
401-
raise error_data, resp
454+
raise NNTPDataError(resp)
402455
date = elem[1][2:8]
403456
time = elem[1][-6:]
404457
if len(date) != 6 or len(time) != 6:
405-
raise error_data, resp
458+
raise NNTPDataError(resp)
406459
return resp, date, time
407460

408461

@@ -415,7 +468,7 @@ def post(self, f):
415468
resp = self.shortcmd('POST')
416469
# Raises error_??? if posting is not allowed
417470
if resp[0] <> '3':
418-
raise error_reply, resp
471+
raise NNTPReplyError(resp)
419472
while 1:
420473
line = f.readline()
421474
if not line:
@@ -439,7 +492,7 @@ def ihave(self, id, f):
439492
resp = self.shortcmd('IHAVE ' + id)
440493
# Raises error_??? if the server already has it
441494
if resp[0] <> '3':
442-
raise error_reply, resp
495+
raise NNTPReplyError(resp)
443496
while 1:
444497
line = f.readline()
445498
if not line:
@@ -465,7 +518,7 @@ def quit(self):
465518

466519
def _test():
467520
"""Minimal test function."""
468-
s = NNTP('news')
521+
s = NNTP('news', readermode='reader')
469522
resp, count, first, last, name = s.group('comp.lang.python')
470523
print resp
471524
print 'Group', name, 'has', count, 'articles, range', first, 'to', last

0 commit comments

Comments
 (0)