From 9a4febca5c01c4252ae72d2a9e32228c8a9eba05 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Fri, 22 Nov 2024 23:57:14 -0500 Subject: [PATCH] Gotta commit somethin' :X --- lib/nntp/tiny/server.py | 15 ++++- lib/nntp/tiny/session.py | 135 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/lib/nntp/tiny/server.py b/lib/nntp/tiny/server.py index 2089ca1..c70df45 100644 --- a/lib/nntp/tiny/server.py +++ b/lib/nntp/tiny/server.py @@ -1,10 +1,21 @@ import enum +from nntp.tiny.db import Database +from nntp.tiny.newsgroup import Newsgroup + class ServerCapability(enum.Flag): NONE = 0 AUTH = enum.auto() POST = enum.auto() class Server(): - def __init_(self): - self.capabilities = NNTPServerCapability.NONE + def __init_(self, db: Database): + self.db = db + self.capabilities = ServerCapability.NONE + self.newsgroups = dict() + + self._init_groups() + + def _init_newsgroups(self): + for newsgroup in self.db.query(Newsgroup).each(): + self.newsgroups[newsgroup.name.casefold()] = newsgroup diff --git a/lib/nntp/tiny/session.py b/lib/nntp/tiny/session.py index 98be025..2c08809 100644 --- a/lib/nntp/tiny/session.py +++ b/lib/nntp/tiny/session.py @@ -2,8 +2,12 @@ import enum import socket import re -from nntp.tiny.server import Server, ServerCapability -from nntp.tiny.response import Response +from typing import Optional + +from nntp.tiny.server import Server, ServerCapability +from nntp.tiny.response import Response, ResponseCode +from nntp.tiny.newsgroup import Newsgroup +from nntp.tiny.message import Message class SessionState(enum.Flag): NONE = 0 @@ -12,6 +16,70 @@ class SessionState(enum.Flag): from nntp.tiny.buffer import LineBuffer, BufferOverflow +class MessageRange(): + __slots__ = 'id', 'min', 'max', + + RE_NUM = re.compile('^(\d+)$') + RE_RANGE = re.compile('^(\d+)-(\d+)$') + RE_RANGE_LOWER = re.compile('^(\d+$)-$') + RE_RANGE_UPPER = re.compile('^-(\d+$)$') + + def __init__(self): + self.id: int = None + self.min: int = None + self.max: int = None + + def __str__(self): + if self.id is not None: + return str(self.id) + + if self.min is not None and self.max is None: + return "%d-" % (self.min) + elif self.min is not None and self.max is not None: + return "%d-%d" % (self.min, self.max) + elif self.min is None and self.max is not None: + return "-%d" % (self.max) + + return "?" + + def __dict__(self): + if self.id is not None: + return {'id': self.id} + + if self.min is not None and self.max is None: + return { 'min(id)': self.min } + elif self.min is not None and self.max is not None: + return { 'min(id)': self.min, 'max(id)': self.max } + elif self.min is None and self.max is not None: + return { 'max(id)': self.max } + + @staticmethod + def parse(r: str): + match = __class__.RE_NUM.match(r) + if match: + obj = __class__() + obj.id = match[1] + return obj + + match = __class__.RE_RANGE.match(r) + if match: + obj = __class__() + obj.min = match[1] + obj.max = match[2] + return obj + + match = __class__.RE_RANGE_LOWER.match(r) + if match: + obj = __class__() + obj.min = match[1] + return obj + + match = __class__.RE_RANGE_UPPER.match(r) + if match: + obj = __class__() + obj.max = match[1] + return obj + class Session(): RE_SPLIT = re.compile(r'\s+') @@ -36,6 +104,8 @@ class Session(): self.sock: socket.socket = sock self.buf: LineBuffer = LineBuffer() + self.newsgroup: Optional[Newsgroup] = None + def readline(self): return self.buf.readline(self.sock) @@ -64,6 +134,67 @@ class Session(): self.end() + def _cmd_group(self, name: str): + if name not in self.server.newsgroups: + return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_FOUND) + + newsgroup = self.server.newsgroups[name] + + sql = """ + select + count(id), + min(id), + max(id) + from + newsgroup_message + where + newsgroup_id = ? + """ + + cr = self.server.db.execute(sql, (newsgroup.id)) + row = cr.fetchone() + + text = "%d %d %d %s" % ( + row[0], + row[1], + row[2], + newsgroup.name + ) + + self.respond(ResponseCode.NNTP_GROUP_LISTING, text) + + self.newsgroup = newsgroup + + return + + + def _cmd_listgroup(self, *args): + newsgroup = self.newsgroup + + if len(args) == 0 and newsgroup is None: + return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_SELECTED) + elif len(args) > 0: + newsgroup = self.server.newsgroups.get(args[0]) + + if newsgroup is None: + return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_FOUND) + + values = { + 'newsgroup_id': newsgroup.id + } + + if len(args) > 1: + msgrange = MessageRange.parse(args[1])z + + values.update(dict(msgrange)) + + cr = self.server.db.query(Message, values) + + for message in cr.each(): + self.print(str(message.id)) + + return self.end() + def handle(self): line = self.readline()