|
5 | 5 | # Example: |
6 | 6 | # |
7 | 7 | # >>> from nntplib import NNTP |
8 | | -# >>> s = NNTP('charon') |
9 | | -# >>> resp, count, first, last, name = s.group('nlnet.misc') |
| 8 | +# >>> s = NNTP('news') |
| 9 | +# >>> resp, count, first, last, name = s.group('comp.lang.python') |
10 | 10 | # >>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last |
11 | | -# Group nlnet.misc has 525 articles, range 6960 to 7485 |
| 11 | +# Group comp.lang.python has 51 articles, range 5770 to 5821 |
12 | 12 | # >>> resp, subs = s.xhdr('subject', first + '-' + last) |
13 | 13 | # >>> resp = s.quit() |
14 | 14 | # >>> |
|
25 | 25 | # Note that all arguments and return values representing article numbers |
26 | 26 | # are strings, not numbers, since they are rarely used for calculations. |
27 | 27 |
|
| 28 | +# (xover, xgtitle, xpath, date methods by Kevan Heydon) |
| 29 | + |
28 | 30 |
|
29 | 31 | # Imports |
30 | 32 | import regex |
|
38 | 40 | error_temp = 'nntplib.error_temp' # 4xx errors |
39 | 41 | error_perm = 'nntplib.error_perm' # 5xx errors |
40 | 42 | error_proto = 'nntplib.error_proto' # response does not begin with [1-5] |
| 43 | +error_data = 'nntplib.error_data' # error in response data |
41 | 44 |
|
42 | 45 |
|
43 | 46 | # Standard port used by NNTP servers |
44 | 47 | NNTP_PORT = 119 |
45 | 48 |
|
46 | 49 |
|
47 | 50 | # Response numbers that are followed by additional text (e.g. article) |
48 | | -LONGRESP = ['100', '215', '220', '221', '222', '230', '231'] |
| 51 | +LONGRESP = ['100', '215', '220', '221', '222', '224', '230', '231', '282'] |
49 | 52 |
|
50 | 53 |
|
51 | 54 | # Line terminators (we always output CRLF, but accept any of CRLF, CR, LF) |
@@ -308,6 +311,86 @@ def xhdr(self, hdr, str): |
308 | 311 | lines[i] = (nr, line[n:]) |
309 | 312 | return resp, lines |
310 | 313 |
|
| 314 | + # Process an XOVER command (optional server extension) Arguments: |
| 315 | + # - start: start of range |
| 316 | + # - end: end of range |
| 317 | + # Returns: |
| 318 | + # - resp: server response if succesful |
| 319 | + # - list: list of (art-nr, subject, poster, date, id, refrences, size, lines) |
| 320 | + |
| 321 | + def xover(self,start,end): |
| 322 | + resp, lines = self.longcmd('XOVER ' + start + '-' + end) |
| 323 | + xover_lines = [] |
| 324 | + for line in lines: |
| 325 | + elem = string.splitfields(line,"\t") |
| 326 | + try: |
| 327 | + xover_lines.append(elem[0], |
| 328 | + elem[1], |
| 329 | + elem[2], |
| 330 | + elem[3], |
| 331 | + elem[4], |
| 332 | + elem[5:-2], |
| 333 | + elem[-2], |
| 334 | + elem[-1]) |
| 335 | + except IndexError: |
| 336 | + raise error_data,line |
| 337 | + return resp,xover_lines |
| 338 | + |
| 339 | + # Process an XGTITLE command (optional server extension) Arguments: |
| 340 | + # - group: group name wildcard (i.e. news.*) |
| 341 | + # Returns: |
| 342 | + # - resp: server response if succesful |
| 343 | + # - list: list of (name,title) strings |
| 344 | + |
| 345 | + def xgtitle(self, group): |
| 346 | + line_pat = regex.compile("^\([^ \t]+\)[ \t]+\(.*\)$") |
| 347 | + resp, raw_lines = self.longcmd('XGTITLE ' + group) |
| 348 | + lines = [] |
| 349 | + for raw_line in raw_lines: |
| 350 | + if line_pat.search(string.strip(raw_line)) == 0: |
| 351 | + lines.append(line_pat.group(1), |
| 352 | + line_pat.group(2)) |
| 353 | + |
| 354 | + return resp, lines |
| 355 | + |
| 356 | + # Process an XPATH command (optional server extension) Arguments: |
| 357 | + # - id: Message id of article |
| 358 | + # Returns: |
| 359 | + # resp: server response if succesful |
| 360 | + # path: directory path to article |
| 361 | + |
| 362 | + def xpath(self,id): |
| 363 | + resp = self.shortcmd("XPATH " + id) |
| 364 | + if resp[:3] <> '223': |
| 365 | + raise error_reply, resp |
| 366 | + try: |
| 367 | + [resp_num, path] = string.split(resp) |
| 368 | + except ValueError: |
| 369 | + raise error_reply, resp |
| 370 | + else: |
| 371 | + return resp, path |
| 372 | + |
| 373 | + # Process the DATE command. Arguments: |
| 374 | + # None |
| 375 | + # Returns: |
| 376 | + # resp: server response if succesful |
| 377 | + # date: Date suitable for newnews/newgroups commands etc. |
| 378 | + # time: Time suitable for newnews/newgroups commands etc. |
| 379 | + |
| 380 | + def date (self): |
| 381 | + resp = self.shortcmd("DATE") |
| 382 | + if resp[:3] <> '111': |
| 383 | + raise error_reply, resp |
| 384 | + elem = string.split(resp) |
| 385 | + if len(elem) != 2: |
| 386 | + raise error_data, resp |
| 387 | + date = elem[1][2:8] |
| 388 | + time = elem[1][-6:] |
| 389 | + if len(date) != 6 or len(time) != 6: |
| 390 | + raise error_data, resp |
| 391 | + return resp, date, time |
| 392 | + |
| 393 | + |
311 | 394 | # Process a POST command. Arguments: |
312 | 395 | # - f: file containing the article |
313 | 396 | # Returns: |
|
0 commit comments