[Patches] Re: [Mailman-Developers] Bug#57223: mailman: gate_news problems (fwd)

bwarsaw@cnri.reston.va.us bwarsaw@cnri.reston.va.us
Tue, 8 Feb 2000 18:18:14 -0500 (EST)


Okay, here's my proposed patch to the current CVS version of
nntplib.py.  It merges Jim's and Thomas's patches, and re-implements
the module's exceptions as class-based (with backwards compatibility).

I'm not sure what to do about the email disclaimers, but I'd say to be
safe that both Jim and Thomas should re-submit their patches with the
disclaimer attached (you can just to this to patches@python.org).

Everyone else on patches@python.org: please let me know if you have
any objections to this change.  Otherwise, I'll commit it (and make
the necessary documentation updates).

-Barry

-------------------- snip snip --------------------
Index: nntplib.py
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Lib/nntplib.py,v
retrieving revision 1.17
diff -c -r1.17 nntplib.py
*** nntplib.py	2000/02/04 15:10:33	1.17
--- nntplib.py	2000/02/08 23:11:44
***************
*** 34,47 ****
  import string
  
  
! # Exception raised when an error or invalid response is received
! error_reply = 'nntplib.error_reply'	# unexpected [123]xx reply
! error_temp = 'nntplib.error_temp'	# 4xx errors
! error_perm = 'nntplib.error_perm'	# 5xx errors
! error_proto = 'nntplib.error_proto'	# response does not begin with [1-5]
! error_data = 'nntplib.error_data'	# error in response data
  
  
  # Standard port used by NNTP servers
  NNTP_PORT = 119
  
--- 34,79 ----
  import string
  
  
! 
! # Exceptions raised when an error or invalid response is received
! class NNTPError(Exception):
! 	"""Base class for all nntplib exceptions"""
! 	def __init__(self, *args):
! 		apply(Exception.__init__, (self,)+args)
! 		try:
! 			self.response = args[0]
! 		except IndexError:
! 			self.response = 'No response given'
! 
! class NNTPReplyError(NNTPError):
! 	"""Unexpected [123]xx reply"""
! 	pass
! 
! class NNTPTemporaryError(NNTPError):
! 	"""4xx errors"""
! 	pass
! 
! class NNTPPermanentError(NNTPError):
! 	"""5xx errors"""
! 	pass
! 
! class NNTPProtocolError(NNTPError):
! 	"""Response does not begin with [1-5]"""
! 	pass
! 
! class NNTPDataError(NNTPError):
! 	"""Error in response data"""
! 	pass
! 
! # for backwards compatibility
! error_reply = NNTPReplyError
! error_temp = NNTPTemporaryError
! error_perm = NNTPPermanentError
! error_proto = NNTPProtocolError
! error_data = NNTPDataError
  
  
+ 
  # Standard port used by NNTP servers
  NNTP_PORT = 119
  
***************
*** 54,68 ****
  CRLF = '\r\n'
  
  
  # The class itself
- 
  class NNTP:
! 
! 	def __init__(self, host, port = NNTP_PORT, user=None, password=None):
  		"""Initialize an instance.  Arguments:
  		- host: hostname to connect to
! 		- port: port to connect to (default the standard NNTP port)"""
! 
  		self.host = host
  		self.port = port
  		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
--- 86,108 ----
  CRLF = '\r\n'
  
  
+ 
  # The class itself
  class NNTP:
! 	def __init__(self, host, port = NNTP_PORT, user=None, password=None,
! 		     readermode=None):
  		"""Initialize an instance.  Arguments:
  		- host: hostname to connect to
! 		- port: port to connect to (default the standard NNTP port)
! 		- user: username to authenticate with
! 		- password: password to use with username
! 		- readermode: if true, send 'mode reader' command after
! 		              connecting.
! 
! 	        readermode is sometimes necessary if you are connecting to an
! 	        NNTP server on your local machine and intend to call the
! 	        group() method.
! 		"""
  		self.host = host
  		self.port = port
  		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
***************
*** 70,85 ****
  		self.file = self.sock.makefile('rb')
  		self.debugging = 0
  		self.welcome = self.getresp()
  		if user:
  			resp = self.shortcmd('authinfo user '+user)
  			if resp[:3] == '381':
  				if not password:
! 					raise error_reply, resp
  				else:
  					resp = self.shortcmd(
  						'authinfo pass '+password)
  					if resp[:3] != '281':
! 						raise error_perm, resp
  
  	def getwelcome(self):
  		"""Get the welcome message from the server
--- 110,136 ----
  		self.file = self.sock.makefile('rb')
  		self.debugging = 0
  		self.welcome = self.getresp()
+ 		if readermode:
+ 			try:
+ 				self.welcome = self.shortcmd('mode reader')
+ 			except NNTPPermanentError:
+ 				# error 500, probably 'not implemented'
+ 				pass
  		if user:
  			resp = self.shortcmd('authinfo user '+user)
  			if resp[:3] == '381':
  				if not password:
! 					raise NNTPReplyError(resp)
  				else:
  					resp = self.shortcmd(
  						'authinfo pass '+password)
  					if resp[:3] != '281':
! 						raise NNTPPermanentError(resp)
! 
! 	# Get the welcome message from the server
! 	# (this is read and squirreled away by __init__()).
! 	# If the response code is 200, posting is allowed;
! 	# if it 201, posting is not allowed
  
  	def getwelcome(self):
  		"""Get the welcome message from the server
***************
*** 128,138 ****
  		if self.debugging: print '*resp*', `resp`
  		c = resp[:1]
  		if c == '4':
! 			raise error_temp, resp
  		if c == '5':
