96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
import enum
|
|
import socket
|
|
|
|
from typing import Optional
|
|
|
|
class ResponseCode(enum.Enum):
|
|
NNTP_HELP_FOLLOWS = 100
|
|
NNTP_CAPABILITIES_FOLLOW = 101
|
|
NNTP_DATE = 111
|
|
NNTP_SERVICE_READY_POST_ALLOWED = 200
|
|
NNTP_SERVICE_READY_POST_PROHIBITED = 201
|
|
NNTP_CONNECTION_CLOSING = 205
|
|
NNTP_GROUP_LISTING = 211
|
|
NNTP_INFORMATION_FOLLOWS = 215
|
|
NNTP_ARTICLE_BODY = 220
|
|
NNTP_ARTICLE_LISTING = 221
|
|
NNTP_BODY_LISTING = 222
|
|
NNTP_ARTICLE_STAT_RESPONSE = 223
|
|
NNTP_OVERVIEW_FOLLOWS = 224
|
|
NNTP_HEADERS_FOLLOW = 225
|
|
NNTP_ARTICLE_LISTING_ID_FOLLOWS = 230
|
|
NNTP_GROUPS_NEW_FOLLOW = 231
|
|
NNTP_ARTICLE_RECEIVED_ID = 235
|
|
NNTP_ARTICLE_RECEIVED = 240
|
|
NNTP_AUTH_ACCEPTED = 281
|
|
NNTP_INQUIRY_ARTICLE_ID = 335
|
|
NNTP_INQUIRY_ARTICLE = 340
|
|
NNTP_INQUIRY_PASSPHRASE = 381
|
|
NNTP_NEWSGROUP_NOT_FOUND = 411
|
|
NNTP_NEWSGROUP_NOT_SELECTED = 412
|
|
NNTP_ARTICLE_INVALID_NUMBER = 420
|
|
NNTP_ARTICLE_NO_NEXT = 421
|
|
NNTP_ARTICLE_NO_PREVIOUS = 422
|
|
NNTP_ARTICLE_NOT_FOUND_NUM = 423
|
|
NNTP_ARTICLE_NOT_FOUND_ID = 430
|
|
NNTP_ARTICLE_NOT_WANTED_ID = 435
|
|
NNTP_POST_PROHIBITED = 440
|
|
NNTP_POST_FAILED = 441
|
|
NNTP_AUTH_FAILED = 481
|
|
NNTP_AUTH_BAD_SEQUENCE = 482
|
|
NNTP_COMMAND_UNKNOWN = 500
|
|
NNTP_SYNTAX_ERROR = 501
|
|
NNTP_COMMAND_UNAVAILABLE = 502
|
|
NNTP_GROUPS_UNAVAILABLE = 503
|
|
|
|
def message(self):
|
|
return {
|
|
100: "Help text follows",
|
|
101: "Capabilities follow",
|
|
200: "NNTP Service Ready, posting allowed",
|
|
201: "NNTP Service Ready, posting prohibited",
|
|
205: "Connection closing",
|
|
215: "Information follows",
|
|
223: "Article exists",
|
|
224: "Overview information follows (multi-line)",
|
|
225: "Headers follow (multi-line)",
|
|
231: "List of new newsgroups follows",
|
|
235: "Article received OK",
|
|
240: "Article received OK",
|
|
281: "Authentication accepted",
|
|
335: "Input article; end with <CR><LF>.<CR><LF>",
|
|
340: "Input article; end with <CR><LF>.<CR><LF>",
|
|
381: "Enter passphrase",
|
|
411: "No such newsgroup",
|
|
412: "No newsgroup selected",
|
|
420: "Current article number is invalid",
|
|
421: "No next article in this group",
|
|
422: "No previous article in this group",
|
|
423: "No article found by that message number",
|
|
430: "No article found by that message ID",
|
|
435: "Article not wanted",
|
|
440: "Posting prohibited",
|
|
441: "Posting failed",
|
|
481: "Authentication failed",
|
|
482: "Authentication commands issued out of sequence",
|
|
500: "Unknown command",
|
|
501: "Syntax error",
|
|
502: "Command unavailable",
|
|
503: "No list of recommended newsgroups available"
|
|
}.get(self.value)
|
|
|
|
class Response():
|
|
__slots__ = 'code', 'message', 'body',
|
|
|
|
def __init__(self, code: ResponseCode, message: Optional[str]=None, body: Optional[str]=None):
|
|
self.code = code
|
|
self.message = message or code.message() or "Unknown response"
|
|
self.body = body
|
|
|
|
def __str__(self):
|
|
ret = "%d %s" % (self.code.value, self.message)
|
|
|
|
if self.body:
|
|
ret += "\r\n" + self.body
|
|
|
|
return ret
|