irc: Improve parsing of IRC commands
patch 1e0f59717da4cd1b659c91ef4b75715620d33325
Author: E. Bosch <presidev@AT@gmail.com>
Date: Sun Jan 24 03:31:52 CET 2021
* irc: Improve parsing of IRC commands
Add IRC replies/errors numerics
hunk ./irc.py 13
+from irc_replies import irc_codes
hunk ./irc.py 17
-PREFIX = r'(:[^ ]+ +|)'
-IRC_NICK_RX = re.compile(PREFIX + r'NICK +(:|)(?P<nick>[^\n\r]+)')
-IRC_PASS_RX = re.compile(PREFIX + r'PASS +(:|)(?P<password>[^\n\r]+)')
-IRC_PING_RX = re.compile(PREFIX + r'PING +(:|)(?P<payload>[^\n\r]+)')
-IRC_PRIVMSG_RX = re.compile(PREFIX + r'PRIVMSG +(?P<nick>[^ ]+) +(:|):(?P<message>[^\n\r]+)')
-IRC_USER_RX = re.compile(PREFIX + r'USER +(?P<username>[^ ]+) +[^ ]+ +[^ ]+ +(:|)(?P<realname>[^\n\r]+)')
-IRC_JOIN_RX = re.compile(PREFIX + r'JOIN +(?P<channel>[^ ]+)')
+PREFIX = r'(:[^ ]+ +|)'
+IRC_NICK_RX = re.compile(PREFIX + r'NICK( +:| +|\n)(?P<nick>[^\n]+|)')
+IRC_PASS_RX = re.compile(PREFIX + r'PASS( +:| +|\n)(?P<password>[^\n]+|)')
+IRC_PING_RX = re.compile(PREFIX + r'PING( +:| +|\n)(?P<payload>[^\n]+|)')
+IRC_PRIVMSG_RX = re.compile(PREFIX + r'PRIVMSG( +|\n)(?P<nick>[^ ]+)( +:| +|\n)(?P<message>[^\n]+|)')
+IRC_USER_RX = re.compile(PREFIX + r'USER( +|\n)(?P<username>[^ ]+) +[^ ]+ +[^ ]+( +:| +|\n)(?P<realname>[^\n]+|)')
+IRC_JOIN_RX = re.compile(PREFIX + r'JOIN( +|\n)(?P<channel>[^ ]+)')
hunk ./irc.py 47
- message = message.decode().rstrip()
+ message = message.decode()
hunk ./irc.py 49
-
- for pattern, handler in self.irc_handlers:
+ matched = False
+
+ for pattern, handler, register_required in self.irc_handlers:
hunk ./irc.py 54
- await handler(user, **matches.groupdict())
+ matched = True
+ if user.registered or not register_required:
+ params = matches.groupdict()
+ num_params = len([x for x in params.values() if x])
+ num_params_expected = len(params.keys())
+ if num_params >= num_params_expected:
+ await handler(user, **params)
+ else:
+ await self.reply(user, 'ERR_NEEDMOREPARAMS')
+
+ if not matched and user.registered:
+ await self.reply(user, 'ERR_UNKNOWNCOMMAND')
hunk ./irc.py 74
- (IRC_NICK_RX , self.handle_irc_nick),
- (IRC_PASS_RX , self.handle_irc_pass),
- (IRC_PING_RX , self.handle_irc_ping),
- (IRC_PRIVMSG_RX, self.handle_irc_privmsg),
- (IRC_USER_RX , self.handle_irc_user),
- (IRC_JOIN_RX , self.handle_irc_join),
+ # pattern handle register_required
+ (IRC_NICK_RX, self.handle_irc_nick, False),
+ (IRC_PASS_RX, self.handle_irc_pass, False),
+ (IRC_PING_RX, self.handle_irc_ping, False),
+ (IRC_PRIVMSG_RX, self.handle_irc_privmsg, True),
+ (IRC_USER_RX, self.handle_irc_user, False),
+ (IRC_JOIN_RX, self.handle_irc_join, True),
hunk ./irc.py 139
+ # IRC functions
+
+ async def reply(self, user, code):
+ num, tail = irc_codes[code]
+ await self.send_irc_command(user, ':{} {} {} :{}'.format(
+ self.hostname, num, user.irc_nick, tail
+ ))
+
hunk ./irc.py 187
+ self.registered = True
+ self.recv_pass = ''
addfile ./irc_replies.py
hunk ./irc_replies.py 1
+
+irc_codes = \
+{
+ 'RPL_WELCOME': ('001', 'Welcome to the irgramd gateway, {}'),
+ 'RPL_YOURHOST': ('002', 'Host {} is running irgramd version {}'),
+ 'RPL_CREATED': ('003', 'This server was created {}'),
+ 'RPL_MYINFO': ('004', '{} ircgramd {} o nt'),
+ 'RPL_ISUPPORT': ('005', 'CASEMAPPING=ascii CHANLIMIT=#&+: CHANTYPES=&#+ CHANMODES=,,,nt CHANNELLEN={} NICKLEN={} SAFELIST'),
+ 'RPL_MOTDSTART': ('375', '- {} Message of the day - '),
+ 'RPL_MOTD': ('372', '{}'),
+ 'RPL_ENDOFMOTD': (376, 'End of MOTD command'),
+ 'ERR_NOSUCHNICK': ('401', 'No such nick'),
+ 'ERR_NOSUCHSERVER': ('402', 'No such server'),
+ 'ERR_NOSUCHCHANNEL': ('403', 'No such channel'),
+ 'ERR_CANNOTSENDTOCHAN': ('404', 'Cannot send to channel'),
+ 'ERR_TOOMANYCHANNELS': ('405', 'Too many channels'),
+ 'ERR_WASNOSUCHNICK': ('406', 'There was no such nick'),
+ 'ERR_TOOMANYTARGETS': ('407', 'Too many targets'),
+ 'ERR_NOORIGIN': ('409', 'No origin present'),
+ 'ERR_NORECIPIENT': ('411', 'No recipient'),
+ 'ERR_NOTEXTTOSEND': ('412', 'No text to send'),
+ 'ERR_NOTOPLEVEL': ('413', 'No top level domain'),
+ 'ERR_WILDTOPLEVEL': ('414', 'Wild top level domain'),
+ 'ERR_UNKNOWNCOMMAND': ('421', 'Unknown command'),
+ 'ERR_NOMOTD': ('422', 'No MOTD'),
+ 'ERR_NOADMININFO': ('423', 'No admin info'),
+ 'ERR_FILEERROR': ('424', 'File error'),
+ 'ERR_NONICKNAMEGIVEN': ('431', 'No nickname given'),
+ 'ERR_ERRONEUSNICKNAME': ('432', 'Erroneus nickname'),
+ 'ERR_NICKNAMEINUSE': ('433', 'Nickname in use'),
+ 'ERR_NICKCOLLISION': ('436', 'Nickname collision'),
+ 'ERR_USERNOTINCHANNEL': ('441', 'User not in channel'),
+ 'ERR_NOTONCHANNEL': ('442', 'Not on channel'),
+ 'ERR_USERONCHANNEL': ('443', 'User on channel'),
+ 'ERR_NOLOGIN': ('444', 'No login'),
+ 'ERR_SUMMONDISABLED': ('445', 'Summon disabled'),
+ 'ERR_USERSDISABLED': ('446', 'Users disabled'),
+ 'ERR_NOTREGISTERED': ('451', 'Not registered'),
+ 'ERR_NEEDMOREPARAMS': ('461', 'Need more params'),
+ 'ERR_ALREADYREGISTRED': ('462', 'Already registered'),
+ 'ERR_NOPERMFORHOST': ('463', 'Insufficient permissions for host'),
+ 'ERR_PASSWDMISMATCH': ('464', 'Password mismatch'),
+ 'ERR_YOUREBANNEDCREEP': ('465', 'You\'re banned, creep'),
+ 'ERR_KEYSET': ('467', 'Key set'),
+ 'ERR_CHANNELISFULL': ('471', 'Channel is full'),
+ 'ERR_UNKNOWNMODE': ('472', 'Unknown mode'),
+ 'ERR_INVITEONLYCHAN': ('473', 'Invite only channel'),
+ 'ERR_BANNEDFROMCHAN': ('474', 'Banned from channel'),
+ 'ERR_BADCHANNELKEY': ('475', 'Bad channel key'),
+ 'ERR_NOPRIVILEGES': ('481', 'No privileges'),
+ 'ERR_CHANOPRIVSNEEDED': ('482', 'Channel +o privileges needed'),
+ 'ERR_CANTKILLSERVER': ('483', 'Cannot kill server'),
+ 'ERR_NOOPERHOST': ('491', 'No operator host'),
+ 'ERR_UMODEUNKNOWNFLAG': ('501', 'User mode unknown flag'),
+ 'ERR_USERSDONTMATCH': ('502', 'Users don\'t match'),
+}