telegram, service: Move initial help to service module
Annotate for file service.py
2022-03-02 E. 1 # irgramd: IRC-Telegram gateway
19:18:03 ' 2 # service.py: IRC service/control command handlers
' 3 #
2023-03-29 E. 4 # Copyright (c) 2022,2023 E. Bosch <presidev@AT@gmail.com>
2022-03-02 E. 5 #
19:18:03 ' 6 # Use of this source code is governed by a MIT style license that
' 7 # can be found in the LICENSE file included in this project.
' 8
2023-06-25 E. 9 from utils import compact_date, command, HELP
2023-03-18 E. 10 from telethon import utils as tgutils
2022-03-19 E. 11
2023-06-22 E. 12 class service(command):
2022-03-08 E. 13 def __init__(self, settings, telegram):
2022-03-02 E. 14 self.commands = \
2023-06-25 E. 15 { # Command Handler Arguments Min Max Maxsplit
22:17:22 ' 16 'code': (self.handle_command_code, 1, 1, -1),
' 17 'dialog': (self.handle_command_dialog, 1, 2, -1),
' 18 'get': (self.handle_command_get, 2, 2, -1),
' 19 'help': (self.handle_command_help, 0, 1, -1),
' 20 'history': (self.handle_command_history, 1, 3, -1),
' 21 'mark_read': (self.handle_command_mark_read, 1, 1, -1),
2022-03-02 E. 22 }
2022-03-08 E. 23 self.ask_code = settings['ask_code']
21:58:55 ' 24 self.tg = telegram
2023-05-04 E. 25 self.irc = telegram.irc
2022-03-19 E. 26 self.tmp_ircnick = None
22:26:56 ' 27
2024-10-06 E. 28 def initial_help(self):
22:07:54 ' 29 return (
' 30 'Welcome to irgramd service',
' 31 'use /msg {} help'.format(self.irc.service_user.irc_nick),
' 32 'or equivalent in your IRC client',
' 33 'to get help',
' 34 )
' 35
2022-03-08 E. 36 async def handle_command_code(self, code=None, help=None):
21:58:55 ' 37 if not help:
' 38 if self.ask_code:
' 39 reply = ('Code will be asked on console',)
' 40 elif code.isdigit():
' 41 try:
' 42 await self.tg.telegram_client.sign_in(code=code)
' 43 except:
' 44 reply = ('Invalid code',)
' 45 else:
' 46 reply = ('Valid code', 'Telegram account authorized')
' 47 await self.tg.continue_auth()
' 48 else: # not isdigit
' 49 reply = ('Code must be numeric',)
' 50
' 51 else: # HELP.brief or HELP.desc (first line)
2023-05-07 E. 52 reply = (' code Enter authorization code',)
2022-03-08 E. 53 if help == HELP.desc: # rest of HELP.desc
21:58:55 ' 54 reply += \
' 55 (
' 56 ' code <code>',
' 57 'Enter authorization code sent by Telegram to the phone or to',
' 58 'another client connected.',
' 59 'This authorization code usually is only needed the first time',
' 60 'that irgramd connects to Telegram with a given account.',
2022-03-19 E. 61 )
22:26:56 ' 62 return reply
' 63
' 64 async def handle_command_dialog(self, command=None, id=None, help=None):
' 65 if not help:
' 66 if command == 'archive':
' 67 pass
' 68 elif command == 'delete':
' 69 pass
' 70 elif command == 'list':
' 71 reply = \
' 72 (
' 73 'Dialogs:',
2023-04-11 E. 74 ' {:<11} {:<9} {:<9} {:5} {:<3} {:<4} {:<6} {}'.format(
2022-03-19 E. 75 'Id', 'Unread', 'Mentions', 'Type', 'Pin', 'Arch', 'Last', 'Name'),
22:26:56 ' 76 )
' 77 async for dialog in self.tg.telegram_client.iter_dialogs():
2023-03-18 E. 78 id, type = tgutils.resolve_id(dialog.id)
2022-03-19 E. 79 unr = dialog.unread_count
22:26:56 ' 80 men = dialog.unread_mentions_count
2023-04-11 E. 81 ty = self.tg.get_entity_type(dialog.entity, format='short')
2022-03-19 E. 82 pin = 'Yes' if dialog.pinned else 'No'
22:26:56 ' 83 arch = 'Yes' if dialog.archived else 'No'
2023-05-07 E. 84 last = compact_date(dialog.date, self.tg.timezone)
2023-03-18 E. 85 if id == self.tg.id:
04:12:31 ' 86 name_in_irc = self.tmp_ircnick
' 87 else:
2023-12-02 E. 88 name_in_irc = self.tg.get_irc_name_from_telegram_id(id)
19:41:44 ' 89
2023-04-11 E. 90 reply += (' {:<11d} {:<9d} {:<9d} {:5} {:<3} {:<4} {:<6} {}'.format(
2022-03-19 E. 91 id, unr, men, ty, pin, arch, last, name_in_irc),
22:26:56 ' 92 )
' 93
' 94 else: # HELP.brief or HELP.desc (first line)
2023-05-07 E. 95 reply = (' dialog Manage conversations (dialogs)',)
2022-03-19 E. 96 if help == HELP.desc: # rest of HELP.desc
22:26:56 ' 97 reply += \
' 98 (
' 99 ' dialog <subcommand> [id]',
' 100 'Manage conversations (dialogs) established in Telegram, the',
' 101 'following subcommands are available:',
2024-04-18 E. 102 # ' archive <id> Archive the dialog specified by id',
23:11:38 ' 103 # ' delete <id> Delete the dialog specified by id',
2022-03-19 E. 104 ' list Show all dialogs',
2023-05-13 E. 105 )
22:39:42 ' 106 return reply
' 107
' 108 async def handle_command_get(self, peer=None, mid=None, help=None):
' 109 if not help:
2023-05-16 E. 110 msg = None
2023-05-13 E. 111 peer_id, reply = self.get_peer_id(peer.lower())
22:39:42 ' 112 if reply: return reply
2023-05-16 E. 113 else: reply = ()
2023-05-13 E. 114
2023-11-28 E. 115 # If the ID starts with '=' is absolute ID, not compact ID
21:38:01 ' 116 # character '=' is not used by compact IDs
' 117 if mid[0] == '=':
' 118 id = int(mid[1:])
' 119 else:
' 120 id = self.tg.mid.id_to_num_offset(peer_id, mid)
2023-05-16 E. 121 if id is not None:
21:13:51 ' 122 msg = await self.tg.telegram_client.get_messages(entity=peer_id, ids=id)
' 123 if msg is not None:
' 124 await self.tg.handle_telegram_message(event=None, message=msg, history=True)
' 125 else:
2023-06-25 E. 126 reply = ('Message not found',)
2023-05-13 E. 127 return reply
22:39:42 ' 128
' 129 else: # HELP.brief or HELP.desc (first line)
' 130 reply = (' get Get a message by id and peer',)
' 131 if help == HELP.desc: # rest of HELP.desc
' 132 reply += \
' 133 (
2023-11-28 E. 134 ' get <peer> <compact_id|=ID>',
21:38:01 ' 135 'Get one message from peer with the compact or absolute ID',
2022-03-08 E. 136 )
21:58:55 ' 137 return reply
' 138
' 139 async def handle_command_help(self, help_command=None, help=None):
2022-03-06 E. 140
01:36:51 ' 141 start_help = ('*** Telegram Service Help ***',)
' 142 end_help = ('*** End of Help ***',)
' 143
2022-03-08 E. 144 if help == HELP.brief:
2023-05-07 E. 145 help_text = (' help This help',)
2022-03-08 E. 146 elif not help_command or help_command == 'help':
2022-03-06 E. 147 help_text = start_help
01:36:51 ' 148 help_text += \
' 149 (
' 150 'This service contains specific Telegram commands that irgramd',
' 151 'cannot map to IRC commands. The following commands are available:',
' 152 )
' 153 for command in self.commands.values():
' 154 handler = command[0]
2022-03-08 E. 155 help_text += await handler(help=HELP.brief)
2022-03-06 E. 156 help_text += \
01:36:51 ' 157 (
2023-06-25 E. 158 'The commands begining with ! (exclamation) must be used directly',
22:17:22 ' 159 'in channels or chats. The following ! commands are available:',
' 160 )
' 161 for command in self.irc.exclam.commands.values():
' 162 handler = command[0]
' 163 help_text += await handler(help=HELP.brief)
' 164 help_text += \
' 165 (
2022-03-06 E. 166 'If you need more information about a specific command you can use',
01:36:51 ' 167 'help <command>',
' 168 )
' 169 help_text += end_help
2023-06-25 E. 170 elif help_command in (all_commands := dict(**self.commands, **self.irc.exclam.commands)).keys():
22:17:22 ' 171 handler = all_commands[help_command][0]
2022-03-06 E. 172 help_text = start_help
2022-03-08 E. 173 help_text += await handler(help=HELP.desc)
2022-03-06 E. 174 help_text += end_help
01:36:51 ' 175 else:
' 176 help_text = ('help: Unknown command',)
' 177 return help_text
' 178
2023-05-04 E. 179 async def handle_command_history(self, peer=None, limit='10', add_unread=None, help=None):
22:23:04 ' 180 if not help:
' 181 async def get_unread(tgt):
' 182 async for dialog in self.tg.telegram_client.iter_dialogs():
' 183 id, type = tgutils.resolve_id(dialog.id)
' 184 if id in self.tg.tid_to_iid.keys():
' 185 name = self.tg.tid_to_iid[id]
' 186 if tgt == name.lower():
' 187 count = dialog.unread_count
' 188 reply = None
' 189 break
' 190 else:
' 191 count = None
' 192 reply = ('Unknown unread',)
' 193 return count, reply
' 194
' 195 def conv_int(num_str):
' 196 if num_str.isdigit():
' 197 n = int(num_str)
' 198 err = None
' 199 else:
' 200 n = None
' 201 err = ('Invalid argument',)
' 202 return n, err
' 203
' 204 tgt = peer.lower()
2023-05-07 E. 205 peer_id, reply = self.get_peer_id(tgt)
2023-05-04 E. 206 if reply: return reply
22:23:04 ' 207
' 208 if limit == 'unread':
' 209 add_unread = '0' if add_unread is None else add_unread
' 210 add_unread_int, reply = conv_int(add_unread)
' 211 if reply: return reply
' 212
' 213 li, reply = await get_unread(tgt)
' 214 if reply: return reply
' 215 li += add_unread_int
' 216 elif add_unread is not None:
' 217 reply = ('Wrong number of arguments',)
' 218 return reply
' 219 elif limit == 'all':
' 220 li = None
' 221 else:
' 222 li, reply = conv_int(limit)
' 223 if reply: return reply
' 224
' 225 his = await self.tg.telegram_client.get_messages(peer_id, limit=li)
' 226 for msg in reversed(his):
2023-05-06 E. 227 await self.tg.handle_telegram_message(event=None, message=msg, history=True)
2023-05-04 E. 228 reply = ()
22:23:04 ' 229 return reply
' 230
' 231 else: # HELP.brief or HELP.desc (first line)
2023-05-07 E. 232 reply = (' history Get messages from history',)
2023-05-04 E. 233 if help == HELP.desc: # rest of HELP.desc
22:23:04 ' 234 reply += \
' 235 (
' 236 ' history <peer> [<limit>|all|unread [<plusN>]]',
' 237 'Get last <limit> number of messages already sent to <peer>',
' 238 '(channel or user). If not set <limit> is 10.',
' 239 'Instead of <limit>, "unread" is for messages not marked as read,',
' 240 'optionally <plusN> number of previous messages to the first unread.',
' 241 'Instead of <limit>, "all" is for retrieving all available messages',
' 242 'in <peer>.',
' 243 )
' 244 return reply
2022-03-06 E. 245
2023-05-07 E. 246 async def handle_command_mark_read(self, peer=None, help=None):
23:04:52 ' 247 if not help:
' 248 peer_id, reply = self.get_peer_id(peer.lower())
' 249 if reply: return reply
' 250
' 251 await self.tg.telegram_client.send_read_acknowledge(peer_id, clear_mentions=True)
' 252 reply = ('',)
' 253 else: # HELP.brief or HELP.desc (first line)
2023-05-07 E. 254 reply = (' mark_read Mark messages as read',)
2023-05-07 E. 255 if help == HELP.desc: # rest of HELP.desc
23:04:52 ' 256 reply += \
' 257 (
' 258 ' mark_read <peer>',
' 259 'Mark all messages on <peer> (channel or user) as read, this also will',
2024-08-29 E. 260 'reset the number of mentions to you on <peer>.',
2023-05-07 E. 261 )
23:04:52 ' 262 return reply
' 263
' 264 def get_peer_id(self, tgt):
' 265 if tgt in self.irc.users or tgt in self.irc.irc_channels:
' 266 peer_id = self.tg.get_tid(tgt)
' 267 reply = None
' 268 else:
' 269 peer_id = None
' 270 reply = ('Unknown user or channel',)
' 271 return peer_id, reply