summaryrefslogtreecommitdiffstats
path: root/Lib/nntplib.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/nntplib.py')
-rw-r--r--Lib/nntplib.py348
1 files changed, 173 insertions, 175 deletions
diff --git a/Lib/nntplib.py b/Lib/nntplib.py
index 21649a0..5a16fcb 100644
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -1,31 +1,31 @@
-# An NNTP client class. Based on RFC 977: Network News Transfer
-# Protocol, by Brian Kantor and Phil Lapsley.
-
-
-# Example:
-#
-# >>> from nntplib import NNTP
-# >>> s = NNTP('news')
-# >>> resp, count, first, last, name = s.group('comp.lang.python')
-# >>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
-# Group comp.lang.python has 51 articles, range 5770 to 5821
-# >>> resp, subs = s.xhdr('subject', first + '-' + last)
-# >>> resp = s.quit()
-# >>>
-#
-# Here 'resp' is the server response line.
-# Error responses are turned into exceptions.
-#
-# To post an article from a file:
-# >>> f = open(filename, 'r') # file containing article, including header
-# >>> resp = s.post(f)
-# >>>
-#
-# For descriptions of all methods, read the comments in the code below.
-# Note that all arguments and return values representing article numbers
-# are strings, not numbers, since they are rarely used for calculations.
-
-# (xover, xgtitle, xpath, date methods by Kevan Heydon)
+"""An NNTP client class based on RFC 977: Network News Transfer Protocol.
+
+Example:
+
+>>> from nntplib import NNTP
+>>> s = NNTP('news')
+>>> resp, count, first, last, name = s.group('comp.lang.python')
+>>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
+Group comp.lang.python has 51 articles, range 5770 to 5821
+>>> resp, subs = s.xhdr('subject', first + '-' + last)
+>>> resp = s.quit()
+>>>
+
+Here 'resp' is the server response line.
+Error responses are turned into exceptions.
+
+To post an article from a file:
+>>> f = open(filename, 'r') # file containing article, including header
+>>> resp = s.post(f)
+>>>
+
+For descriptions of all methods, read the comments in the code below.
+Note that all arguments and return values representing article numbers
+are strings, not numbers, since they are rarely used for calculations.
+"""
+
+# RFC 977 by Brian Kantor and Phil Lapsley.
+# xover, xgtitle, xpath, date methods by Kevan Heydon
# Imports
@@ -35,7 +35,6 @@ 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
@@ -59,11 +58,11 @@ CRLF = '\r\n'
class NNTP:
- # Initialize an instance. Arguments:
- # - host: hostname to connect to
- # - port: port to connect to (default the standard NNTP port)
-
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)
@@ -82,38 +81,38 @@ class NNTP:
if resp[:3] != '281':
raise error_perm, 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
+ (this is read and squirreled away by __init__()).
+ If the response code is 200, posting is allowed;
+ if it 201, posting is not allowed."""
+
if self.debugging: print '*welcome*', `self.welcome`
return self.welcome
- # Set the debugging level. Argument level means:
- # 0: no debugging output (default)
- # 1: print commands and responses but not body text etc.
- # 2: also print raw lines read and sent before stripping CR/LF
-
def set_debuglevel(self, level):
+ """Set the debugging level. Argument 'level' means:
+ 0: no debugging output (default)
+ 1: print commands and responses but not body text etc.
+ 2: also print raw lines read and sent before stripping CR/LF"""
+
self.debugging = level
debug = set_debuglevel
- # Internal: send one line to the server, appending CRLF
def putline(self, line):
+ """Internal: send one line to the server, appending CRLF."""
line = line + CRLF
if self.debugging > 1: print '*put*', `line`
self.sock.send(line)
- # Internal: send one command to the server (through putline())
def putcmd(self, line):
+ """Internal: send one command to the server (through putline())."""
if self.debugging: print '*cmd*', `line`
self.putline(line)
- # Internal: return one line from the server, stripping CRLF.
- # Raise EOFError if the connection is closed
def getline(self):
+ """Internal: return one line from the server, stripping CRLF.
+ Raise EOFError if the connection is closed."""
line = self.file.readline()
if self.debugging > 1:
print '*get*', `line`
@@ -122,9 +121,9 @@ class NNTP:
elif line[-1:] in CRLF: line = line[:-1]
return line
- # Internal: get a response from the server.
- # Raise various errors if the response indicates an error
def getresp(self):
+ """Internal: get a response from the server.
+ Raise various errors if the response indicates an error."""
resp = self.getline()
if self.debugging: print '*resp*', `resp`
c = resp[:1]
@@ -136,9 +135,9 @@ class NNTP:
raise error_proto, resp
return resp
- # Internal: get a response plus following text from the server.
- # Raise various errors if the response indicates an error
def getlongresp(self):
+ """Internal: get a response plus following text from the server.
+ Raise various errors if the response indicates an error."""
resp = self.getresp()
if resp[:3] not in LONGRESP:
raise error_reply, resp
@@ -152,59 +151,59 @@ class NNTP:
list.append(line)
return resp, list
- # Internal: send a command and get the response
def shortcmd(self, line):
+ """Internal: send a command and get the response."""
self.putcmd(line)
return self.getresp()
- # Internal: send a command and get the response plus following text
def longcmd(self, line):
+ """Internal: send a command and get the response plus following text."""
self.putcmd(line)
return self.getlongresp()
- # Process a NEWGROUPS command. Arguments:
- # - date: string 'yymmdd' indicating the date
- # - time: string 'hhmmss' indicating the time
- # Return:
- # - resp: server response if succesful
- # - list: list of newsgroup names
-
def newgroups(self, date, time):
- return self.longcmd('NEWGROUPS ' + date + ' ' + time)
+ """Process a NEWGROUPS command. Arguments:
+ - date: string 'yymmdd' indicating the date
+ - time: string 'hhmmss' indicating the time
+ Return:
+ - resp: server response if succesful
+ - list: list of newsgroup names"""
- # Process a NEWNEWS command. Arguments:
- # - group: group name or '*'
- # - date: string 'yymmdd' indicating the date
- # - time: string 'hhmmss' indicating the time
- # Return:
- # - resp: server response if succesful
- # - list: list of article ids
+ return self.longcmd('NEWGROUPS ' + date + ' ' + time)
def newnews(self, group, date, time):
+ """Process a NEWNEWS command. Arguments:
+ - group: group name or '*'
+ - date: string 'yymmdd' indicating the date
+ - time: string 'hhmmss' indicating the time
+ Return:
+ - resp: server response if succesful
+ - list: list of article ids"""
+
cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
return self.longcmd(cmd)
- # Process a LIST command. Return:
- # - resp: server response if succesful
- # - list: list of (group, last, first, flag) (strings)
-
def list(self):
+ """Process a LIST command. Return:
+ - resp: server response if succesful
+ - list: list of (group, last, first, flag) (strings)"""
+
resp, list = self.longcmd('LIST')
for i in range(len(list)):
# Parse lines into "group last first flag"
list[i] = tuple(string.split(list[i]))
return resp, list
- # Process a GROUP command. Argument:
- # - group: the group name
- # Returns:
- # - resp: server response if succesful
- # - count: number of articles (string)
- # - first: first article number (string)
- # - last: last article number (string)
- # - name: the group name
-
def group(self, name):
+ """Process a GROUP command. Argument:
+ - group: the group name
+ Returns:
+ - resp: server response if succesful
+ - count: number of articles (string)
+ - first: first article number (string)
+ - last: last article number (string)
+ - name: the group name"""
+
resp = self.shortcmd('GROUP ' + name)
if resp[:3] <> '211':
raise error_reply, resp
@@ -221,15 +220,15 @@ class NNTP:
name = string.lower(words[4])
return resp, count, first, last, name
- # Process a HELP command. Returns:
- # - resp: server response if succesful
- # - list: list of strings
-
def help(self):
+ """Process a HELP command. Returns:
+ - resp: server response if succesful
+ - list: list of strings"""
+
return self.longcmd('HELP')
- # Internal: parse the response of a STAT, NEXT or LAST command
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)
@@ -242,84 +241,82 @@ class NNTP:
id = words[2]
return resp, nr, id
- # Internal: process a STAT, NEXT or LAST command
def statcmd(self, line):
+ """Internal: process a STAT, NEXT or LAST command."""
resp = self.shortcmd(line)
return self.statparse(resp)
- # Process a STAT command. Argument:
- # - id: article number or message id
- # Returns:
- # - resp: server response if succesful
- # - nr: the article number
- # - id: the article id
-
def stat(self, id):
- return self.statcmd('STAT ' + id)
+ """Process a STAT command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if succesful
+ - nr: the article number
+ - id: the article id"""
- # Process a NEXT command. No arguments. Return as for STAT
+ return self.statcmd('STAT ' + id)
def next(self):
+ """Process a NEXT command. No arguments. Return as for STAT."""
return self.statcmd('NEXT')
- # Process a LAST command. No arguments. Return as for STAT
-
def last(self):
+ """Process a LAST command. No arguments. Return as for STAT."""
return self.statcmd('LAST')
- # Internal: process a HEAD, BODY or ARTICLE command
def artcmd(self, line):
+ """Internal: process a HEAD, BODY or ARTICLE command."""
resp, list = self.longcmd(line)
resp, nr, id = self.statparse(resp)
return resp, nr, id, list
- # Process a HEAD command. Argument:
- # - id: article number or message id
- # Returns:
- # - resp: server response if succesful
- # - nr: article number
- # - id: message id
- # - list: the lines of the article's header
-
def head(self, id):
- return self.artcmd('HEAD ' + id)
+ """Process a HEAD command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if succesful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article's header"""
- # Process a BODY command. Argument:
- # - id: article number or message id
- # Returns:
- # - resp: server response if succesful
- # - nr: article number
- # - id: message id
- # - list: the lines of the article's body
+ return self.artcmd('HEAD ' + id)
def body(self, id):
- return self.artcmd('BODY ' + id)
+ """Process a BODY command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if succesful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article's body"""
- # Process an ARTICLE command. Argument:
- # - id: article number or message id
- # Returns:
- # - resp: server response if succesful
- # - nr: article number
- # - id: message id
- # - list: the lines of the article
+ return self.artcmd('BODY ' + id)
def article(self, id):
- return self.artcmd('ARTICLE ' + id)
+ """Process an ARTICLE command. Argument:
+ - id: article number or message id
+ Returns:
+ - resp: server response if succesful
+ - nr: article number
+ - id: message id
+ - list: the lines of the article"""
- # Process a SLAVE command. Returns:
- # - resp: server response if succesful
+ return self.artcmd('ARTICLE ' + id)
def slave(self):
- return self.shortcmd('SLAVE')
+ """Process a SLAVE command. Returns:
+ - resp: server response if succesful"""
- # Process an XHDR command (optional server extension). Arguments:
- # - hdr: the header type (e.g. 'subject')
- # - str: an article nr, a message id, or a range nr1-nr2
- # Returns:
- # - resp: server response if succesful
- # - list: list of (nr, value) strings
+ return self.shortcmd('SLAVE')
def xhdr(self, hdr, str):
+ """Process an XHDR command (optional server extension). Arguments:
+ - hdr: the header type (e.g. 'subject')
+ - str: an article nr, a message id, or a range nr1-nr2
+ Returns:
+ - resp: server response if succesful
+ - list: list of (nr, value) strings"""
+
pat = re.compile('^([0-9]+) ?(.*)\n?')
resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
for i in range(len(lines)):
@@ -329,14 +326,15 @@ class NNTP:
lines[i] = m.group(1, 2)
return resp, lines
- # Process an XOVER command (optional server extension) Arguments:
- # - start: start of range
- # - end: end of range
- # Returns:
- # - resp: server response if succesful
- # - list: list of (art-nr, subject, poster, date, id, refrences, size, lines)
-
def xover(self,start,end):
+ """Process an XOVER command (optional server extension) Arguments:
+ - start: start of range
+ - end: end of range
+ Returns:
+ - resp: server response if succesful
+ - list: list of (art-nr, subject, poster, date,
+ id, references, size, lines)"""
+
resp, lines = self.longcmd('XOVER ' + start + '-' + end)
xover_lines = []
for line in lines:
@@ -354,13 +352,13 @@ class NNTP:
raise error_data,line
return resp,xover_lines
- # Process an XGTITLE command (optional server extension) Arguments:
- # - group: group name wildcard (i.e. news.*)
- # Returns:
- # - resp: server response if succesful
- # - list: list of (name,title) strings
-
def xgtitle(self, group):
+ """Process an XGTITLE command (optional server extension) Arguments:
+ - group: group name wildcard (i.e. news.*)
+ Returns:
+ - resp: server response if succesful
+ - list: list of (name,title) strings"""
+
line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
resp, raw_lines = self.longcmd('XGTITLE ' + group)
lines = []
@@ -370,13 +368,13 @@ class NNTP:
lines.append(match.group(1, 2))
return resp, lines
- # Process an XPATH command (optional server extension) Arguments:
- # - id: Message id of article
- # Returns:
- # resp: server response if succesful
- # path: directory path to article
-
def xpath(self,id):
+ """Process an XPATH command (optional server extension) Arguments:
+ - id: Message id of article
+ Returns:
+ resp: server response if succesful
+ path: directory path to article"""
+
resp = self.shortcmd("XPATH " + id)
if resp[:3] <> '223':
raise error_reply, resp
@@ -387,14 +385,14 @@ class NNTP:
else:
return resp, path
- # Process the DATE command. Arguments:
- # None
- # Returns:
- # resp: server response if succesful
- # date: Date suitable for newnews/newgroups commands etc.
- # time: Time suitable for newnews/newgroups commands etc.
-
def date (self):
+ """Process the DATE command. Arguments:
+ None
+ Returns:
+ resp: server response if succesful
+ date: Date suitable for newnews/newgroups commands etc.
+ time: Time suitable for newnews/newgroups commands etc."""
+
resp = self.shortcmd("DATE")
if resp[:3] <> '111':
raise error_reply, resp
@@ -408,12 +406,12 @@ class NNTP:
return resp, date, time
- # Process a POST command. Arguments:
- # - f: file containing the article
- # Returns:
- # - resp: server response if succesful
-
def post(self, f):
+ """Process a POST command. Arguments:
+ - f: file containing the article
+ Returns:
+ - resp: server response if succesful"""
+
resp = self.shortcmd('POST')
# Raises error_??? if posting is not allowed
if resp[0] <> '3':
@@ -430,14 +428,14 @@ class NNTP:
self.putline('.')
return self.getresp()
- # Process an IHAVE command. Arguments:
- # - id: message-id of the article
- # - f: file containing the article
- # Returns:
- # - resp: server response if succesful
- # Note that if the server refuses the article an exception is raised
-
def ihave(self, id, f):
+ """Process an IHAVE command. Arguments:
+ - id: message-id of the article
+ - f: file containing the article
+ Returns:
+ - resp: server response if succesful
+ Note that if the server refuses the article an exception is raised."""
+
resp = self.shortcmd('IHAVE ' + id)
# Raises error_??? if the server already has it
if resp[0] <> '3':
@@ -454,10 +452,10 @@ class NNTP:
self.putline('.')
return self.getresp()
- # Process a QUIT command and close the socket. Returns:
- # - resp: server response if succesful
-
def quit(self):
+ """Process a QUIT command and close the socket. Returns:
+ - resp: server response if succesful"""
+
resp = self.shortcmd('QUIT')
self.file.close()
self.sock.close()
@@ -465,8 +463,8 @@ class NNTP:
return resp
-# Minimal test function
def _test():
+ """Minimal test function."""
s = NNTP('news')
resp, count, first, last, name = s.group('comp.lang.python')
print resp