from enum import Enum, auto
from getpass import getuser
from threading import Thread
-from typing import Any, Callable, Generic, NamedTuple, Optional, Self, TypeVar
+from typing import Any, Callable, Generic, Optional, Self, TypeVar
from uuid import uuid4
# ourselves
from ircplom.events import (
from ircplom.irc_conn import (
BaseIrcConnection, IrcConnAbortException, IrcMessage,
ILLEGAL_NICK_CHARS, ILLEGAL_NICK_FIRSTCHARS, ISUPPORT_DEFAULTS, PORT_SSL)
+from ircplom.msg_parse_expectations import MsgTok, MSG_EXPECTATIONS
ClientsDb = dict[str, 'Client']
_NAMES_DESIRED_SERVER_CAPS = ('sasl',)
-class _MsgTok(Enum):
- ANY = auto()
- CHANNEL = auto()
- LIST = auto()
- NICKNAME = auto()
- NONE = auto()
- SERVER = auto()
- NICK_USER_HOST = auto()
-
-
-_MsgTokGuide = str | _MsgTok | tuple[str | _MsgTok, str]
-
-
-class _MsgParseExpectation(NamedTuple):
- source: _MsgTokGuide
- verb: str
- params: tuple[_MsgTokGuide, ...] = tuple()
- idx_into_list: int = -1
-
-
-_EXPECTATIONS: list[_MsgParseExpectation] = []
-
-# these we ignore except for confirming/collecting the nickname
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '001', # RPL_WELCOME
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '002', # RPL_YOURHOST
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '003', # RPL_CREATED
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '004', # RPL_MYINFO
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '250', # RPL_STATSDLINE / RPL_STATSCONN
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '251', # RPL_LUSERCLIENT
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '252', # RPL_LUSEROP
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '253', # RPL_LUSERUNKNOWN
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '254', # RPL_LUSERCHANNELS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '255', # RPL_LUSERME
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '265', # RPL_LOCALUSERS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '265', # RPL_LOCALUSERS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '266', # RPL_GLOBALUSERS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '266', # RPL_GLOBALUSERS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY,
- _MsgTok.ANY,
- _MsgTok.ANY)),
- _MsgParseExpectation(_MsgTok.SERVER,
- '375', # RPL_MOTDSTART already implied by 1st 372
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)),
-]
-
-# various login stuff
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '005', # RPL_ISUPPORT
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, ':isupport'),
- _MsgTok.ANY), # comment
- idx_into_list=1),
- _MsgParseExpectation(_MsgTok.SERVER,
- '372', # RPL_MOTD
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, ':line'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- '376', # RPL_ENDOFMOTD
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.ANY)), # comment
- _MsgParseExpectation(_MsgTok.SERVER,
- '396', # RPL_VISIBLEHOST
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.SERVER, 'set_me_attr:host'),
- _MsgTok.ANY)), # comment
-]
-
-# SASL
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '900', # RPL_LOGGEDIN
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.NICK_USER_HOST, 'set_me_attr:nickuserhost'),
- (_MsgTok.ANY, 'set_db_attr:sasl_account'),
- _MsgTok.ANY)), # comment
- _MsgParseExpectation(_MsgTok.SERVER,
- '903', # RPL_SASLSUCCESS
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, 'set_db_attr:sasl_auth_state'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- '904', # ERR_SASLFAIL
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, 'set_db_attr:sasl_auth_state'))),
- _MsgParseExpectation(_MsgTok.NONE,
- 'AUTHENTICATE',
- ('+',)),
-]
-
-# capability negotation
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('NEW', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('DEL', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('ACK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('ACK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('NAK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('NAK', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('LS', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('LS', ':subverb'),
- ('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('LS', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('LS', ':subverb'),
- ('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
-
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('LIST', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ('*',
- ('LIST', ':subverb'),
- ('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('LIST', ':subverb'),
- (_MsgTok.LIST, ':items'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'CAP',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- ('LIST', ':subverb'),
- ('*', ':tbc'),
- (_MsgTok.LIST, ':items'))),
-]
-
-# nickname management
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '432', # ERR_ERRONEOUSNICKNAME
- ('*',
- _MsgTok.NICKNAME, # no need to re-use the bad one
- _MsgTok.ANY)), # comment
- _MsgParseExpectation(_MsgTok.SERVER,
- '432', # ERR_ERRONEOUSNICKNAME
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- _MsgTok.NICKNAME, # no need to re-use the bad one
- _MsgTok.ANY)), # comment
- _MsgParseExpectation(_MsgTok.SERVER,
- '433', # ERR_NICKNAMEINUSE
- (_MsgTok.NICKNAME, # we rather go for incrementation
- (_MsgTok.NICKNAME, ':used'),
- _MsgTok.ANY)), # comment
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, ':named'),
- 'NICK',
- ((_MsgTok.NICKNAME, ':nick'),)),
-]
-
-# joining/leaving
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '353', # RPL_NAMREPLY
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- '=',
- (_MsgTok.CHANNEL, ':channel'),
- (_MsgTok.LIST, ':names'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- '366', # RPL_ENDOFNAMES
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.CHANNEL, ':channel'),
- _MsgTok.ANY)), # comment
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, ':joiner'),
- 'JOIN',
- ((_MsgTok.CHANNEL, ':channel'),)),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, ':parter'),
- 'PART',
- ((_MsgTok.CHANNEL, ':channel'),)),
-]
-
-# messaging
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.SERVER,
- '401', # ERR_NOSUCKNICK
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.NICKNAME, ':target'),
- _MsgTok.ANY)), # comment
- _MsgParseExpectation(_MsgTok.SERVER,
- 'NOTICE',
- ('*',
- (_MsgTok.ANY, ':message'))),
- _MsgParseExpectation(_MsgTok.SERVER,
- 'NOTICE',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, ':message'))),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, 'set_user:sender'),
- 'NOTICE',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, ':message'))),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, 'set_user:sender'),
- 'NOTICE',
- ((_MsgTok.CHANNEL, ':channel'),
- (_MsgTok.ANY, ':message'))),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, 'set_user:sender'),
- 'PRIVMSG',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, ':message'))),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, 'set_user:sender'),
- 'PRIVMSG',
- ((_MsgTok.CHANNEL, ':channel'),
- (_MsgTok.ANY, ':message'))),
-]
-
-# misc.
-_EXPECTATIONS += [
- _MsgParseExpectation(_MsgTok.NONE,
- 'ERROR',
- ((_MsgTok.ANY, 'set_db_attr:connection_state'),)),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, 'set_me_attr:nickuserhost'),
- 'MODE',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, 'set_db_attr:user_modes'))),
- _MsgParseExpectation(_MsgTok.NICKNAME,
- 'MODE',
- ((_MsgTok.NICKNAME, 'set_me_attr:nick'),
- (_MsgTok.ANY, 'set_db_attr:user_modes'))),
- _MsgParseExpectation(_MsgTok.NONE,
- 'PING',
- ((_MsgTok.ANY, ':reply'),)),
- _MsgParseExpectation((_MsgTok.NICK_USER_HOST, ':quitter'),
- 'QUIT',
- ((_MsgTok.ANY, ':message'),)),
-]
-
-
def _nick_incremented(nickname: str) -> str:
'Return nickname with number suffix incremented, or "0" if none.'
name, digits = ([(nickname, '')]
tok_type = (str | _NickUserHost | tuple[str, ...]
| dict[str, str | _Channel])
- def param_match(ex_tok: str | _MsgTok, msg_tok: str | list[str]
+ def param_match(ex_tok: str | MsgTok, msg_tok: str | list[str]
) -> Optional[tok_type | tuple[tok_type, ...]]:
if isinstance(msg_tok, list):
to_return = []
return tuple(to_return)
if isinstance(ex_tok, str):
return msg_tok if msg_tok == ex_tok else None
- if ex_tok is _MsgTok.NONE:
+ if ex_tok is MsgTok.NONE:
return msg_tok if msg_tok == '' else None
- if ex_tok is _MsgTok.SERVER:
+ if ex_tok is MsgTok.SERVER:
return msg_tok if ('.' in msg_tok
and not set('@!') & set(msg_tok)) else None
- if ex_tok is _MsgTok.CHANNEL:
+ if ex_tok is MsgTok.CHANNEL:
return {'id': msg_tok, 'db': self._db.channels[msg_tok]
} if self._db.is_chan_name(msg_tok) else None
- if ex_tok is _MsgTok.NICKNAME:
+ if ex_tok is MsgTok.NICKNAME:
return (msg_tok
if msg_tok[0] not in self._db.illegal_nick_firstchars
else None)
- if ex_tok is _MsgTok.NICK_USER_HOST:
+ if ex_tok is MsgTok.NICK_USER_HOST:
try:
return _NickUserHost.from_str(msg_tok)
except AssertionError:
return None
- if ex_tok is _MsgTok.LIST:
+ if ex_tok is MsgTok.LIST:
return tuple(msg_tok.split())
return msg_tok
- for ex in [ex for ex in _EXPECTATIONS if ex.verb == msg.verb]:
+ for ex in [ex for ex in MSG_EXPECTATIONS if ex.verb == msg.verb]:
tasks: dict[str, list[str]] = {}
to_return: dict[str, Any] = {'verb': ex.verb, '_tasks': tasks}
ex_tok_fields = tuple([ex.source] + list(ex.params))
--- /dev/null
+'Structured expectations and processing hints for server messages.'
+from enum import Enum, auto
+from typing import NamedTuple
+
+
+class MsgTok(Enum):
+ 'Server message token classifications.'
+ ANY = auto()
+ CHANNEL = auto()
+ LIST = auto()
+ NICKNAME = auto()
+ NONE = auto()
+ SERVER = auto()
+ NICK_USER_HOST = auto()
+
+
+_MsgTokGuide = str | MsgTok | tuple[str | MsgTok, str]
+
+
+class _MsgParseExpectation(NamedTuple):
+ source: _MsgTokGuide
+ verb: str
+ params: tuple[_MsgTokGuide, ...] = tuple()
+ idx_into_list: int = -1
+
+
+MSG_EXPECTATIONS: list[_MsgParseExpectation] = []
+
+# these we ignore except for confirming/collecting the nickname
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '001', # RPL_WELCOME
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '002', # RPL_YOURHOST
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '003', # RPL_CREATED
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '004', # RPL_MYINFO
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY,
+ MsgTok.ANY,
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '250', # RPL_STATSDLINE / RPL_STATSCONN
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '251', # RPL_LUSERCLIENT
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '252', # RPL_LUSEROP
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '253', # RPL_LUSERUNKNOWN
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '254', # RPL_LUSERCHANNELS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '255', # RPL_LUSERME
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '265', # RPL_LOCALUSERS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '265', # RPL_LOCALUSERS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '266', # RPL_GLOBALUSERS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '266', # RPL_GLOBALUSERS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY,
+ MsgTok.ANY,
+ MsgTok.ANY)),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '375', # RPL_MOTDSTART already implied by 1st 372
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)),
+]
+
+# various login stuff
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '005', # RPL_ISUPPORT
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, ':isupport'),
+ MsgTok.ANY), # comment
+ idx_into_list=1),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '372', # RPL_MOTD
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, ':line'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '376', # RPL_ENDOFMOTD
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation(MsgTok.SERVER,
+ '396', # RPL_VISIBLEHOST
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.SERVER, 'set_me_attr:host'),
+ MsgTok.ANY)), # comment
+]
+
+# SASL
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '900', # RPL_LOGGEDIN
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.NICK_USER_HOST, 'set_me_attr:nickuserhost'),
+ (MsgTok.ANY, 'set_db_attr:sasl_account'),
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation(MsgTok.SERVER,
+ '903', # RPL_SASLSUCCESS
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, 'set_db_attr:sasl_auth_state'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '904', # ERR_SASLFAIL
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, 'set_db_attr:sasl_auth_state'))),
+ _MsgParseExpectation(MsgTok.NONE,
+ 'AUTHENTICATE',
+ ('+',)),
+]
+
+# capability negotation
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('NEW', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('DEL', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('ACK', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('ACK', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('NAK', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('NAK', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('LS', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('LS', ':subverb'),
+ ('*', ':tbc'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('LS', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('LS', ':subverb'),
+ ('*', ':tbc'),
+ (MsgTok.LIST, ':items'))),
+
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('LIST', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ('*',
+ ('LIST', ':subverb'),
+ ('*', ':tbc'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('LIST', ':subverb'),
+ (MsgTok.LIST, ':items'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'CAP',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ ('LIST', ':subverb'),
+ ('*', ':tbc'),
+ (MsgTok.LIST, ':items'))),
+]
+
+# nickname management
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '432', # ERR_ERRONEOUSNICKNAME
+ ('*',
+ MsgTok.NICKNAME, # no need to re-use the bad one
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation(MsgTok.SERVER,
+ '432', # ERR_ERRONEOUSNICKNAME
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ MsgTok.NICKNAME, # no need to re-use the bad one
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation(MsgTok.SERVER,
+ '433', # ERR_NICKNAMEINUSE
+ (MsgTok.NICKNAME, # we rather go for incrementation
+ (MsgTok.NICKNAME, ':used'),
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, ':named'),
+ 'NICK',
+ ((MsgTok.NICKNAME, ':nick'),)),
+]
+
+# joining/leaving
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '353', # RPL_NAMREPLY
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ '=',
+ (MsgTok.CHANNEL, ':channel'),
+ (MsgTok.LIST, ':names'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ '366', # RPL_ENDOFNAMES
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.CHANNEL, ':channel'),
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, ':joiner'),
+ 'JOIN',
+ ((MsgTok.CHANNEL, ':channel'),)),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, ':parter'),
+ 'PART',
+ ((MsgTok.CHANNEL, ':channel'),)),
+]
+
+# messaging
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.SERVER,
+ '401', # ERR_NOSUCKNICK
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.NICKNAME, ':target'),
+ MsgTok.ANY)), # comment
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'NOTICE',
+ ('*',
+ (MsgTok.ANY, ':message'))),
+ _MsgParseExpectation(MsgTok.SERVER,
+ 'NOTICE',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, ':message'))),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, 'set_user:sender'),
+ 'NOTICE',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, ':message'))),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, 'set_user:sender'),
+ 'NOTICE',
+ ((MsgTok.CHANNEL, ':channel'),
+ (MsgTok.ANY, ':message'))),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, 'set_user:sender'),
+ 'PRIVMSG',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, ':message'))),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, 'set_user:sender'),
+ 'PRIVMSG',
+ ((MsgTok.CHANNEL, ':channel'),
+ (MsgTok.ANY, ':message'))),
+]
+
+# misc.
+MSG_EXPECTATIONS += [
+ _MsgParseExpectation(MsgTok.NONE,
+ 'ERROR',
+ ((MsgTok.ANY, 'set_db_attr:connection_state'),)),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, 'set_me_attr:nickuserhost'),
+ 'MODE',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, 'set_db_attr:user_modes'))),
+ _MsgParseExpectation(MsgTok.NICKNAME,
+ 'MODE',
+ ((MsgTok.NICKNAME, 'set_me_attr:nick'),
+ (MsgTok.ANY, 'set_db_attr:user_modes'))),
+ _MsgParseExpectation(MsgTok.NONE,
+ 'PING',
+ ((MsgTok.ANY, ':reply'),)),
+ _MsgParseExpectation((MsgTok.NICK_USER_HOST, ':quitter'),
+ 'QUIT',
+ ((MsgTok.ANY, ':message'),)),
+]