irc: Fix JOIN command
patch 4b63ac15d2b61f2c0da0686ba1936c79d7136444
Author: E. Bosch <presidev@AT@gmail.com>
Date: Fri Feb 12 03:09:58 CET 2021
* irc: Fix JOIN command
diff -rN -u old-irgramd/irc.py new-irgramd/irc.py
--- old-irgramd/irc.py 2024-11-23 01:03:23.183043432 +0100
+++ new-irgramd/irc.py 2024-11-23 01:03:23.183043432 +0100
@@ -29,7 +29,7 @@
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_JOIN_RX = re.compile(PREFIX + r'JOIN( +|\n)(?P<channels>[^ ]+)')
IRC_WHO_RX = re.compile(PREFIX + r'WHO( +:| +|\n)(?P<target>[^\n]+|)')
IRC_WHOIS_RX = re.compile(PREFIX + r'WHOIS( +:| +|\n)(?P<nicks>[^\n]+|)')
@@ -153,10 +153,18 @@
user.registered = True
await self.send_greeting(user)
- async def handle_irc_join(self, user, channel):
- self.logger.debug('Handling JOIN: %s', channel)
+ async def handle_irc_join(self, user, channels):
+ self.logger.debug('Handling JOIN: %s', channels)
- await self.join_irc_channel(user, channel, True)
+ if channels == '0':
+ #part all
+ pass
+ else:
+ for channel in channels.split(','):
+ if channel.lower() in self.irc_channels.keys():
+ await self.join_irc_channel(user, channel, True)
+ else:
+ await reply_code(user, 'ERR_NOSUCHCHANNEL', (channel,))
async def handle_irc_ping(self, user, payload):
self.logger.debug('Handling PING: %s', payload)
@@ -267,35 +275,41 @@
await self.reply_code(user, 'RPL_ENDOFMOTD')
async def join_irc_channel(self, user, channel, full_join=False):
+ entity_cache = [None]
chan = channel.lower()
- self.irc_channels[chan].add(user.irc_nick)
- op = self.get_irc_op(self.tg.tg_username, channel)
- if op == '@': self.irc_channels_ops[chan].add(user.irc_nick)
- elif op == '~': self.irc_channels_founder[chan].add(user.irc_nick)
+ real_chan = self.get_realcaps_name(chan)
- # Join Channel
- await self.send_irc_command(user, ':{} JOIN :{}'.format(
- user.get_irc_mask(), channel
- ))
+ if full_join: self.irc_channels[chan].add(user.irc_nick)
+
+ # Notify IRC users in this channel
+ for usr in [self.users[x.lower()] for x in self.irc_channels[chan] if self.users[x.lower()].stream]:
+ await self.reply_command(usr, user, 'JOIN', (real_chan,))
if not full_join:
return
- # Get all users from channel
- tid = self.iid_to_tid[channel.lower()]
- nicks = self.irc_channels[channel.lower()]
-
- # Set channel topic
- topic = (await self.tg.telegram_client.get_entity(tid)).title
- await self.send_irc_command(user, ':{} TOPIC {} :{}'.format(
- user.get_irc_mask(), channel, topic
- ))
+ op = self.get_irc_op(self.tg.tg_username, channel)
+ if op == '@': self.irc_channels_ops[chan].add(user.irc_nick)
+ elif op == '~': self.irc_channels_founder[chan].add(user.irc_nick)
- # Send NAMESLIST
+ date = await self.tg.get_channel_creation(channel, entity_cache)
+ await self.reply_code(user, 'RPL_CREATIONTIME', (real_chan, date))
+ await self.irc_channel_topic(user, real_chan, entity_cache)
+ await self.irc_namelist(user, real_chan)
+
+ async def irc_channel_topic(self, user, channel, entity_cache):
+ topic = await self.tg.get_channel_topic(channel, entity_cache)
+ timestamp = await self.tg.get_channel_creation(channel, entity_cache)
+ founder = list(self.irc_channels_founder[channel.lower()])[0]
+ await self.reply_code(user, 'RPL_TOPIC', (channel, topic))
+ await self.reply_code(user, 'RPL_TOPICWHOTIME', (channel, founder, timestamp))
+
+ async def irc_namelist(self, user, channel):
+ nicks = [self.get_irc_op(x, channel) + x for x in self.irc_channels[channel.lower()]]
+ status = '='
for chunk in chunks(nicks, 25, ''):
- await self.send_irc_command(user, ':{} 353 {} = {} :{}'.format(
- self.hostname, user.irc_nick, channel, ' '.join(chunk)
- ))
+ await self.reply_code(user, 'RPL_NAMREPLY', (status, channel, ' '.join(chunk)))
+ await self.reply_code(user, 'RPL_ENDOFNAMES', (channel,))
async def part_irc_channel(self, user, channel):
self.irc_channels[channel].remove(user.irc_nick)
@@ -312,6 +326,10 @@
return '~'
return ''
+ def get_realcaps_name(self, name):
+ # name must be in lower
+ return self.tg.tid_to_iid[self.iid_to_tid[name]]
+
class IRCUser(object):
def __init__(self, stream, address, irc_nick=None, username=None, realname=None):
self.stream = stream
diff -rN -u old-irgramd/irc_replies.py new-irgramd/irc_replies.py
--- old-irgramd/irc_replies.py 2024-11-23 01:03:23.183043432 +0100
+++ new-irgramd/irc_replies.py 2024-11-23 01:03:23.187043425 +0100
@@ -13,15 +13,20 @@
'RPL_WHOISIDLE': ('317', '{} {} :seconds idle'),
'RPL_ENDOFWHOIS': ('318', '{} :End of WHOIS command'),
'RPL_WHOISCHANNELS': ('319', '{} :{}'),
+ 'RPL_CREATIONTIME': ('329', '{} {}'),
'RPL_WHOISACCOUNT': ('330', '{} {} :Telegram name'),
+ 'RPL_TOPIC': ('332', '{} :{}'),
+ 'RPL_TOPICWHOTIME': ('333', '{} {} {}'),
'RPL_WHOISBOT': ('335', '{} :is a Telegram bot'),
'RPL_WHOREPLY': ('352', '{} {} {} {} {} H{} :0 {}'),
+ 'RPL_NAMREPLY': ('353', '{} {} :{}'),
+ 'RPL_ENDOFNAMES': ('366', '{} :End of NAME reply'),
'RPL_MOTDSTART': ('375', ':- {} Message of the day - '),
'RPL_MOTD': ('372', ':- {}'),
'RPL_ENDOFMOTD': ('376', 'End of MOTD command'),
'ERR_NOSUCHNICK': ('401', '{} :Nick not found'),
'ERR_NOSUCHSERVER': ('402', '{} :Target not found'),
- 'ERR_NOSUCHCHANNEL': ('403', 'No such channel'),
+ 'ERR_NOSUCHCHANNEL': ('403', '{} :Channel not found'),
'ERR_CANNOTSENDTOCHAN': ('404', 'Cannot send to channel'),
'ERR_TOOMANYCHANNELS': ('405', 'Too many channels'),
'ERR_WASNOSUCHNICK': ('406', 'There was no such nick'),
diff -rN -u old-irgramd/telegram.py new-irgramd/telegram.py
--- old-irgramd/telegram.py 2024-11-23 01:03:23.183043432 +0100
+++ new-irgramd/telegram.py 2024-11-23 01:03:23.187043425 +0100
@@ -2,6 +2,7 @@
import logging
import os
import datetime
+import re
import telethon
from telethon import types as tgty
@@ -10,6 +11,10 @@
from include import CHAN_MAX_LENGHT, NICK_MAX_LENGTH
from irc import IRCUser
+# Constants
+
+TL_TYPES_IDENT = re.compile(r"<class 'telethon.tl.types.([^']+)'>")
+
# Configuration
# GET API_ID and API_HASH from https://my.telegram.org/apps
@@ -29,6 +34,7 @@
self.authorized = False
self.id = None
self.tg_username = None
+ self.channels_date = {}
async def initialize_telegram(self):
# Setup media folder
@@ -188,15 +194,43 @@
self.irc.users[irc_nick].bot = bot
return bot
- def get_tid(self, irc_nick, tid=None):
+ async def get_channel_topic(self, channel, entity_cache=[None]):
+ tid = self.get_tid(channel)
+ if entity_cache[0]:
+ entity = entity_cache[0]
+ else:
+ entity = await self.telegram_client.get_entity(tid)
+ entity_cache[0] = entity
+ entity_type = self.get_entity_type(entity)
+ return 'Telegram ' + entity_type + ' ' + str(tid) + ': ' + entity.title
+
+ async def get_channel_creation(self, channel, entity_cache=[None]):
+ tid = self.get_tid(channel)
+ if tid in self.channels_date.keys():
+ timestamp = self.channels_date[tid]
+ else:
+ if entity_cache[0]:
+ entity = entity_cache[0]
+ else:
+ entity = await self.telegram_client.get_entity(tid)
+ entity_cache[0] = entity
+ timestamp = entity.date.timestamp()
+ self.channels_date[tid] = timestamp
+ return int(timestamp)
+
+ def get_tid(self, irc_item, tid=None):
+ it = irc_item.lower()
if tid:
pass
- elif irc_nick in self.irc.iid_to_tid:
- tid = self.irc.iid_to_tid[irc_nick.lower()]
+ elif it in self.irc.iid_to_tid:
+ tid = self.irc.iid_to_tid[it]
else:
tid = self.id
return tid
+ def get_entity_type(self, entity):
+ return TL_TYPES_IDENT.match(str(type(entity))).groups()[0]
+
async def handle_telegram_message(self, event):
self.logger.debug('Handling Telegram Message: %s', event)