3 Commits

6 changed files with 62 additions and 16 deletions
Unified View
  1. +7
    -3
      paircd/client.py
  2. +18
    -0
      paircd/handler/away.py
  3. +9
    -7
      paircd/handler/join.py
  4. +16
    -5
      paircd/handler/privmsg.py
  5. +2
    -0
      paircd/handlers.py
  6. +10
    -1
      paircd/reply.py

+ 7
- 3
paircd/client.py View File

@ -2,7 +2,7 @@ from asyncio import StreamReader, StreamWriter, Queue
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from logging import log, INFO from logging import log, INFO
from paircd.reply import RPL_CREATED, RPL_WELCOME, RPL_YOURHOST
from paircd.reply import RPL_CREATED, RPL_MYINFO, RPL_WELCOME, RPL_YOURHOST
from paircd.message import Message from paircd.message import Message
from typing import Set from typing import Set
@ -18,6 +18,7 @@ class Client:
username: str = "" username: str = ""
realname: str = "" realname: str = ""
registered: bool = False registered: bool = False
away: str = ""
channels: Set[str] = field(default_factory=set) channels: Set[str] = field(default_factory=set)
@ -50,6 +51,9 @@ class Client:
self.write_message(RPL_WELCOME(self.nickname, self.id())) self.write_message(RPL_WELCOME(self.nickname, self.id()))
self.write_message(RPL_YOURHOST(self.nickname, "localhost", "paircd-0.0.1")) self.write_message(RPL_YOURHOST(self.nickname, "localhost", "paircd-0.0.1"))
# TODO: Pull timestamp from Server instance
# TODO: Pull timestamp from server instance
self.write_message(RPL_CREATED(self.nickname, datetime.utcnow())) self.write_message(RPL_CREATED(self.nickname, datetime.utcnow()))
# TODO: Display list of supported user & channel modes
self.write_message(
RPL_MYINFO(self.nickname, "localhost", "paircd-0.0.1", "", "")
)

+ 18
- 0
paircd/handler/away.py View File

@ -0,0 +1,18 @@
from paircd.client import Client
from paircd.command_handler import CommandHandler
from paircd.message import Message
from paircd.reply import RPL_NOWAWAY, RPL_UNAWAY
from paircd.server import Server
class AwayHandler(CommandHandler):
def __init__(self) -> None:
super().__init__("AWAY")
async def handle(self, server: Server, client: Client, msg: Message) -> None:
if len(msg.args) == 0 or len(msg.args[0]) == 0:
client.away = ""
client.write_message(RPL_UNAWAY(client.nickname))
else:
client.away = msg.args[0]
client.write_message(RPL_NOWAWAY(client.nickname))

+ 9
- 7
paircd/handler/join.py View File

@ -1,5 +1,11 @@
import logging
from paircd.reply import JOIN, RPL_ENDOFNAMES, RPL_NAMREPLY, RPL_TOPIC
from paircd.reply import (
ERR_NOSUCHCHANNEL,
ERR_NOTREGISTERED,
JOIN,
RPL_ENDOFNAMES,
RPL_NAMREPLY,
RPL_TOPIC,
)
from paircd.client import Client from paircd.client import Client
from paircd.command_handler import CommandHandler from paircd.command_handler import CommandHandler
@ -12,13 +18,9 @@ class JoinHandler(CommandHandler):
super().__init__("JOIN", 1) super().__init__("JOIN", 1)
async def handle(self, server: Server, client: Client, msg: Message) -> None: async def handle(self, server: Server, client: Client, msg: Message) -> None:
if not client.registered:
client.log("join: not registered", level=logging.WARN)
return
channel_name = msg.args[0] channel_name = msg.args[0]
if not channel_name.startswith("#"): if not channel_name.startswith("#"):
client.log("tried to join invalid channel", level=logging.WARN)
client.write_message(ERR_NOSUCHCHANNEL(client.nickname, channel_name))
return return
channel = server.get_channel_by_name(channel_name) channel = server.get_channel_by_name(channel_name)

+ 16
- 5
paircd/handler/privmsg.py View File

