exclam: Add upload (!upl) command to upload files/media to chats/channels
Annotate for file /irgramd
2019-07-17 Peter 1 #!/usr/bin/env python3
2022-02-20 E. 2 #
01:25:27 ' 3 # irgramd: IRC-Telegram gateway - Main file
' 4 #
' 5 # Copyright (c) 2019 Peter Bui <pbui@bx612.space>
2024-04-14 E. 6 # Copyright (c) 2020-2024 E. Bosch <presidev@AT@gmail.com>
2022-02-20 E. 7 #
01:25:27 ' 8 # Use of this source code is governed by a MIT style license that
' 9 # can be found in the LICENSE file included in this project.
2019-07-17 Peter 10
01:23:35 ' 11 import logging
' 12 import os
2021-01-27 E. 13 import asyncio
23:13:48 ' 14
2019-07-17 Peter 15 import tornado.options
01:23:35 ' 16 import tornado.tcpserver
2021-12-08 E. 17 import ssl
2019-07-17 Peter 18
2020-11-19 E. 19 # Local modules
19:41:24 ' 20
2020-11-22 E. 21 from irc import IRCHandler
22:57:38 ' 22 from telegram import TelegramHandler
2023-12-20 E. 23 from utils import parse_loglevel
2019-07-17 Peter 24
2019-07-26 Peter 25 # IRC Telegram Daemon
01:05:21 ' 26
' 27 class IRCTelegramd(tornado.tcpserver.TCPServer):
2021-12-12 E. 28 def __init__(self, logger, settings):
2021-12-11 E. 29 self.logger = logger
2022-03-03 E. 30 effective_port = settings['irc_port']
2021-12-08 E. 31
00:39:32 ' 32 if settings['tls']:
' 33 if not settings['tls_cert']: # error
' 34 self.logger.error('TLS configured but certificate not present')
' 35 exit(1)
' 36 tls_context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
2021-12-10 E. 37 tls_context.load_cert_chain(os.path.expanduser(settings['tls_cert']), os.path.expanduser(settings['tls_key']))
2021-12-08 E. 38 if not effective_port:
00:39:32 ' 39 effective_port = 6697
' 40 self.logger.info('TLS configured')
' 41 else:
' 42 tls_context = None
' 43 if not effective_port:
' 44 effective_port = 6667
' 45
' 46 tornado.tcpserver.TCPServer.__init__(self, ssl_options=tls_context)
' 47
2022-03-03 E. 48 self.address = settings['irc_address']
2021-12-08 E. 49 self.port = effective_port
2020-11-22 E. 50 self.irc_handler = None
22:57:38 ' 51 self.tg_handler = None
2019-07-26 Peter 52
2019-07-17 Peter 53
01:23:35 ' 54 async def handle_stream(self, stream, address):
2020-11-22 E. 55 await self.irc_handler.run(stream, address)
2019-07-17 Peter 56
2021-12-12 E. 57 async def run(self, settings):
2019-07-17 Peter 58 self.listen(self.port, self.address)
2020-11-19 E. 59 self.logger.info('irgramd listening on %s:%s', self.address, self.port)
2021-12-12 E. 60 self.irc_handler = IRCHandler(settings)
01:15:52 ' 61 self.tg_handler = TelegramHandler(self.irc_handler, settings)
2020-11-22 E. 62 self.irc_handler.set_telegram(self.tg_handler)
2021-01-27 E. 63 await self.tg_handler.initialize_telegram()
2019-07-17 Peter 64
01:23:35 ' 65
' 66 # Main Execution
' 67
' 68 if __name__ == '__main__':
2023-12-20 E. 69 # Remove tornado.log options (ugly hacks but these must not be defined)
00:50:56 ' 70 tornado.options.options.logging = None
' 71 tornado_log_options = tuple(x for x in tornado.options.options._options.keys() if x != 'help' and x != 'logging')
' 72 for opt in tornado_log_options:
' 73 del tornado.options.options._options[opt]
' 74 # and reuse "--logging" to document empty "--" ;)
' 75 tornado.options.options._options['logging'].help = 'Stop parsing options'
' 76 for att in ('name', 'metavar', 'group_name', 'default'):
' 77 setattr(tornado.options.options._options['logging'], att, '')
' 78 # Define irgramd options
2022-02-16 E. 79 tornado.options.define('api_hash', default=None, metavar='HASH', help='Telegram API Hash for your account (obtained from https://my.telegram.org/apps)')
01:18:10 ' 80 tornado.options.define('api_id', type=int, default=None, metavar='ID', help='Telegram API ID for your account (obtained from https://my.telegram.org/apps)')
2022-03-08 E. 81 tornado.options.define('ask_code', default=False, help='Ask authentication code (sent by Telegram) in console instead of "code" service command in IRC')
2024-04-14 E. 82 tornado.options.define('cache_dir', default='~/.cache/irgramd', metavar='PATH', help='Cache directory where telegram media is saved by default')
2023-06-10 E. 83 tornado.options.define('char_in_encoding', default='utf-8', metavar='ENCODING', help='Character input encoding for IRC')
22:44:55 ' 84 tornado.options.define('char_out_encoding', default='utf-8', metavar='ENCODING', help='Character output encoding for IRC')
2022-02-16 E. 85 tornado.options.define('config', default='irgramdrc', metavar='CONFIGFILE', help='Config file absolute or relative to `config_dir` (command line options override it)')
2021-12-11 E. 86 tornado.options.define('config_dir', default='~/.config/irgramd', metavar='PATH', help='Configuration directory where telegram session info is saved')
2023-10-15 E. 87 tornado.options.define('download_media', default=True, help='Enable download of any media (photos, documents, etc.), if not set only a message of media will be shown')
2023-10-15 E. 88 tornado.options.define('download_notice', default=10, metavar='SIZE (MiB)', help='Enable a notice when a download starts if its size is greater than SIZE, this is useful when a download takes some time to be completed')
2023-04-29 E. 89 tornado.options.define('emoji_ascii', default=False, help='Replace emoji with ASCII emoticons')
2023-07-20 E. 90 tornado.options.define('geo_url', type=str, default=None, metavar='TEMPLATE_URL', help='Use custom URL for showing geo latitude/longitude location, eg. OpenStreetMap')
2023-05-06 E. 91 tornado.options.define('hist_timestamp_format', metavar='DATETIME_FORMAT', help='Format string for timestamps in history, see https://www.strfti.me')
2022-03-03 E. 92 tornado.options.define('irc_address', default='127.0.0.1', metavar='ADDRESS', help='Address to listen on for IRC')
2022-02-16 E. 93 tornado.options.define('irc_nicks', type=str, multiple=True, metavar='nick,..', help='List of nicks allowed for IRC, if `pam` and optionally `pam_group` are set, PAM authentication will be used instead')
00:58:19 ' 94 tornado.options.define('irc_password', default='', metavar='PASSWORD', help='Password for IRC authentication, if `pam` is set, PAM authentication will be used instead')
2022-03-03 E. 95 tornado.options.define('irc_port', type=int, default=None, metavar='PORT', help='Port to listen on for IRC. (default 6667, default with TLS 6697)')
2023-12-20 E. 96 tornado.options.define('log_file', default=None, metavar='PATH', help='File where logs are appended, if not set will be stderr')
00:50:56 ' 97 tornado.options.define('log_level', default='INFO', metavar='DEBUG|INFO|WARNING|ERROR|CRITICAL|NONE', help='The log level (and any higher to it) that will be logged')
2024-04-14 E. 98 tornado.options.define('media_dir', default=None, metavar='PATH', help='Directory where Telegram media files are downloaded, default "media" in `cache_dir`')
2022-01-30 E. 99 tornado.options.define('media_url', default=None, metavar='BASE_URL', help='Base URL for media files, should be configured in the external (to irgramd) webserver')
2021-12-13 E. 100 tornado.options.define('pam', default=False, help='Use PAM for IRC authentication, if not set you should set `irc_password`')
20:31:17 ' 101 tornado.options.define('pam_group', default=None, metavar='GROUP', help='Unix group allowed if `pam` enabled, if empty any user is allowed')
2022-02-16 E. 102 tornado.options.define('phone', default=None, metavar='PHONE_NUMBER', help='Phone number associated with the Telegram account to receive the authorization codes if necessary')
2023-04-26 E. 103 tornado.options.define('quote_length', default=50, metavar='LENGTH', help='Max length of the text quoted in replies and reactions, if longer is truncated')
2022-02-26 E. 104 tornado.options.define('service_user', default='TelegramServ', metavar='SERVICE_NICK', help='Nick of the service/control user, must be a nick not used by a real Telegram user')
2022-02-22 E. 105 tornado.options.define('test', default=False, help='Connect to Telegram test environment')
01:37:33 ' 106 tornado.options.define('test_datacenter', default=2, metavar='DATACENTER_NUMBER', help='Datacenter to connect to Telegram test environment')
' 107 tornado.options.define('test_host', default=None, metavar='HOST_IP', help='Host to connect to Telegram test environment (default: use a internal table depending on datacenter)')
' 108 tornado.options.define('test_port', default=443, metavar='PORT', help='Port to connect to Telegram test environment')
2023-05-06 E. 109 tornado.options.define('timezone', default='UTC', metavar='TIMEZONE', help='Timezone to use for dates (timestamps in history, last in dialogs, etc.)')
2022-02-16 E. 110 tornado.options.define('tls', default=False, help='Use TLS/SSL encrypted connection for IRC server')
00:58:19 ' 111 tornado.options.define('tls_cert', default=None, metavar='CERTFILE', help='IRC server certificate chain for TLS/SSL, also can contain private key if not defined with `tls_key`')
' 112 tornado.options.define('tls_key', default=None, metavar='KEYFILE', help='IRC server private key for TLS/SSL')
2024-04-14 E. 113 tornado.options.define('upload_dir', default=None, metavar='PATH', help='Directory where files to upload are picked up, default "upload" in `cache_dir`')
2023-12-20 E. 114 try:
00:50:56 ' 115 # parse cmd line first time to get --config and --config_dir
' 116 tornado.options.parse_command_line()
' 117 except Exception as exc:
' 118 print(exc)
' 119 exit(1)
2021-12-11 E. 120 config_file = os.path.expanduser(tornado.options.options.config)
21:32:43 ' 121 config_dir = os.path.expanduser(tornado.options.options.config_dir)
' 122 if not os.path.exists(config_dir):
' 123 os.makedirs(config_dir)
2023-12-20 E. 124 defered_logs = [(logging.INFO, 'Configuration Directory: %s', config_dir)]
2021-12-11 E. 125
21:32:43 ' 126 if not os.path.isabs(config_file):
' 127 config_file = os.path.join(config_dir, config_file)
' 128 if os.path.isfile(config_file):
2023-12-20 E. 129 defered_logs.append((logging.INFO, 'Using configuration file: %s', config_file))
00:50:56 ' 130 try:
' 131 tornado.options.parse_config_file(config_file)
' 132 except Exception as exc:
' 133 print(exc)
' 134 exit(1)
2021-12-11 E. 135 else:
2023-12-20 E. 136 defered_logs.append((logging.WARNING, 'Configuration file not present, using only command line options and defaults'))
2021-12-11 E. 137 # parse cmd line second time to override file options
21:32:43 ' 138 tornado.options.parse_command_line()
2019-07-26 Peter 139
01:05:21 ' 140 options = tornado.options.options.as_dict()
2021-12-12 E. 141 options['config_dir'] = config_dir
01:15:52 ' 142
2023-12-20 E. 143 # configure logging
00:50:56 ' 144 loglevel = parse_loglevel(options['log_level'])
' 145 if loglevel == False:
' 146 print("Option 'log_level' requires one of these values: {}".format(tornado.options.options._options['log-level'].metavar))
' 147 exit(1)
' 148 logger_formats = { 'datefmt':'%Y-%m-%d %H:%M:%S', 'format':'[%(levelname).1s %(asctime)s %(module)s:%(lineno)d] %(message)s' }
' 149 logger = logging.getLogger()
' 150 if options['log_file']:
' 151 logging.basicConfig(filename=options['log_file'], level=loglevel, **logger_formats)
' 152 else:
' 153 logging.basicConfig(level=loglevel, **logger_formats)
' 154
' 155 for log in defered_logs:
' 156 logger.log(*log)
' 157
' 158 # main loop
2021-12-12 E. 159 irc_server = IRCTelegramd(logger, options)
2023-03-19 E. 160 loop = asyncio.new_event_loop()
01:40:30 ' 161 loop.run_until_complete(irc_server.run(options))
' 162 loop.run_forever()