Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ExeBy/smexe_ro.../lib64/python2....
File: nntplib.py
"""An NNTP client class based on RFC 977: Network News Transfer Protocol.
[0] Fix | Delete
[1] Fix | Delete
Example:
[2] Fix | Delete
[3] Fix | Delete
>>> from nntplib import NNTP
[4] Fix | Delete
>>> s = NNTP('news')
[5] Fix | Delete
>>> resp, count, first, last, name = s.group('comp.lang.python')
[6] Fix | Delete
>>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
[7] Fix | Delete
Group comp.lang.python has 51 articles, range 5770 to 5821
[8] Fix | Delete
>>> resp, subs = s.xhdr('subject', first + '-' + last)
[9] Fix | Delete
>>> resp = s.quit()
[10] Fix | Delete
>>>
[11] Fix | Delete
[12] Fix | Delete
Here 'resp' is the server response line.
[13] Fix | Delete
Error responses are turned into exceptions.
[14] Fix | Delete
[15] Fix | Delete
To post an article from a file:
[16] Fix | Delete
>>> f = open(filename, 'r') # file containing article, including header
[17] Fix | Delete
>>> resp = s.post(f)
[18] Fix | Delete
>>>
[19] Fix | Delete
[20] Fix | Delete
For descriptions of all methods, read the comments in the code below.
[21] Fix | Delete
Note that all arguments and return values representing article numbers
[22] Fix | Delete
are strings, not numbers, since they are rarely used for calculations.
[23] Fix | Delete
"""
[24] Fix | Delete
[25] Fix | Delete
# RFC 977 by Brian Kantor and Phil Lapsley.
[26] Fix | Delete
# xover, xgtitle, xpath, date methods by Kevan Heydon
[27] Fix | Delete
[28] Fix | Delete
[29] Fix | Delete
# Imports
[30] Fix | Delete
import re
[31] Fix | Delete
import socket
[32] Fix | Delete
[33] Fix | Delete
__all__ = ["NNTP","NNTPReplyError","NNTPTemporaryError",
[34] Fix | Delete
"NNTPPermanentError","NNTPProtocolError","NNTPDataError",
[35] Fix | Delete
"error_reply","error_temp","error_perm","error_proto",
[36] Fix | Delete
"error_data",]
[37] Fix | Delete
[38] Fix | Delete
# maximal line length when calling readline(). This is to prevent
[39] Fix | Delete
# reading arbitrary length lines. RFC 3977 limits NNTP line length to
[40] Fix | Delete
# 512 characters, including CRLF. We have selected 2048 just to be on
[41] Fix | Delete
# the safe side.
[42] Fix | Delete
_MAXLINE = 2048
[43] Fix | Delete
[44] Fix | Delete
[45] Fix | Delete
# Exceptions raised when an error or invalid response is received
[46] Fix | Delete
class NNTPError(Exception):
[47] Fix | Delete
"""Base class for all nntplib exceptions"""
[48] Fix | Delete
def __init__(self, *args):
[49] Fix | Delete
Exception.__init__(self, *args)
[50] Fix | Delete
try:
[51] Fix | Delete
self.response = args[0]
[52] Fix | Delete
except IndexError:
[53] Fix | Delete
self.response = 'No response given'
[54] Fix | Delete
[55] Fix | Delete
class NNTPReplyError(NNTPError):
[56] Fix | Delete
"""Unexpected [123]xx reply"""
[57] Fix | Delete
pass
[58] Fix | Delete
[59] Fix | Delete
class NNTPTemporaryError(NNTPError):
[60] Fix | Delete
"""4xx errors"""
[61] Fix | Delete
pass
[62] Fix | Delete
[63] Fix | Delete
class NNTPPermanentError(NNTPError):
[64] Fix | Delete
"""5xx errors"""
[65] Fix | Delete
pass
[66] Fix | Delete
[67] Fix | Delete
class NNTPProtocolError(NNTPError):
[68] Fix | Delete
"""Response does not begin with [1-5]"""
[69] Fix | Delete
pass
[70] Fix | Delete
[71] Fix | Delete
class NNTPDataError(NNTPError):
[72] Fix | Delete
"""Error in response data"""
[73] Fix | Delete
pass
[74] Fix | Delete
[75] Fix | Delete
# for backwards compatibility
[76] Fix | Delete
error_reply = NNTPReplyError
[77] Fix | Delete
error_temp = NNTPTemporaryError
[78] Fix | Delete
error_perm = NNTPPermanentError
[79] Fix | Delete
error_proto = NNTPProtocolError
[80] Fix | Delete
error_data = NNTPDataError
[81] Fix | Delete
[82] Fix | Delete
[83] Fix | Delete
[84] Fix | Delete
# Standard port used by NNTP servers
[85] Fix | Delete
NNTP_PORT = 119
[86] Fix | Delete
[87] Fix | Delete
[88] Fix | Delete
# Response numbers that are followed by additional text (e.g. article)
[89] Fix | Delete
LONGRESP = ['100', '215', '220', '221', '222', '224', '230', '231', '282']
[90] Fix | Delete
[91] Fix | Delete
[92] Fix | Delete
# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
[93] Fix | Delete
CRLF = '\r\n'
[94] Fix | Delete
[95] Fix | Delete
[96] Fix | Delete
[97] Fix | Delete
# The class itself
[98] Fix | Delete
class NNTP:
[99] Fix | Delete
def __init__(self, host, port=NNTP_PORT, user=None, password=None,
[100] Fix | Delete
readermode=None, usenetrc=True):
[101] Fix | Delete
"""Initialize an instance. Arguments:
[102] Fix | Delete
- host: hostname to connect to
[103] Fix | Delete
- port: port to connect to (default the standard NNTP port)
[104] Fix | Delete
- user: username to authenticate with
[105] Fix | Delete
- password: password to use with username
[106] Fix | Delete
- readermode: if true, send 'mode reader' command after
[107] Fix | Delete
connecting.
[108] Fix | Delete
[109] Fix | Delete
readermode is sometimes necessary if you are connecting to an
[110] Fix | Delete
NNTP server on the local machine and intend to call
[111] Fix | Delete
reader-specific commands, such as `group'. If you get
[112] Fix | Delete
unexpected NNTPPermanentErrors, you might need to set
[113] Fix | Delete
readermode.
[114] Fix | Delete
"""
[115] Fix | Delete
self.host = host
[116] Fix | Delete
self.port = port
[117] Fix | Delete
self.sock = socket.create_connection((host, port))
[118] Fix | Delete
self.file = self.sock.makefile('rb')
[119] Fix | Delete
self.debugging = 0
[120] Fix | Delete
self.welcome = self.getresp()
[121] Fix | Delete
[122] Fix | Delete
# 'mode reader' is sometimes necessary to enable 'reader' mode.
[123] Fix | Delete
# However, the order in which 'mode reader' and 'authinfo' need to
[124] Fix | Delete
# arrive differs between some NNTP servers. Try to send
[125] Fix | Delete
# 'mode reader', and if it fails with an authorization failed
[126] Fix | Delete
# error, try again after sending authinfo.
[127] Fix | Delete
readermode_afterauth = 0
[128] Fix | Delete
if readermode:
[129] Fix | Delete
try:
[130] Fix | Delete
self.welcome = self.shortcmd('mode reader')
[131] Fix | Delete
except NNTPPermanentError:
[132] Fix | Delete
# error 500, probably 'not implemented'
[133] Fix | Delete
pass
[134] Fix | Delete
except NNTPTemporaryError, e:
[135] Fix | Delete
if user and e.response[:3] == '480':
[136] Fix | Delete
# Need authorization before 'mode reader'
[137] Fix | Delete
readermode_afterauth = 1
[138] Fix | Delete
else:
[139] Fix | Delete
raise
[140] Fix | Delete
# If no login/password was specified, try to get them from ~/.netrc
[141] Fix | Delete
# Presume that if .netc has an entry, NNRP authentication is required.
[142] Fix | Delete
try:
[143] Fix | Delete
if usenetrc and not user:
[144] Fix | Delete
import netrc
[145] Fix | Delete
credentials = netrc.netrc()
[146] Fix | Delete
auth = credentials.authenticators(host)
[147] Fix | Delete
if auth:
[148] Fix | Delete
user = auth[0]
[149] Fix | Delete
password = auth[2]
[150] Fix | Delete
except IOError:
[151] Fix | Delete
pass
[152] Fix | Delete
# Perform NNRP authentication if needed.
[153] Fix | Delete
if user:
[154] Fix | Delete
resp = self.shortcmd('authinfo user '+user)
[155] Fix | Delete
if resp[:3] == '381':
[156] Fix | Delete
if not password:
[157] Fix | Delete
raise NNTPReplyError(resp)
[158] Fix | Delete
else:
[159] Fix | Delete
resp = self.shortcmd(
[160] Fix | Delete
'authinfo pass '+password)
[161] Fix | Delete
if resp[:3] != '281':
[162] Fix | Delete
raise NNTPPermanentError(resp)
[163] Fix | Delete
if readermode_afterauth:
[164] Fix | Delete
try:
[165] Fix | Delete
self.welcome = self.shortcmd('mode reader')
[166] Fix | Delete
except NNTPPermanentError:
[167] Fix | Delete
# error 500, probably 'not implemented'
[168] Fix | Delete
pass
[169] Fix | Delete
[170] Fix | Delete
[171] Fix | Delete
# Get the welcome message from the server
[172] Fix | Delete
# (this is read and squirreled away by __init__()).
[173] Fix | Delete
# If the response code is 200, posting is allowed;
[174] Fix | Delete
# if it 201, posting is not allowed
[175] Fix | Delete
[176] Fix | Delete
def getwelcome(self):
[177] Fix | Delete
"""Get the welcome message from the server
[178] Fix | Delete
(this is read and squirreled away by __init__()).
[179] Fix | Delete
If the response code is 200, posting is allowed;
[180] Fix | Delete
if it 201, posting is not allowed."""
[181] Fix | Delete
[182] Fix | Delete
if self.debugging: print '*welcome*', repr(self.welcome)
[183] Fix | Delete
return self.welcome
[184] Fix | Delete
[185] Fix | Delete
def set_debuglevel(self, level):
[186] Fix | Delete
"""Set the debugging level. Argument 'level' means:
[187] Fix | Delete
0: no debugging output (default)
[188] Fix | Delete
1: print commands and responses but not body text etc.
[189] Fix | Delete
2: also print raw lines read and sent before stripping CR/LF"""
[190] Fix | Delete
[191] Fix | Delete
self.debugging = level
[192] Fix | Delete
debug = set_debuglevel
[193] Fix | Delete
[194] Fix | Delete
def putline(self, line):
[195] Fix | Delete
"""Internal: send one line to the server, appending CRLF."""
[196] Fix | Delete
line = line + CRLF
[197] Fix | Delete
if self.debugging > 1: print '*put*', repr(line)
[198] Fix | Delete
self.sock.sendall(line)
[199] Fix | Delete
[200] Fix | Delete
def putcmd(self, line):
[201] Fix | Delete
"""Internal: send one command to the server (through putline())."""
[202] Fix | Delete
if self.debugging: print '*cmd*', repr(line)
[203] Fix | Delete
self.putline(line)
[204] Fix | Delete
[205] Fix | Delete
def getline(self):
[206] Fix | Delete
"""Internal: return one line from the server, stripping CRLF.
[207] Fix | Delete
Raise EOFError if the connection is closed."""
[208] Fix | Delete
line = self.file.readline(_MAXLINE + 1)
[209] Fix | Delete
if len(line) > _MAXLINE:
[210] Fix | Delete
raise NNTPDataError('line too long')
[211] Fix | Delete
if self.debugging > 1:
[212] Fix | Delete
print '*get*', repr(line)
[213] Fix | Delete
if not line: raise EOFError
[214] Fix | Delete
if line[-2:] == CRLF: line = line[:-2]
[215] Fix | Delete
elif line[-1:] in CRLF: line = line[:-1]
[216] Fix | Delete
return line
[217] Fix | Delete
[218] Fix | Delete
def getresp(self):
[219] Fix | Delete
"""Internal: get a response from the server.
[220] Fix | Delete
Raise various errors if the response indicates an error."""
[221] Fix | Delete
resp = self.getline()
[222] Fix | Delete
if self.debugging: print '*resp*', repr(resp)
[223] Fix | Delete
c = resp[:1]
[224] Fix | Delete
if c == '4':
[225] Fix | Delete
raise NNTPTemporaryError(resp)
[226] Fix | Delete
if c == '5':
[227] Fix | Delete
raise NNTPPermanentError(resp)
[228] Fix | Delete
if c not in '123':
[229] Fix | Delete
raise NNTPProtocolError(resp)
[230] Fix | Delete
return resp
[231] Fix | Delete
[232] Fix | Delete
def getlongresp(self, file=None):
[233] Fix | Delete
"""Internal: get a response plus following text from the server.
[234] Fix | Delete
Raise various errors if the response indicates an error."""
[235] Fix | Delete
[236] Fix | Delete
openedFile = None
[237] Fix | Delete
try:
[238] Fix | Delete
# If a string was passed then open a file with that name
[239] Fix | Delete
if isinstance(file, str):
[240] Fix | Delete
openedFile = file = open(file, "w")
[241] Fix | Delete
[242] Fix | Delete
resp = self.getresp()
[243] Fix | Delete
if resp[:3] not in LONGRESP:
[244] Fix | Delete
raise NNTPReplyError(resp)
[245] Fix | Delete
list = []
[246] Fix | Delete
while 1:
[247] Fix | Delete
line = self.getline()
[248] Fix | Delete
if line == '.':
[249] Fix | Delete
break
[250] Fix | Delete
if line[:2] == '..':
[251] Fix | Delete
line = line[1:]
[252] Fix | Delete
if file:
[253] Fix | Delete
file.write(line + "\n")
[254] Fix | Delete
else:
[255] Fix | Delete
list.append(line)
[256] Fix | Delete
finally:
[257] Fix | Delete
# If this method created the file, then it must close it
[258] Fix | Delete
if openedFile:
[259] Fix | Delete
openedFile.close()
[260] Fix | Delete
[261] Fix | Delete
return resp, list
[262] Fix | Delete
[263] Fix | Delete
def shortcmd(self, line):
[264] Fix | Delete
"""Internal: send a command and get the response."""
[265] Fix | Delete
self.putcmd(line)
[266] Fix | Delete
return self.getresp()
[267] Fix | Delete
[268] Fix | Delete
def longcmd(self, line, file=None):
[269] Fix | Delete
"""Internal: send a command and get the response plus following text."""
[270] Fix | Delete
self.putcmd(line)
[271] Fix | Delete
return self.getlongresp(file)
[272] Fix | Delete
[273] Fix | Delete
def newgroups(self, date, time, file=None):
[274] Fix | Delete
"""Process a NEWGROUPS command. Arguments:
[275] Fix | Delete
- date: string 'yymmdd' indicating the date
[276] Fix | Delete
- time: string 'hhmmss' indicating the time
[277] Fix | Delete
Return:
[278] Fix | Delete
- resp: server response if successful
[279] Fix | Delete
- list: list of newsgroup names"""
[280] Fix | Delete
[281] Fix | Delete
return self.longcmd('NEWGROUPS ' + date + ' ' + time, file)
[282] Fix | Delete
[283] Fix | Delete
def newnews(self, group, date, time, file=None):
[284] Fix | Delete
"""Process a NEWNEWS command. Arguments:
[285] Fix | Delete
- group: group name or '*'
[286] Fix | Delete
- date: string 'yymmdd' indicating the date
[287] Fix | Delete
- time: string 'hhmmss' indicating the time
[288] Fix | Delete
Return:
[289] Fix | Delete
- resp: server response if successful
[290] Fix | Delete
- list: list of message ids"""
[291] Fix | Delete
[292] Fix | Delete
cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
[293] Fix | Delete
return self.longcmd(cmd, file)
[294] Fix | Delete
[295] Fix | Delete
def list(self, file=None):
[296] Fix | Delete
"""Process a LIST command. Return:
[297] Fix | Delete
- resp: server response if successful
[298] Fix | Delete
- list: list of (group, last, first, flag) (strings)"""
[299] Fix | Delete
[300] Fix | Delete
resp, list = self.longcmd('LIST', file)
[301] Fix | Delete
for i in range(len(list)):
[302] Fix | Delete
# Parse lines into "group last first flag"
[303] Fix | Delete
list[i] = tuple(list[i].split())
[304] Fix | Delete
return resp, list
[305] Fix | Delete
[306] Fix | Delete
def description(self, group):
[307] Fix | Delete
[308] Fix | Delete
"""Get a description for a single group. If more than one
[309] Fix | Delete
group matches ('group' is a pattern), return the first. If no
[310] Fix | Delete
group matches, return an empty string.
[311] Fix | Delete
[312] Fix | Delete
This elides the response code from the server, since it can
[313] Fix | Delete
only be '215' or '285' (for xgtitle) anyway. If the response
[314] Fix | Delete
code is needed, use the 'descriptions' method.
[315] Fix | Delete
[316] Fix | Delete
NOTE: This neither checks for a wildcard in 'group' nor does
[317] Fix | Delete
it check whether the group actually exists."""
[318] Fix | Delete
[319] Fix | Delete
resp, lines = self.descriptions(group)
[320] Fix | Delete
if len(lines) == 0:
[321] Fix | Delete
return ""
[322] Fix | Delete
else:
[323] Fix | Delete
return lines[0][1]
[324] Fix | Delete
[325] Fix | Delete
def descriptions(self, group_pattern):
[326] Fix | Delete
"""Get descriptions for a range of groups."""
[327] Fix | Delete
line_pat = re.compile("^(?P<group>[^ \t]+)[ \t]+(.*)$")
[328] Fix | Delete
# Try the more std (acc. to RFC2980) LIST NEWSGROUPS first
[329] Fix | Delete
resp, raw_lines = self.longcmd('LIST NEWSGROUPS ' + group_pattern)
[330] Fix | Delete
if resp[:3] != "215":
[331] Fix | Delete
# Now the deprecated XGTITLE. This either raises an error
[332] Fix | Delete
# or succeeds with the same output structure as LIST
[333] Fix | Delete
# NEWSGROUPS.
[334] Fix | Delete
resp, raw_lines = self.longcmd('XGTITLE ' + group_pattern)
[335] Fix | Delete
lines = []
[336] Fix | Delete
for raw_line in raw_lines:
[337] Fix | Delete
match = line_pat.search(raw_line.strip())
[338] Fix | Delete
if match:
[339] Fix | Delete
lines.append(match.group(1, 2))
[340] Fix | Delete
return resp, lines
[341] Fix | Delete
[342] Fix | Delete
def group(self, name):
[343] Fix | Delete
"""Process a GROUP command. Argument:
[344] Fix | Delete
- group: the group name
[345] Fix | Delete
Returns:
[346] Fix | Delete
- resp: server response if successful
[347] Fix | Delete
- count: number of articles (string)
[348] Fix | Delete
- first: first article number (string)
[349] Fix | Delete
- last: last article number (string)
[350] Fix | Delete
- name: the group name"""
[351] Fix | Delete
[352] Fix | Delete
resp = self.shortcmd('GROUP ' + name)
[353] Fix | Delete
if resp[:3] != '211':
[354] Fix | Delete
raise NNTPReplyError(resp)
[355] Fix | Delete
words = resp.split()
[356] Fix | Delete
count = first = last = 0
[357] Fix | Delete
n = len(words)
[358] Fix | Delete
if n > 1:
[359] Fix | Delete
count = words[1]
[360] Fix | Delete
if n > 2:
[361] Fix | Delete
first = words[2]
[362] Fix | Delete
if n > 3:
[363] Fix | Delete
last = words[3]
[364] Fix | Delete
if n > 4:
[365] Fix | Delete
name = words[4].lower()
[366] Fix | Delete
return resp, count, first, last, name
[367] Fix | Delete
[368] Fix | Delete
def help(self, file=None):
[369] Fix | Delete
"""Process a HELP command. Returns:
[370] Fix | Delete
- resp: server response if successful
[371] Fix | Delete
- list: list of strings"""
[372] Fix | Delete
[373] Fix | Delete
return self.longcmd('HELP',file)
[374] Fix | Delete
[375] Fix | Delete
def statparse(self, resp):
[376] Fix | Delete
"""Internal: parse the response of a STAT, NEXT or LAST command."""
[377] Fix | Delete
if resp[:2] != '22':
[378] Fix | Delete
raise NNTPReplyError(resp)
[379] Fix | Delete
words = resp.split()
[380] Fix | Delete
nr = 0
[381] Fix | Delete
id = ''
[382] Fix | Delete
n = len(words)
[383] Fix | Delete
if n > 1:
[384] Fix | Delete
nr = words[1]
[385] Fix | Delete
if n > 2:
[386] Fix | Delete
id = words[2]
[387] Fix | Delete
return resp, nr, id
[388] Fix | Delete
[389] Fix | Delete
def statcmd(self, line):
[390] Fix | Delete
"""Internal: process a STAT, NEXT or LAST command."""
[391] Fix | Delete
resp = self.shortcmd(line)
[392] Fix | Delete
return self.statparse(resp)
[393] Fix | Delete
[394] Fix | Delete
def stat(self, id):
[395] Fix | Delete
"""Process a STAT command. Argument:
[396] Fix | Delete
- id: article number or message id
[397] Fix | Delete
Returns:
[398] Fix | Delete
- resp: server response if successful
[399] Fix | Delete
- nr: the article number
[400] Fix | Delete
- id: the message id"""
[401] Fix | Delete
[402] Fix | Delete
return self.statcmd('STAT ' + id)
[403] Fix | Delete
[404] Fix | Delete
def next(self):
[405] Fix | Delete
"""Process a NEXT command. No arguments. Return as for STAT."""
[406] Fix | Delete
return self.statcmd('NEXT')
[407] Fix | Delete
[408] Fix | Delete
def last(self):
[409] Fix | Delete
"""Process a LAST command. No arguments. Return as for STAT."""
[410] Fix | Delete
return self.statcmd('LAST')
[411] Fix | Delete
[412] Fix | Delete
def artcmd(self, line, file=None):
[413] Fix | Delete
"""Internal: process a HEAD, BODY or ARTICLE command."""
[414] Fix | Delete
resp, list = self.longcmd(line, file)
[415] Fix | Delete
resp, nr, id = self.statparse(resp)
[416] Fix | Delete
return resp, nr, id, list
[417] Fix | Delete
[418] Fix | Delete
def head(self, id):
[419] Fix | Delete
"""Process a HEAD command. Argument:
[420] Fix | Delete
- id: article number or message id
[421] Fix | Delete
Returns:
[422] Fix | Delete
- resp: server response if successful
[423] Fix | Delete
- nr: article number
[424] Fix | Delete
- id: message id
[425] Fix | Delete
- list: the lines of the article's header"""
[426] Fix | Delete
[427] Fix | Delete
return self.artcmd('HEAD ' + id)
[428] Fix | Delete
[429] Fix | Delete
def body(self, id, file=None):
[430] Fix | Delete
"""Process a BODY command. Argument:
[431] Fix | Delete
- id: article number or message id
[432] Fix | Delete
- file: Filename string or file object to store the article in
[433] Fix | Delete
Returns:
[434] Fix | Delete
- resp: server response if successful
[435] Fix | Delete
- nr: article number
[436] Fix | Delete
- id: message id
[437] Fix | Delete
- list: the lines of the article's body or an empty list
[438] Fix | Delete
if file was used"""
[439] Fix | Delete
[440] Fix | Delete
return self.artcmd('BODY ' + id, file)
[441] Fix | Delete
[442] Fix | Delete
def article(self, id):
[443] Fix | Delete
"""Process an ARTICLE command. Argument:
[444] Fix | Delete
- id: article number or message id
[445] Fix | Delete
Returns:
[446] Fix | Delete
- resp: server response if successful
[447] Fix | Delete
- nr: article number
[448] Fix | Delete
- id: message id
[449] Fix | Delete
- list: the lines of the article"""
[450] Fix | Delete
[451] Fix | Delete
return self.artcmd('ARTICLE ' + id)
[452] Fix | Delete
[453] Fix | Delete
def slave(self):
[454] Fix | Delete
"""Process a SLAVE command. Returns:
[455] Fix | Delete
- resp: server response if successful"""
[456] Fix | Delete
[457] Fix | Delete
return self.shortcmd('SLAVE')
[458] Fix | Delete
[459] Fix | Delete
def xhdr(self, hdr, str, file=None):
[460] Fix | Delete
"""Process an XHDR command (optional server extension). Arguments:
[461] Fix | Delete
- hdr: the header type (e.g. 'subject')
[462] Fix | Delete
- str: an article nr, a message id, or a range nr1-nr2
[463] Fix | Delete
Returns:
[464] Fix | Delete
- resp: server response if successful
[465] Fix | Delete
- list: list of (nr, value) strings"""
[466] Fix | Delete
[467] Fix | Delete
pat = re.compile('^([0-9]+) ?(.*)\n?')
[468] Fix | Delete
resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str, file)
[469] Fix | Delete
for i in range(len(lines)):
[470] Fix | Delete
line = lines[i]
[471] Fix | Delete
m = pat.match(line)
[472] Fix | Delete
if m:
[473] Fix | Delete
lines[i] = m.group(1, 2)
[474] Fix | Delete
return resp, lines
[475] Fix | Delete
[476] Fix | Delete
def xover(self, start, end, file=None):
[477] Fix | Delete
"""Process an XOVER command (optional server extension) Arguments:
[478] Fix | Delete
- start: start of range
[479] Fix | Delete
- end: end of range
[480] Fix | Delete
Returns:
[481] Fix | Delete
- resp: server response if successful
[482] Fix | Delete
- list: list of (art-nr, subject, poster, date,
[483] Fix | Delete
id, references, size, lines)"""
[484] Fix | Delete
[485] Fix | Delete
resp, lines = self.longcmd('XOVER ' + start + '-' + end, file)
[486] Fix | Delete
xover_lines = []
[487] Fix | Delete
for line in lines:
[488] Fix | Delete
elem = line.split("\t")
[489] Fix | Delete
try:
[490] Fix | Delete
xover_lines.append((elem[0],
[491] Fix | Delete
elem[1],
[492] Fix | Delete
elem[2],
[493] Fix | Delete
elem[3],
[494] Fix | Delete
elem[4],
[495] Fix | Delete
elem[5].split(),
[496] Fix | Delete
elem[6],
[497] Fix | Delete
elem[7]))
[498] Fix | Delete
except IndexError:
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function