@ -1,9 +1,13 @@
import logging
from paircd.client import Client from paircd.client import Client
from paircd.command_handler import CommandHandler from paircd.command_handler import CommandHandler
from paircd.message import Message from paircd.message import Message
from paircd.reply import PRIVMSG
from paircd.reply import (
ERR_NOSUCHNICK,
ERR_NOTEXTTOSEND,
ERR_NOTREGISTERED,
PRIVMSG,
RPL_AWAY,
)
from paircd.server import Server from paircd.server import Server
@ -13,10 +17,17 @@ class PrivmsgHandler(CommandHandler):
async def handle(self, server: Server, client: Client, msg: Message) -> None: async def handle(self, server: Server, client: Client, msg: Message) -> None:
recipient, raw_msg = msg.args recipient, raw_msg = msg.args
out = PRIVMSG(recipient, raw_msg, prefix=client.id())
if len(raw_msg) == 0:
client.write_message(ERR_NOTEXTTOSEND(client.nickname))
return
out = PRIVMSG(recipient, raw_msg, prefix=client.id())
for name, other_client in server.clients_by_nick.items(): for name, other_client in server.clients_by_nick.items():
if name == recipient: if name == recipient:
if other_client.away:
client.write_message(
RPL_AWAY(client.nickname, name, other_client.away)
)
other_client.write_message(out) other_client.write_message(out)
return return
@ -25,4 +36,4 @@ class PrivmsgHandler(CommandHandler):
channel.write_message(out) channel.write_message(out)
return return
client.log("unknown recipient", level=logging.WARN)
client.write_message(ERR_NOSUCHNICK(client.nickname, recipient))

+ 2
- 0
paircd/handlers.py View File

@ -1,4 +1,5 @@
from logging import WARN from logging import WARN
from paircd.handler.away import AwayHandler
from typing import Dict from typing import Dict
from paircd.client import Client from paircd.client import Client
@ -15,6 +16,7 @@ from paircd.handler.user import UserHandler
from paircd.handler.who import WhoHandler from paircd.handler.who import WhoHandler
HANDLER_CLASSES = [ HANDLER_CLASSES = [
AwayHandler,
JoinHandler, JoinHandler,
ModeHandler, ModeHandler,
NickHandler, NickHandler,

+ 10
- 1
paircd/reply.py View File

@ -31,12 +31,21 @@ PRIVMSG = cmd_fn("PRIVMSG", "{0} :{1}")
# Error replies # Error replies
ERR_NOSUCHNICK = reply_fn(401, "{0} :No such nick/channel") ERR_NOSUCHNICK = reply_fn(401, "{0} :No such nick/channel")
ERR_NOSUCHSERVER = reply_fn(402, "{0}: No such server")
ERR_NOSUCHSERVER = reply_fn(402, "{0} :No such server")
ERR_NOSUCHCHANNEL = reply_fn(403, "{0} :No such channel")
ERR_CANNOTSENDTOCHAN = reply_fn(404, "{0} :Cannot send to channel")
ERR_TOOMANYCHANNELS = reply_fn(405, "{0} :You have joined too many channels")
ERR_NOTEXTTOSEND = reply_fn(412, ":No text to send")
ERR_NOTREGISTERED = reply_fn(451, ":You have not registered")
# Command responses # Command responses
RPL_WELCOME = reply_fn("001", "Welcome to the Internet Relay Network {0}") RPL_WELCOME = reply_fn("001", "Welcome to the Internet Relay Network {0}")
RPL_YOURHOST = reply_fn("002", "Your host is {0}, running version {1}") RPL_YOURHOST = reply_fn("002", "Your host is {0}, running version {1}")
RPL_CREATED = reply_fn("003", "This server was created {0}") RPL_CREATED = reply_fn("003", "This server was created {0}")
RPL_MYINFO = reply_fn("004", "{0} {1} {2} {3}")
RPL_AWAY = reply_fn(301, "{0} :{1}")
RPL_UNAWAY = reply_fn(305, ":You are no longer marked as being away")
RPL_NOWAWAY = reply_fn(306, ":You have been marked as being away")
RPL_WHOISUSER = reply_fn(311, "{0} {1} {2} * :{3}") RPL_WHOISUSER = reply_fn(311, "{0} {1} {2} * :{3}")
RPL_ENDOFWHO = reply_fn(315, "{0} :End of /WHO list") RPL_ENDOFWHO = reply_fn(315, "{0} :End of /WHO list")
RPL_ENDOFWHOIS = reply_fn(318, "{0} :End of /WHOIS list") RPL_ENDOFWHOIS = reply_fn(318, "{0} :End of /WHOIS list")

Loading…
Cancel
Save