'Structured expectations and processing hints for server messages.'
from enum import Enum, auto
from typing import Any, Callable, NamedTuple, Optional, Self
-from ircplom.irc_conn import IrcMessage
+from ircplom.irc_conn import IrcMessage, NickUserHost
-class _MsgTok(Enum):
+_TOK_SKIPNUH = 'SKIPNUH'
+
+
+class _MsgToken(Enum):
'Server message token classifications.'
ANY = auto()
CHANNEL = auto()
NICK_USER_HOST = auto()
-_MsgTokGuide = str | _MsgTok | tuple[str | _MsgTok, str]
+_MsgTokenWithStr = _MsgToken | str
+_MsgTokenGuide = _MsgTokenWithStr | tuple[_MsgTokenWithStr, str]
+_MsgTokenValidatorDict = dict[_MsgTokenWithStr, Callable[[Any], bool]]
class _Command(NamedTuple):
if path_str))
-class _MsgParseExpectation:
+class _Code(NamedTuple):
+ tok_name: str = ''
+ commands: tuple[_Command, ...] = tuple()
+ skip_nuh: bool = False
- def __init__(self,
- verb: str,
- source: _MsgTokGuide,
- params: tuple[_MsgTokGuide, ...] = tuple(),
- bonus_tasks: tuple[str, ...] = tuple()
- ) -> None:
+ def __bool__(self) -> bool:
+ return bool(self.tok_name) or bool(self.commands)
- class _Code(NamedTuple):
- title: str
- commands: tuple[_Command, ...]
+ @classmethod
+ def from_(cls, input_: str) -> Self:
+ 'Split by ":" into commands (further split by ","), tok_name.'
+ commands_str, tok_name = input_.split(':', maxsplit=1)
+ skip_nuh = False
+ commands: list[_Command] = []
+ for command_str in commands_str.split(','):
+ if command_str == _TOK_SKIPNUH:
+ skip_nuh = True
+ elif command_str:
+ commands += [_Command.from_(command_str)]
+ return cls(tok_name, tuple(commands), skip_nuh)
+
+
+class _TokenExpectation(NamedTuple):
+ type_: _MsgTokenWithStr
+ code: _Code
- @classmethod
- def from_(cls, input_: str) -> Self:
- 'Split by ":" into commands (further split by ","), title.'
- cmdsstr, title = input_.split(':', maxsplit=1)
- return cls(title, tuple(_Command.from_(t)
- for t in cmdsstr.split(',') if t))
+ @classmethod
+ def from_(cls, val: _MsgTokenGuide) -> Self:
+ 'Standardize value into .type_, (potentially empty) .code.'
+ t = ((val[0], _Code.from_(val[1])) if isinstance(val, tuple)
+ else (val, _Code()))
+ return cls(*t)
- class _TokExpectation(NamedTuple):
- type_: _MsgTok | str
- code: Optional[_Code]
- @classmethod
- def from_(cls, val: _MsgTokGuide) -> Self:
- 'Standardize value into .type_, (potentially empty) .code.'
- t = ((val[0], _Code.from_(val[1])) if isinstance(val, tuple)
- else (val, None))
- return cls(*t)
+class _MsgParseExpectation:
+ VALIDATORS: _MsgTokenValidatorDict = {
+ _MsgToken.NONE: lambda tok: tok == '',
+ _MsgToken.NICK_USER_HOST: NickUserHost.possible_from,
+ _MsgToken.SERVER: lambda tok: ('.' in tok
+ and not set('@!') & set(tok))}
+ PARSERS: dict[_MsgTokenWithStr, Callable] = {
+ _MsgToken.LIST: lambda tok: tuple(tok.split()),
+ _MsgToken.NICK_USER_HOST: NickUserHost.from_str}
+ def __init__(self,
+ verb: str,
+ source: _MsgTokenGuide,
+ params: tuple[_MsgTokenGuide, ...] = tuple(),
+ bonus_tasks: tuple[str, ...] = tuple()
+ ) -> None:
self.verb = verb
- self.source = _TokExpectation.from_(source)
- self.params = tuple(_TokExpectation.from_(param) for param in params)
+ self.source = _TokenExpectation.from_(source)
+ self.params = tuple(_TokenExpectation.from_(param) for param in params)
self.bonus_tasks = tuple(_Code.from_(item) for item in bonus_tasks)
def parse_msg(self,
msg: IrcMessage,
is_chan_name: Callable,
is_nick: Callable,
- possible_nickuserhost: Callable,
- into_nickuserhost: Callable
) -> Optional[dict[str, Any]]:
'Try parsing msg into informative result dictionary, or None on fail.'
- cmp_params: list[str | tuple[str, ...]] = []
- idx_after = 0
- for idx, param in enumerate(self.params):
- if param == _MsgTok.LIST or (isinstance(param, tuple)
- and param[0] == _MsgTok.LIST):
- idx_after = len(msg.params) + 1 - (len(self.params) - idx)
- cmp_params += [' '.join(msg.params[idx:idx_after])]
- cmp_params += list(msg.params[idx_after:])
- break
- cmp_params += msg.params[idx:idx + 1]
- if (not idx_after) and len(cmp_params) != len(msg.params):
- return None
- cmp_fields = tuple([msg.source] + cmp_params)
- ex_fields = tuple([self.source] + list(self.params))
- if len(ex_fields) != len(cmp_fields):
- return None
- validators: dict[_MsgTok, Callable[[Any], bool]] = {
- _MsgTok.NONE: lambda tok: tok == '',
- _MsgTok.CHANNEL: is_chan_name,
- _MsgTok.NICKNAME: is_nick,
- _MsgTok.NICK_USER_HOST: possible_nickuserhost,
- _MsgTok.SERVER: lambda tok: '.' in tok and not set('@!') & set(tok)
- }
- parsers: dict[_MsgTok, Callable[[Any], Any]] = {
- _MsgTok.LIST: lambda tok: tuple(tok.split()),
- _MsgTok.NICK_USER_HOST: into_nickuserhost
- }
- parsed: dict[str, str | tuple[str, ...]] = {}
- singled_tasks: list[tuple[_Command, str]] = []
- nickuserhosts = []
- for ex_tok, cmp_tok in [(ex_tok, cmp_fields[idx])
- for idx, ex_tok in enumerate(ex_fields)]:
- if isinstance(ex_tok.type_, str) and ex_tok.type_ != cmp_tok:
- return None
- if (not isinstance(ex_tok.type_, str))\
- and ex_tok.type_ in validators\
- and not validators[ex_tok.type_](cmp_tok):
- return None
- if ex_tok.code or ex_tok.type_ is _MsgTok.NICK_USER_HOST:
- value = (cmp_tok if (isinstance(ex_tok.type_, str)
- or ex_tok.type_ not in parsers)
- else parsers[ex_tok.type_](cmp_tok))
- if ex_tok.type_ is _MsgTok.NICK_USER_HOST:
- if not (ex_tok.code and
- 'skipnuh' in [cmd.verb
- for cmd in ex_tok.code.commands]):
- nickuserhosts += [value]
- if ex_tok.code:
- parsed[ex_tok.code.title] = value
- singled_tasks += [(cmd, ex_tok.code.title)
- for cmd in ex_tok.code.commands
- if cmd.verb != 'skipnuh']
- for code in self.bonus_tasks:
- singled_tasks += [(cmd, code.title) for cmd in code.commands]
- tasks: dict[_Command, list[str]] = {}
- for cmd, title in singled_tasks:
- if cmd not in tasks:
- tasks[cmd] = []
- tasks[cmd] += [title]
- return parsed | {'_verb': self.verb,
- '_tasks': tasks,
- '_nickuserhosts': nickuserhosts}
+ StrTuplable = str | tuple[str, ...]
+ RetDict = dict[str, StrTuplable | tuple[NickUserHost, ...]]
+ validators = self.VALIDATORS | {_MsgToken.CHANNEL: is_chan_name,
+ _MsgToken.NICKNAME: is_nick}
+
+ def divide_msg(msg: IrcMessage) -> Optional[tuple[StrTuplable, ...]]:
+ from_msg: list[StrTuplable] = []
+ idx_after_list = 0
+ for idx, param in enumerate(self.params):
+ if param.type_ == _MsgToken.LIST:
+ remaining_exp_params = len(self.params) - idx
+ idx_after_list = len(msg.params) - remaining_exp_params + 1
+ from_msg += [' '.join(msg.params[idx:idx_after_list])]
+ from_msg += list(msg.params[idx_after_list:])
+ break
+ from_msg += msg.params[idx:idx + 1] # collect [] if none there
+ if len(from_msg) < len(msg.params) and not idx_after_list:
+ return None # not all msg.params collected
+ if len(self.params) != len(from_msg):
+ return None # msg.params are too few or too many
+ return tuple([msg.source] + from_msg)
+
+ def harvest_msg(exp_fields: tuple[_TokenExpectation, ...],
+ msg_fields: tuple[StrTuplable, ...],
+ validators: _MsgTokenValidatorDict
+ ) -> Optional[RetDict]:
+ def parsed(type_: _MsgToken | str, to_parse: StrTuplable):
+ return self.PARSERS.get(type_, lambda keep: keep)(to_parse)
+
+ d: RetDict = {}
+ nickuserhosts: list[NickUserHost] = []
+ for exp_tok, msg_tok in [(exp_tok, msg_fields[idx])
+ for idx, exp_tok
+ in enumerate(exp_fields)]:
+ if not validators.get(exp_tok.type_, lambda _: True)(msg_tok):
+ return None # validator found for this type, failed it
+ if isinstance(exp_tok.type_, str) and exp_tok.type_ != msg_tok:
+ return None # validator for "specific string"
+ if exp_tok.type_ is _MsgToken.NICK_USER_HOST\
+ and not exp_tok.code.skip_nuh:
+ nickuserhosts += [parsed(exp_tok.type_, msg_tok)]
+ if exp_tok.code.tok_name:
+ d[exp_tok.code.tok_name] = parsed(exp_tok.type_, msg_tok)
+ return d | {'_nickuserhosts': tuple(nickuserhosts)}
+
+ if (msg_fields := divide_msg(msg)):
+ exp_fields = tuple([self.source] + list(self.params))
+ if (to_ret := harvest_msg(exp_fields, msg_fields, validators)):
+ tasks: dict[_Command, list[str]] = {}
+ for code in (tuple(exp_field.code for exp_field in exp_fields)
+ + self.bonus_tasks):
+ for cmd in code.commands:
+ tasks[cmd] = tasks.get(cmd, []) + [code.tok_name]
+ return to_ret | {'_verb': self.verb, '_tasks': tasks}
+ return None
MSG_EXPECTATIONS: list[_MsgParseExpectation] = [
_MsgParseExpectation(
'001', # RPL_WELCOME
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY),
bonus_tasks=('do_autojoin:',)),
_MsgParseExpectation(
'002', # RPL_YOURHOST
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'003', # RPL_CREATED
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'004', # RPL_MYINFO
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY,
+ _MsgToken.ANY,
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'250', # RPL_STATSDLINE / RPL_STATSCONN
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'251', # RPL_LUSERCLIENT
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'252', # RPL_LUSEROP
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'253', # RPL_LUSERUNKNOWN
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'254', # RPL_LUSERCHANNELS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'255', # RPL_LUSERME
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'265', # RPL_LOCALUSERS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'265', # RPL_LOCALUSERS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'266', # RPL_GLOBALUSERS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
_MsgParseExpectation(
'266', # RPL_GLOBALUSERS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY,
+ _MsgToken.ANY,
+ _MsgToken.ANY)),
_MsgParseExpectation(
'375', # RPL_MOTDSTART already implied by 1st 372
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY)),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY)),
# various login stuff
_MsgParseExpectation(
'005', # RPL_ISUPPORT
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.LIST, 'do_db.set_isupport_from_rpl:isupport'),
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.LIST, 'do_db.set_isupport_from_rpl:isupport'),
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'372', # RPL_MOTD
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'do_db.motd.append:line'))),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'do_db.motd.append:line'))),
_MsgParseExpectation(
'376', # RPL_ENDOFMOTD
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY), # comment
bonus_tasks=('do_db.motd.complete:',)),
_MsgParseExpectation(
'396', # RPL_VISIBLEHOST
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.SERVER, 'setattr_db.users.me:host'),
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.SERVER, 'setattr_db.users.me:host'),
+ _MsgToken.ANY)), # comment
# SASL
_MsgParseExpectation(
'900', # RPL_LOGGEDIN
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.NICK_USER_HOST, 'setattr_db.users.me:nickuserhost'),
- (_MsgTok.ANY, 'setattr_db:sasl_account'),
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.NICK_USER_HOST, 'setattr_db.users.me:nickuserhost'),
+ (_MsgToken.ANY, 'setattr_db:sasl_account'),
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'903', # RPL_SASLSUCCESS
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db:sasl_auth_state')),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db:sasl_auth_state')),
bonus_tasks=('do_caps.end_negotiation:',)),
_MsgParseExpectation(
'904', # ERR_SASLFAIL
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db:sasl_auth_state')),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db:sasl_auth_state')),
bonus_tasks=('do_caps.end_negotiation:',)),
_MsgParseExpectation(
'AUTHENTICATE',
- _MsgTok.NONE,
+ _MsgToken.NONE,
('+',),
bonus_tasks=('do_send_authentication:',)),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('NEW', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('DEL', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('ACK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('ACK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('NAK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('NAK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('LS', ':subverb'),
('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('LS', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('LS', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('LS', ':subverb'),
('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('LIST', ':subverb'),
('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
('LIST', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('LIST', ':subverb'),
('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
_MsgParseExpectation(
'CAP',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
('LIST', ':subverb'),
- (_MsgTok.LIST, ':items'))),
+ (_MsgToken.LIST, ':items'))),
# nickname management
_MsgParseExpectation(
'432', # ERR_ERRONEOUSNICKNAME
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
- _MsgTok.ANY, # bad one probably fails our NICKNAME tests
- _MsgTok.ANY), # comment
+ _MsgToken.ANY, # bad one probably fails our NICKNAME tests
+ _MsgToken.ANY), # comment
bonus_tasks=('do_close:',)),
_MsgParseExpectation(
'432', # ERR_ERRONEOUSNICKNAME
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- _MsgTok.ANY, # bad one probably fails our NICKNAME tests
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.ANY, # bad one probably fails our NICKNAME tests
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'433', # ERR_NICKNAMEINUSE
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
- (_MsgTok.NICKNAME, 'do_increment_for_nicknameinuse:rejected'),
- _MsgTok.ANY)), # comment
+ (_MsgToken.NICKNAME, 'do_increment_for_nicknameinuse:rejected'),
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'433', # ERR_NICKNAMEINUSE
- _MsgTok.SERVER,
- (_MsgTok.NICKNAME, # we rather go for incrementation
- (_MsgTok.NICKNAME, 'do_increment_for_nicknameinuse:rejected'),
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ (_MsgToken.NICKNAME, # we rather go for incrementation
+ (_MsgToken.NICKNAME, 'do_increment_for_nicknameinuse:rejected'),
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'NICK',
- (_MsgTok.NICK_USER_HOST, ':named'),
- ((_MsgTok.NICKNAME, ':nick'),)),
+ (_MsgToken.NICK_USER_HOST, ':named'),
+ ((_MsgToken.NICKNAME, ':nick'),)),
# joining/leaving
_MsgParseExpectation(
'332', # RPL_TOPIC
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.CHANNEL, ':CHAN'),
- (_MsgTok.ANY, 'setattr_db.channels.CHAN.topic:what'))),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.CHANNEL, ':CHAN'),
+ (_MsgToken.ANY, 'setattr_db.channels.CHAN.topic:what'))),
_MsgParseExpectation(
'333', # RPL_TOPICWHOTIME
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.CHANNEL, ':CHAN'),
- (_MsgTok.NICK_USER_HOST,
- 'skipnuh_,setattr_db.channels.CHAN.topic:who'),
- (_MsgTok.ANY, ':timestamp')),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.CHANNEL, ':CHAN'),
+ (_MsgToken.NICK_USER_HOST,
+ f'{_TOK_SKIPNUH},setattr_db.channels.CHAN.topic:who'),
+ (_MsgToken.ANY, ':timestamp')),
bonus_tasks=('doafter_db.channels.CHAN.topic.complete:',)),
_MsgParseExpectation(
'353', # RPL_NAMREPLY
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
'@',
- (_MsgTok.CHANNEL, ':CHANNEL'),
- (_MsgTok.LIST, 'do_db.channels.CHANNEL.add_from_namreply:names'))),
+ (_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.LIST, 'do_db.channels.CHANNEL.add_from_namreply:names'))),
_MsgParseExpectation(
'353', # RPL_NAMREPLY
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
'=',
- (_MsgTok.CHANNEL, ':CHANNEL'),
- (_MsgTok.LIST, 'do_db.channels.CHANNEL.add_from_namreply:names'))),
+ (_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.LIST, 'do_db.channels.CHANNEL.add_from_namreply:names'))),
_MsgParseExpectation(
'366', # RPL_ENDOFNAMES
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.CHANNEL, ':CHAN'),
- _MsgTok.ANY), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.CHANNEL, ':CHAN'),
+ _MsgToken.ANY), # comment
bonus_tasks=('doafter_db.channels.CHAN.user_ids.complete:',)),
_MsgParseExpectation(
'JOIN',
- (_MsgTok.NICK_USER_HOST, 'do_db.channels.CHANNEL.join_user:user'),
- ((_MsgTok.CHANNEL, ':CHANNEL'),)),
+ (_MsgToken.NICK_USER_HOST, 'do_db.channels.CHANNEL.join_user:user'),
+ ((_MsgToken.CHANNEL, ':CHANNEL'),)),
_MsgParseExpectation(
'PART',
- (_MsgTok.NICK_USER_HOST, ':parter'),
- ((_MsgTok.CHANNEL, ':channel'),)),
+ (_MsgToken.NICK_USER_HOST, ':parter'),
+ ((_MsgToken.CHANNEL, ':channel'),)),
_MsgParseExpectation(
'PART',
- (_MsgTok.NICK_USER_HOST, ':parter'),
- ((_MsgTok.CHANNEL, ':channel'),
- (_MsgTok.ANY, ':message'))),
+ (_MsgToken.NICK_USER_HOST, ':parter'),
+ ((_MsgToken.CHANNEL, ':channel'),
+ (_MsgToken.ANY, ':message'))),
# messaging
_MsgParseExpectation(
'401', # ERR_NOSUCKNICK
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.NICKNAME, ':missing'),
- _MsgTok.ANY)), # comment
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.NICKNAME, ':missing'),
+ _MsgToken.ANY)), # comment
_MsgParseExpectation(
'NOTICE',
- _MsgTok.SERVER,
+ _MsgToken.SERVER,
('*',
- (_MsgTok.ANY, 'setattr_db.messaging..to.:notice'))),
+ (_MsgToken.ANY, 'setattr_db.messaging..to.:notice'))),
_MsgParseExpectation(
'NOTICE',
- _MsgTok.SERVER,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db.messaging..to.:notice'))),
+ _MsgToken.SERVER,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db.messaging..to.:notice'))),
_MsgParseExpectation(
'NOTICE',
- (_MsgTok.SERVER, ':SERVER'),
- ((_MsgTok.CHANNEL, ':CHANNEL'),
- (_MsgTok.ANY, 'setattr_db.messaging.SERVER.to.CHANNEL:notice'))),
+ (_MsgToken.SERVER, ':SERVER'),
+ ((_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.ANY, 'setattr_db.messaging.SERVER.to.CHANNEL:notice'))),
_MsgParseExpectation(
'NOTICE',
- (_MsgTok.NICK_USER_HOST, ':USER'),
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db.messaging.USER.to.:notice'))),
+ (_MsgToken.NICK_USER_HOST, ':USER'),
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db.messaging.USER.to.:notice'))),
_MsgParseExpectation(
'NOTICE',
- (_MsgTok.NICK_USER_HOST, ':USER'),
- ((_MsgTok.CHANNEL, ':CHANNEL'),
- (_MsgTok.ANY, 'setattr_db.messaging.USER.to.CHANNEL:notice'))),
+ (_MsgToken.NICK_USER_HOST, ':USER'),
+ ((_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.ANY, 'setattr_db.messaging.USER.to.CHANNEL:notice'))),
_MsgParseExpectation(
'PRIVMSG',
- (_MsgTok.NICK_USER_HOST, ':USER'),
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db.messaging.USER.to.:privmsg'))),
+ (_MsgToken.NICK_USER_HOST, ':USER'),
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db.messaging.USER.to.:privmsg'))),
_MsgParseExpectation(
'PRIVMSG',
- (_MsgTok.NICK_USER_HOST, ':USER'),
- ((_MsgTok.CHANNEL, ':CHANNEL'),
- (_MsgTok.ANY, 'setattr_db.messaging.USER.to.CHANNEL:privmsg'))),
+ (_MsgToken.NICK_USER_HOST, ':USER'),
+ ((_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.ANY, 'setattr_db.messaging.USER.to.CHANNEL:privmsg'))),
# connection state
_MsgParseExpectation(
'ERROR',
- _MsgTok.NONE,
- ((_MsgTok.ANY, 'setattr_db:connection_state'),),
+ _MsgToken.NONE,
+ ((_MsgToken.ANY, 'setattr_db:connection_state'),),
bonus_tasks=('do_consider_retry:', 'doafter_close:',)),
_MsgParseExpectation(
'PING',
- _MsgTok.NONE,
- ((_MsgTok.ANY, 'do_pong:reply'),)),
+ _MsgToken.NONE,
+ ((_MsgToken.ANY, 'do_pong:reply'),)),
_MsgParseExpectation(
'PONG',
- _MsgTok.SERVER,
- (_MsgTok.SERVER,
- (_MsgTok.ANY, 'do_check_pong:reply'),)),
+ _MsgToken.SERVER,
+ (_MsgToken.SERVER,
+ (_MsgToken.ANY, 'do_check_pong:reply'),)),
# misc.
_MsgParseExpectation(
'MODE',
- (_MsgTok.NICK_USER_HOST, 'setattr_db.users.me:nickuserhost'),
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db.users.me:modes'))),
+ (_MsgToken.NICK_USER_HOST, 'setattr_db.users.me:nickuserhost'),
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db.users.me:modes'))),
_MsgParseExpectation(
'MODE',
- _MsgTok.NICKNAME,
- ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
- (_MsgTok.ANY, 'setattr_db.users.me:modes'))),
+ _MsgToken.NICKNAME,
+ ((_MsgToken.NICKNAME, 'setattr_db.users.me:nick'),
+ (_MsgToken.ANY, 'setattr_db.users.me:modes'))),
_MsgParseExpectation(
'MODE',
- _MsgTok.SERVER,
- ((_MsgTok.CHANNEL, ':channel'),
- (_MsgTok.ANY, ':mode_on_nick'),
- (_MsgTok.NICKNAME, ':nick'))),
+ _MsgToken.SERVER,
+ ((_MsgToken.CHANNEL, ':channel'),
+ (_MsgToken.ANY, ':mode_on_nick'),
+ (_MsgToken.NICKNAME, ':nick'))),
_MsgParseExpectation(
'TOPIC',
- (_MsgTok.NICK_USER_HOST, 'setattr_db.channels.CHAN.topic:who'),
- ((_MsgTok.CHANNEL, ':CHAN'),
- (_MsgTok.ANY, 'setattr_db.channels.CHAN.topic:what')),
+ (_MsgToken.NICK_USER_HOST, 'setattr_db.channels.CHAN.topic:who'),
+ ((_MsgToken.CHANNEL, ':CHAN'),
+ (_MsgToken.ANY, 'setattr_db.channels.CHAN.topic:what')),
bonus_tasks=('doafter_db.channels.CHAN.topic.complete:',)),
_MsgParseExpectation(
'QUIT',
- (_MsgTok.NICK_USER_HOST, ':QUITTER'),
- ((_MsgTok.ANY, 'do_QUITTER.quit:message'),)),
+ (_MsgToken.NICK_USER_HOST, ':QUITTER'),
+ ((_MsgToken.ANY, 'do_QUITTER.quit:message'),)),
]