! 			raise error_perm, resp
  		if c not in '123':
! 			raise error_proto, resp
  		return resp
  
  	def getlongresp(self):
--- 179,189 ----
  		if self.debugging: print '*resp*', `resp`
  		c = resp[:1]
  		if c == '4':
! 			raise NNTPTemporaryError(resp)
  		if c == '5':
! 			raise NNTPPermanentError(resp)
  		if c not in '123':
! 			raise NNTPProtocolError(resp)
  		return resp
  
  	def getlongresp(self):
***************
*** 140,146 ****
  		Raise various errors if the response indicates an error."""
  		resp = self.getresp()
  		if resp[:3] not in LONGRESP:
! 			raise error_reply, resp
  		list = []
  		while 1:
  			line = self.getline()
--- 191,197 ----
  		Raise various errors if the response indicates an error."""
  		resp = self.getresp()
  		if resp[:3] not in LONGRESP:
! 			raise NNTPReplyError(resp)
  		list = []
  		while 1:
  			line = self.getline()
***************
*** 206,212 ****
  
  		resp = self.shortcmd('GROUP ' + name)
  		if resp[:3] <> '211':
! 			raise error_reply, resp
  		words = string.split(resp)
  		count = first = last = 0
  		n = len(words)
--- 257,263 ----
  
  		resp = self.shortcmd('GROUP ' + name)
  		if resp[:3] <> '211':
! 			raise NNTPReplyError(resp)
  		words = string.split(resp)
  		count = first = last = 0
  		n = len(words)
***************
*** 230,236 ****
  	def statparse(self, resp):
  		"""Internal: parse the response of a STAT, NEXT or LAST command."""
  		if resp[:2] <> '22':
! 			raise error_reply, resp
  		words = string.split(resp)
  		nr = 0
  		id = ''
--- 281,287 ----
  	def statparse(self, resp):
  		"""Internal: parse the response of a STAT, NEXT or LAST command."""
  		if resp[:2] <> '22':
! 			raise NNTPReplyError(resp)
  		words = string.split(resp)
  		nr = 0
  		id = ''
***************
*** 349,355 ****
  						    elem[6],
  						    elem[7]))
  			except IndexError:
! 				raise error_data,line
  		return resp,xover_lines
  
  	def xgtitle(self, group):
--- 400,406 ----
  						    elem[6],
  						    elem[7]))
  			except IndexError:
! 				raise NNTPDataError(line)
  		return resp,xover_lines
  
  	def xgtitle(self, group):
***************
*** 377,387 ****
  
  		resp = self.shortcmd("XPATH " + id)
  		if resp[:3] <> '223':
! 			raise error_reply, resp
  		try:
  			[resp_num, path] = string.split(resp)
  		except ValueError:
! 			raise error_reply, resp
  		else:
  			return resp, path
  
--- 428,438 ----
  
  		resp = self.shortcmd("XPATH " + id)
  		if resp[:3] <> '223':
! 			raise NNTPReplyError(resp)
  		try:
  			[resp_num, path] = string.split(resp)
  		except ValueError:
! 			raise NNTPReplyError(resp)
  		else:
  			return resp, path
  
***************
*** 395,408 ****
  
  		resp = self.shortcmd("DATE")
  		if resp[:3] <> '111':
! 			raise error_reply, resp
  		elem = string.split(resp)
  		if len(elem) != 2:
! 			raise error_data, resp
  		date = elem[1][2:8]
  		time = elem[1][-6:]
  		if len(date) != 6 or len(time) != 6:
! 			raise error_data, resp
  		return resp, date, time
  
  
--- 446,459 ----
  
  		resp = self.shortcmd("DATE")
  		if resp[:3] <> '111':
! 			raise NNTPReplyError(resp)
  		elem = string.split(resp)
  		if len(elem) != 2:
! 			raise NNTPDataError(resp)
  		date = elem[1][2:8]
  		time = elem[1][-6:]
  		if len(date) != 6 or len(time) != 6:
! 			raise NNTPDataError(resp)
  		return resp, date, time
  
  
***************
*** 415,421 ****
  		resp = self.shortcmd('POST')
  		# Raises error_??? if posting is not allowed
  		if resp[0] <> '3':
! 			raise error_reply, resp
  		while 1:
  			line = f.readline()
  			if not line:
--- 466,472 ----
  		resp = self.shortcmd('POST')
  		# Raises error_??? if posting is not allowed
  		if resp[0] <> '3':
! 			raise NNTPReplyError(resp)
  		while 1:
  			line = f.readline()
  			if not line:
***************
*** 439,445 ****
  		resp = self.shortcmd('IHAVE ' + id)
  		# Raises error_??? if the server already has it
  		if resp[0] <> '3':
! 			raise error_reply, resp
  		while 1:
  			line = f.readline()
  			if not line:
--- 490,496 ----
  		resp = self.shortcmd('IHAVE ' + id)
  		# Raises error_??? if the server already has it
  		if resp[0] <> '3':
! 			raise NNTPReplyError(resp)
  		while 1:
  			line = f.readline()
  			if not line:
***************
*** 465,471 ****
  
  def _test():
  	"""Minimal test function."""
! 	s = NNTP('news')
  	resp, count, first, last, name = s.group('comp.lang.python')
  	print resp
  	print 'Group', name, 'has', count, 'articles, range', first, 'to', last
--- 516,522 ----
  
  def _test():
  	"""Minimal test function."""
! 	s = NNTP('news', readermode='reader')
  	resp, count, first, last, name = s.group('comp.lang.python')
  	print resp
  	print 'Group', name, 'has', count, 'articles, range', first, 'to', last