add MODE parsing

This commit is contained in:
jesopo 2020-03-12 18:17:10 +00:00
parent 8d7da30d8e
commit 15030a8306
4 changed files with 161 additions and 4 deletions

View File

@ -10,8 +10,31 @@ class Channel(Named):
self.topic_setter: Optional[str] = None
self.topic_time: Optional[datetime] = None
self.list_modes: Dict[str, List[str]] = {}
self.modes: Dict[str, str] = {}
self.list_modes: Dict[str, List[str]] = {}
self.modes: Dict[str, Optional[str]] = {}
def __repr__(self) -> str:
return f"Channel(name={self.name!r})"
def add_mode(self,
char: str,
param: Optional[str],
list_mode: bool):
if list_mode:
if not char in self.list_modes:
self.list_modes[char] = []
if not param in self.list_modes[char]:
self.list_modes[char].append(param or "")
else:
self.modes[char] = param
def remove_mode(self,
char: str,
param: Optional[str]):
if char in self.list_modes:
if param in self.list_modes[char]:
self.list_modes[char].remove(param)
if not self.list_modes[char]:
del self.list_modes[char]
elif char in self.modes:
del self.modes[char]

View File

@ -1,4 +1,4 @@
from typing import Callable, Dict, List, Optional, Set
from typing import Callable, Dict, List, Optional, Set, Tuple
from datetime import datetime
from irctokens import build, Line, StatefulDecoder, StatefulEncoder
@ -21,7 +21,8 @@ class Server(Named):
def __init__(self, name: str):
self.name = name
self.nickname = ""
self.nickname = ""
self.modes: List[str] = []
self._encoder = StatefulEncoder()
self._decoder = StatefulDecoder()
@ -206,3 +207,45 @@ class Server(Named):
channel = self.channels[channel_lower]
channel.topic_setter = line.params[2]
channel.topic_time = datetime.fromtimestamp(int(line.params[3]))
@line_handler("MODE")
def handle_MODE(self, line: Line):
target = line.params[0]
modes = line.params[1]
params = line.params[2:].copy()
modifier = True
parts: List[Tuple[bool, str]] = []
for c in list(modes):
if c == "+":
modifier = True
elif c == "-":
modifier = False
else:
parts.append((modifier, c))
if target == self.nickname:
for add, char in parts:
if add:
if not char in self.modes:
self.modes.append(char)
elif char in self.modes:
self.modes.remove(char)
elif self.has_channel(target):
channel = self.channels[self.casemap_lower(target)]
for add, char in parts:
list_mode = char in self.isupport.chanmodes.list_modes
if add and (
list_mode or
char in self.isupport.chanmodes.setting_b_modes or
char in self.isupport.chanmodes.setting_c_modes):
channel.add_mode(char, params.pop(0), list_mode)
elif not add and (
list_mode or
char in self.isupport.chanmodes.setting_b_modes):
channel.remove_mode(char, params.pop(0))
elif add:
channel.add_mode(char, None, False)
else:
channel.remove_mode(char, None)

View File

@ -1,2 +1,3 @@
from .channel import *
from .nickname import *
from .mode import *

90
test/mode.py Normal file
View File

@ -0,0 +1,90 @@
import unittest
import ircstates, irctokens
class ModeTestUMode(unittest.TestCase):
def test_add(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise("MODE nickname +i"))
self.assertEqual(server.modes, ["i"])
def test_remove(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise("MODE nickname +i"))
server.parse_tokens(irctokens.tokenise("MODE nickname -i"))
self.assertEqual(server.modes, [])
class ModeTestChannelList(unittest.TestCase):
def test_add(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +b asd!*@*"))
channel = server.channels["#chan"]
self.assertEqual(channel.list_modes, {"b": ["asd!*@*"]})
def test_remove(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +b asd!*@*"))
server.parse_tokens(irctokens.tokenise("MODE #chan -b asd!*@*"))
channel = server.channels["#chan"]
self.assertEqual(channel.list_modes, {})
class ModeTestChannelTypeB(unittest.TestCase):
def test_add(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +k password"))
channel = server.channels["#chan"]
self.assertEqual(channel.modes, {"k": "password"})
def test_remove(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +k password"))
server.parse_tokens(irctokens.tokenise("MODE #chan -k *"))
channel = server.channels["#chan"]
self.assertEqual(channel.list_modes, {})
class ModeTestChannelTypeC(unittest.TestCase):
def test_add(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +l 100"))
channel = server.channels["#chan"]
self.assertEqual(channel.modes, {"l": "100"})
def test_remove(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +l 100"))
server.parse_tokens(irctokens.tokenise("MODE #chan -l"))
channel = server.channels["#chan"]
self.assertEqual(channel.list_modes, {})
class ModeTestChannelTypeD(unittest.TestCase):
def test_add(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +i"))
channel = server.channels["#chan"]
self.assertEqual(channel.modes, {"i": None})
def test_remove(self):
server = ircstates.Server("test")
server.parse_tokens(irctokens.tokenise("001 nickname"))
server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan"))
server.parse_tokens(irctokens.tokenise("MODE #chan +i"))
server.parse_tokens(irctokens.tokenise("MODE #chan -i"))
channel = server.channels["#chan"]
self.assertEqual(channel.list_modes, {})