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
diff -rN -u old-irgramd/irc.py new-irgramd/irc.py
--- old-irgramd/irc.py 2024-10-23 06:32:26.943348226 +0200
+++ new-irgramd/irc.py 2024-10-23 06:32:26.943348226 +0200
@@ -10,16 +10,17 @@
# Local modules
from utils import chunks
+from irc_replies import irc_codes
# IRC Regular Expressions
-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>[^ ]+)')
# IRC Handler
@@ -43,13 +44,25 @@
while True:
message = await user.stream.read_until(b'\n')
- message = message.decode().rstrip()
+ message = message.decode()
self.logger.debug(message)
+ matched = False
- for pattern, handler in self.irc_handlers:
+ for pattern, handler, register_required in self.irc_handlers:
matches = pattern.match(message)
if matches:
- 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')
def set_telegram(self, tg):
self.tg = tg
@@ -58,12 +71,13 @@
def initialize_irc(self):
self.irc_handlers = (
- (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),
)
self.iid_to_tid = {}
self.irc_channels = collections.defaultdict(set)
@@ -122,6 +136,14 @@
telegram_id = self.iid_to_tid[nick]
await self.tg.telegram_client.send_message(telegram_id, message)
+ # 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
+ ))
+
async def join_irc_channel(self, user, channel, full_join=False):
self.irc_channels[channel].add(user.irc_nick)
@@ -162,3 +184,5 @@
self.irc_nick = None
self.irc_username = None
self.irc_realname = None
+ self.registered = True
+ self.recv_pass = ''
diff -rN -u old-irgramd/irc_replies.py new-irgramd/irc_replies.py
--- old-irgramd/irc_replies.py 1970-01-01 01:00:00.000000000 +0100
+++ new-irgramd/irc_replies.py 2024-10-23 06:32:26.943348226 +0200
@@ -0,0 +1,56 @@
+
+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'),
+}