patch 8e120e3fd8592748b35ae91c4acbf189036704d9 Author: E. Bosch Date: Sun Feb 7 03:14:36 CET 2021 * irc: Add WHOIS command diff -rN -u old-irgramd/irc.py new-irgramd/irc.py --- old-irgramd/irc.py 2024-10-23 06:25:37.228025781 +0200 +++ new-irgramd/irc.py 2024-10-23 06:25:37.236025768 +0200 @@ -30,6 +30,7 @@ IRC_USER_RX = re.compile(PREFIX + r'USER( +|\n)(?P[^ ]+) +[^ ]+ +[^ ]+( +:| +|\n)(?P[^\n]+|)') IRC_JOIN_RX = re.compile(PREFIX + r'JOIN( +|\n)(?P[^ ]+)') IRC_WHO_RX = re.compile(PREFIX + r'WHO( +:| +|\n)(?P[^\n]+|)') +IRC_WHOIS_RX = re.compile(PREFIX + r'WHOIS( +:| +|\n)(?P[^\n]+|)') # IRC Handler @@ -96,6 +97,7 @@ (IRC_USER_RX, self.handle_irc_user, False), (IRC_JOIN_RX, self.handle_irc_join, True), (IRC_WHO_RX, self.handle_irc_who, True), + (IRC_WHOIS_RX, self.handle_irc_whois, True), ) self.iid_to_tid = {} self.irc_channels = collections.defaultdict(set) @@ -182,6 +184,33 @@ )) await self.reply_code(user, 'RPL_ENDOFWHO', (chan,)) + async def handle_irc_whois(self, user, nicks): + self.logger.debug('Handling WHO: %s', nicks) + for nick in nicks.split(','): + ni = nick.lower() + real_ni = self.users[ni].irc_nick + if ni in self.users.keys(): + usr = self.users[ni] + await self.reply_code(user, 'RPL_WHOISUSER', (real_ni, usr.irc_username, usr.address, usr.irc_realname)) + await self.reply_code(user, 'RPL_WHOISSERVER', (real_ni, self.hostname)) + chans = usr.get_channels(self) + if chans: await self.reply_code(user, 'RPL_WHOISCHANNELS', (real_ni, chans)) + idle = await self.tg.get_telegram_idle(ni) + if idle != None: await self.reply_code(user, 'RPL_WHOISIDLE', (real_ni, idle)) + if usr.oper: await self.reply_code(user, 'RPL_WHOISOPERATOR', (real_ni,)) + if usr.stream: await self.reply_code(user, 'RPL_WHOISACCOUNT', (real_ni, + '{}!{}@Telegram'.format(self.tg.tg_username, self.tg.id + ))) + if await self.tg.is_bot(ni): + await self.reply_code(user, 'RPL_WHOISBOT', (real_ni,)) + elif usr.tls or not usr.stream: + proto = 'TLS' if usr.tls else 'MTProto' + server = self.hostname if usr.stream else 'Telegram' + await self.reply_code(user, 'RPL_WHOISSECURE', (real_ni, proto, server)) + await self.reply_code(user, 'RPL_ENDOFWHOIS', (real_ni,)) + else: + await self.reply_code(user, 'ERR_NOSUCHNICK', (nick,)) + async def handle_irc_privmsg(self, user, nick, message): self.logger.debug('Handling PRIVMSG: %s, %s', nick, message) @@ -284,10 +313,20 @@ self.registered = False self.password = '' self.recv_pass = '' + self.oper = False + self.tls = False + self.bot = None def get_irc_mask(self): return '{}!{}@{}'.format(self.irc_nick, self.irc_username, self.address) + def get_channels(self, irc): + res = '' + for chan in irc.irc_channels.keys(): + if self.irc_nick in irc.irc_channels[chan]: + res += irc.get_irc_op(self.irc_nick, chan) + chan + ' ' + return res + def valid_nick(self, nick): if len(nick) <= NICK_MAX_LENGTH and nick[0] in VALID_IRC_NICK_FIRST_CHARS: for x in nick[1:]: diff -rN -u old-irgramd/irc_replies.py new-irgramd/irc_replies.py --- old-irgramd/irc_replies.py 2024-10-23 06:25:37.236025768 +0200 +++ new-irgramd/irc_replies.py 2024-10-23 06:25:37.236025768 +0200 @@ -6,12 +6,20 @@ 'RPL_CREATED': ('003', ':This server was created {}'), 'RPL_MYINFO': ('004', '{} irgramd-{} o nt'), 'RPL_ISUPPORT': ('005', 'CASEMAPPING=ascii CHANLIMIT=#&+: CHANTYPES=&#+ CHANMODES=,,,nt CHANNELLEN={} NICKLEN={} SAFELIST :are supported by this server'), + 'RPL_WHOISUSER': ('311', '{} {} {} * :{}'), + 'RPL_WHOISSERVER': ('312', '{} {} :irgramd gateway'), + 'RPL_WHOISOPERATOR': ('313', '{} :is an irgramd operator'), 'RPL_ENDOFWHO': ('315', '{} :End of WHO list'), + 'RPL_WHOISIDLE': ('317', '{} {} :seconds idle'), + 'RPL_ENDOFWHOIS': ('318', '{} :End of WHOIS command'), + 'RPL_WHOISCHANNELS': ('319', '{} :{}'), + 'RPL_WHOISACCOUNT': ('330', '{} {} :Telegram name'), + 'RPL_WHOISBOT': ('335', '{} :is a Telegram bot'), 'RPL_WHOREPLY': ('352', '{} {} {} {} {} H{} :0 {}'), 'RPL_MOTDSTART': ('375', ':- {} Message of the day - '), 'RPL_MOTD': ('372', ':- {}'), 'RPL_ENDOFMOTD': ('376', 'End of MOTD command'), - 'ERR_NOSUCHNICK': ('401', 'No such nick'), + 'ERR_NOSUCHNICK': ('401', '{} :Nick not found'), 'ERR_NOSUCHSERVER': ('402', '{} :Target not found'), 'ERR_NOSUCHCHANNEL': ('403', 'No such channel'), 'ERR_CANNOTSENDTOCHAN': ('404', 'Cannot send to channel'), @@ -55,4 +63,5 @@ 'ERR_NOOPERHOST': ('491', 'No operator host'), 'ERR_UMODEUNKNOWNFLAG': ('501', 'User mode unknown flag'), 'ERR_USERSDONTMATCH': ('502', 'Users don\'t match'), + 'RPL_WHOISSECURE': ('671', '{} :is using a secure {} connection with {}'), } diff -rN -u old-irgramd/telegram.py new-irgramd/telegram.py --- old-irgramd/telegram.py 2024-10-23 06:25:37.236025768 +0200 +++ new-irgramd/telegram.py 2024-10-23 06:25:37.236025768 +0200 @@ -1,6 +1,7 @@ import logging import os +import datetime import telethon from telethon import types as tgty @@ -157,6 +158,45 @@ return nicks + async def get_telegram_idle(self, irc_nick, tid=None): + tid = self.get_tid(irc_nick, tid) + user = await self.telegram_client.get_entity(tid) + if isinstance(user.status,tgty.UserStatusRecently) or \ + isinstance(user.status,tgty.UserStatusOnline): + idle = 0 + elif isinstance(user.status,tgty.UserStatusOffline): + last = user.status.was_online + current = datetime.datetime.now(datetime.timezone.utc) + idle = int((current - last).total_seconds()) + elif isinstance(user.status,tgty.UserStatusLastWeek): + idle = 604800 + elif isinstance(user.status,tgty.UserStatusLastMonth): + idle = 2678400 + else: + idle = None + return idle + + async def is_bot(self, irc_nick, tid=None): + if self.irc.users[irc_nick].stream: + bot = False + else: + bot = self.irc.users[irc_nick].bot + if bot == None: + tid = self.get_tid(irc_nick, tid) + user = await self.telegram_client.get_entity(tid) + bot = user.bot + self.irc.users[irc_nick].bot = bot + return bot + + def get_tid(self, irc_nick, tid=None): + if tid: + pass + elif irc_nick in self.irc.iid_to_tid: + tid = self.irc.iid_to_tid[irc_nick.lower()] + else: + tid = self.id + return tid + async def handle_telegram_message(self, event): self.logger.debug('Handling Telegram Message: %s', event)