|
|
@ -1,483 +1,318 @@ |
|
|
|
::HELP_GATE_CMD= "/login phone — sign in\n" \ |
|
|
|
"/logout — sign out\n" \ |
|
|
|
"/code — check one-time code\n" \ |
|
|
|
"/password — check 2fa password\n" \ |
|
|
|
"/setusername username — update @username\n" \ |
|
|
|
"/setname first last — update name\n" \ |
|
|
|
"/setbio — update about\n" \ |
|
|
|
"/setpassword [old] [new] — set or remove password" |
|
|
|
::HELP_CHAT_CMD= "/d [n] — delete your last message(s)\n" \ |
|
|
|
"/s regexp replace — edit your last message\n" \ |
|
|
|
"/search string [limit] — search <string> in current chat\n" \ |
|
|
|
"/history [limit] — get last [limit] messages from current chat\n" \ |
|
|
|
"/add @username — add @username to your chat list\n" \ |
|
|
|
"/join https://t.me/invite_link — join to chat via invite link\n" \ |
|
|
|
"/supergroup title description — create new supergroup «title» with «description»\n" \ |
|
|
|
"/channel title description — create new channel «title» with «description»\n" \ |
|
|
|
"/secret — create secretchat with current user\n" \ |
|
|
|
"/group title — create groupchat «title» with current user\n" \ |
|
|
|
"/block — blacklist current user\n" \ |
|
|
|
"/unblock — unblacklist current user\n" \ |
|
|
|
"/invite id or @username — add user to current chat\n" \ |
|
|
|
"/kick id or @username — remove user from current chat\n" \ |
|
|
|
"/ban id or @username [hours] — restrict @username from current chat for [hours] or forever\n" \ |
|
|
|
"/leave — leave current chat\n" \ |
|
|
|
"/close — close current secret chat\n" \ |
|
|
|
"/delete — delete current chat from chat list" |
|
|
|
|
|
|
|
class TelegramClient |
|
|
|
|
|
|
|
attr_reader :jid, :login, :online, :auth_state, :me |
|
|
|
attr_accessor :timezone |
|
|
|
attr_reader :session, :state |
|
|
|
@@config = {loglevel: :debug, verbosity: 2, lib_path: 'lib/', client: {api_id: 50322, api_hash: '9ff1a639196c0779c86dd661af8522ba', use_chat_info_database: false}, content: {path:'',link:'',upload:''}} # defaults |
|
|
|
|
|
|
|
# tdlib configuration, shared within all instances # |
|
|
|
def self.configure(params) |
|
|
|
@@loglevel = params['loglevel'] || Logger::DEBUG |
|
|
|
@@content_path = params['content_path'] || '/tmp' |
|
|
|
@@content_link = params['content_link'] || 'https://localhost/tg_media' |
|
|
|
@@content_upload_prefix = params["content_upload_prefix"] || 'https://localhost/upload/' |
|
|
|
TD.configure do |config| |
|
|
|
config.lib_path = params['path'] || 'lib/' # we hope it's here |
|
|
|
config.client.api_id = params['api_id'] || '50322' # telegram app. from debian repositories |
|
|
|
config.client.api_hash = params['api_hash'] || '9ff1a639196c0779c86dd661af8522ba' # telegram app. from debian repositories |
|
|
|
config.client.device_model = params['useragent'] || 'Zhabogram' |
|
|
|
config.client.application_version = params['version'] || '1.0' # hmm... |
|
|
|
config.client.use_test_dc = params['use_test_dc'] || false |
|
|
|
config.client.system_version = '42' # I think I have permission to hardcode The Ultimate Question of Life, the Universe, and Everything?.. |
|
|
|
config.client.use_file_database = true # wow |
|
|
|
config.client.use_message_database = false # such library |
|
|
|
config.client.use_chat_info_database = false # much options |
|
|
|
config.client.enable_storage_optimizer = false # ... |
|
|
|
end |
|
|
|
TD::Api.set_log_verbosity_level(params['verbosity'] || 1) |
|
|
|
## configure tdlib (when valid tdlib params specified) or zhabogram |
|
|
|
def self.configure(**config) |
|
|
|
@@config = @@config.merge(config) |
|
|
|
TD.config[:lib_path] = @@config[:lib_path] |
|
|
|
TD.configure do |config| @@config[:client].each do |key,value| config.client[key] = value if config.client.key? key end; end |
|
|
|
TD::Api.set_log_verbosity_level(@@config[:verbosity]) |
|
|
|
end |
|
|
|
|
|
|
|
# instance initialization # |
|
|
|
def initialize(xmpp, jid, login) |
|
|
|
return if not @@loglevel # call .configure() first |
|
|
|
@logger = Logger.new(STDOUT); @logger.level = @@loglevel; @logger.progname = '[TelegramClient: %s/%s]' % [jid, login] # create logger |
|
|
|
@logger.info 'Starting Telegram client..' |
|
|
|
@xmpp = xmpp # XMPP stream |
|
|
|
@jid = jid # user JID |
|
|
|
@timezone = '-00:00' # default timezone is UTC |
|
|
|
@login = login # telegram login |
|
|
|
@me = nil # self telegram profile |
|
|
|
@online = nil # we do not know |
|
|
|
@auth_state = 'nil' # too. |
|
|
|
@cache = {chats: {}, users: {}, photos: {}, subscribed: []} # cache |
|
|
|
## initialize telegram client instance (xmpp = XMPP stream, jid = user's jid , login = user's telegram login (for now, it is phone number) |
|
|
|
def initialize(xmpp, jid, **session) |
|
|
|
@logger = Logger.new(STDOUT, level: @@config[:loglevel], progname: 'TelegramClient: %s | %s' % [jid, session[:login]] ) |
|
|
|
@xmpp = xmpp |
|
|
|
@jid = jid |
|
|
|
@session = session |
|
|
|
@cache = {chats: {nil => []}, users: {}} |
|
|
|
@xmpp.send_presence(@jid, nil, :subscribe) |
|
|
|
@xmpp.send_presence(@jid, nil, :probe) |
|
|
|
end |
|
|
|
|
|
|
|
# initialize and connect telegram client # |
|
|
|
## connect telegram client |
|
|
|
def connect() |
|
|
|
return if @client and @client.ready? |
|
|
|
@logger.info 'Connecting to Telegram network..' |
|
|
|
@client = TD::Client.new(database_directory: 'sessions/' + @jid, files_directory: 'sessions/' + @jid + '/files/') # create telegram client instance |
|
|
|
@client.on(TD::Types::Update::AuthorizationState) do |update| self.auth_handler(update) end # register auth update handler |
|
|
|
@client.on(TD::Types::Update::File) do |update| self.file_handler(update); end # register file handler |
|
|
|
@client.on(TD::Types::Update::NewMessage) do |update| self.message_handler(update); end # register new message update handler |
|
|
|
@client.on(TD::Types::Update::MessageContent) do |update| self.message_edited_handler(update) end # register msg edited handler |
|
|
|
@client.on(TD::Types::Update::DeleteMessages) do |update| self.message_deleted_handler(update) end # register msg del handler |
|
|
|
@client.on(TD::Types::Update::NewChat) do |update| self.new_chat_handler(update) end # register new chat handler |
|
|
|
@client.on(TD::Types::Update::User) do |update| self.user_handler(update) end # new user update? |
|
|
|
@client.on(TD::Types::Update::UserStatus) do |update| self.status_update_handler(update) end # register status handler |
|
|
|
@client.connect() |
|
|
|
return true |
|
|
|
return if self.online? # already connected. |
|
|
|
@logger.warn 'Connecting to Telegram network..' |
|
|
|
@telegram = TD::Client.new(database_directory: 'sessions/' + @jid, files_directory: 'sessions/' + @jid + '/files/') |
|
|
|
@telegram.on(TD::Types::Update::AuthorizationState) do |u| @logger.debug(u); self.update_authorizationstate(u) end |
|
|
|
@telegram.on(TD::Types::Update::User) do |u| @logger.debug(u); self.update_user(u) end |
|
|
|
@telegram.on(TD::Types::Update::UserStatus) do |u| @logger.debug(u); self.update_userstatus(u) end |
|
|
|
@telegram.on(TD::Types::Update::NewChat) do |u| @logger.debug(u); self.update_newchat(u) end |
|
|
|
@telegram.on(TD::Types::Update::NewMessage) do |u| @logger.debug(u); self.update_newmessage(u) end |
|
|
|
@telegram.on(TD::Types::Update::MessageContent) do |u| @logger.debug(u); self.update_messagecontent(u) end |
|
|
|
@telegram.on(TD::Types::Update::DeleteMessages) do |u| @logger.debug(u); self.update_deletemessages(u) end |
|
|
|
@telegram.on(TD::Types::Update::File) do |u| @logger.debug(u); self.update_file(u) end |
|
|
|
@telegram.connect() |
|
|
|
end |
|
|
|
|
|
|
|
# disconnect and destroy telegram client # |
|
|
|
def disconnect(logout = false) |
|
|
|
return if not @client |
|
|
|
@logger.info 'Disconnecting..' |
|
|
|
@cache[:chats].each_key do |chat_id| @xmpp.presence(@jid, chat_id.to_s, :unavailable) end # send offline presences |
|
|
|
(logout) ? @client.log_out : @client.dispose # logout if needed |
|
|
|
@client = nil |
|
|
|
@online = false |
|
|
|
|
|
|
|
## disconnect telegram client |
|
|
|
def disconnect() |
|
|
|
return unless self.online? # already disconnected |
|
|
|
@logger.warn 'Disconnecting from Telegram network..' |
|
|
|
@cache[:chats].each_key do |chat| @xmpp.send_presence(@jid, chat, :unavailable) end # we're offline (unsubscribe if logout) |
|
|
|
@telegram.dispose() |
|
|
|
@telegram = nil |
|
|
|
end |
|
|
|
|
|
|
|
## online? |
|
|
|
def online? |
|
|
|
@telegram and @telegram.alive? |
|
|
|
end |
|
|
|
|
|
|
|
########################################### |
|
|
|
## Callback handlers ##################### |
|
|
|
########################################### |
|
|
|
|
|
|
|
# authorization handler # |
|
|
|
def auth_handler(update) |
|
|
|
@logger.debug 'Authorization state changed: %s' % update.authorization_state |
|
|
|
@auth_state = update.authorization_state.class.name |
|
|
|
|
|
|
|
######################################################################### |
|
|
|
# telegram updates handlers ############################################# |
|
|
|
######################################################################### |
|
|
|
|
|
|
|
## authorization state change |
|
|
|
def update_authorizationstate(update) |
|
|
|
@state = update.authorization_state.class.name |
|
|
|
case update.authorization_state |
|
|
|
# auth stage 0: specify login # |
|
|
|
when TD::Types::AuthorizationState::WaitPhoneNumber |
|
|
|
@logger.info 'Logging in..' |
|
|
|
@client.set_authentication_phone_number(@login) |
|
|
|
# auth stage 1: wait for authorization code # |
|
|
|
when TD::Types::AuthorizationState::WaitCode |
|
|
|
@logger.info 'Waiting for authorization code..' |
|
|
|
@xmpp.message(@jid, nil, 'Please, enter authorization code via /code 12345') |
|
|
|
# auth stage 2: wait for 2fa passphrase # |
|
|
|
when TD::Types::AuthorizationState::WaitPassword |
|
|
|
@logger.info 'Waiting for 2FA password..' |
|
|
|
@xmpp.message(@jid, nil, 'Please, enter 2FA passphrase via /password 12345') |
|
|
|
# authorization successful -- indicate that client is online and retrieve contact list # |
|
|
|
when TD::Types::AuthorizationState::Ready |
|
|
|
@logger.info 'Authorization successful!' |
|
|
|
@client.get_me().then { |user| @me = user }.wait |
|
|
|
@client.get_chats(limit=9999) |
|
|
|
@logger.info "Contact list updating finished" |
|
|
|
@xmpp.presence(@jid, nil, :subscribe) |
|
|
|
@xmpp.presence(@jid, nil, nil, nil, "Logged in as %s" % @login) |
|
|
|
@online = true |
|
|
|
# closing session: sent offline presences to XMPP user # |
|
|
|
when TD::Types::AuthorizationState::Closing |
|
|
|
@logger.info 'Closing session..' |
|
|
|
when TD::Types::AuthorizationState::WaitPhoneNumber # stage 0: set login |
|
|
|
@logger.warn 'Logging in..' |
|
|
|
@telegram.set_authentication_phone_number(@session[:login]) if @session[:login] |
|
|
|
@xmpp.send_message(@jid, nil, 'Please, enter your Telegram login via /login 12345') if not @session[:login] |
|
|
|
when TD::Types::AuthorizationState::WaitCode # stage 1: wait for auth code |
|
|
|
@logger.warn 'Waiting for authorization code..' |
|
|
|
@xmpp.send_message(@jid, nil, 'Please, enter authorization code via /code 12345') |
|
|
|
when TD::Types::AuthorizationState::WaitPassword # stage 2: wait for 2fa |
|
|
|
@logger.warn 'Waiting for 2FA password..' |
|
|
|
@xmpp.send_message(@jid, nil, 'Please, enter 2FA passphrase via /password 12345') |
|
|
|
when TD::Types::AuthorizationState::Ready # stage 3: auth completed |
|
|
|
@logger.warn 'Authorization successful!' |
|
|
|
@telegram.get_me.then{|me| @me = me}.wait |
|
|
|
@telegram.get_chats(limit=999).wait |
|
|
|
@session[:login] ||= @me.phone_number |
|
|
|
@xmpp.send_presence(@jid, nil, nil, nil, "Logged in %s" % @session[:login]) |
|
|
|
when TD::Types::AuthorizationState::Closing, TD::Types::AuthorizationState::Closed # disconnecting |
|
|
|
@logger.warn 'Closing session..' |
|
|
|
self.disconnect() |
|
|
|
# session closed gracefully |
|
|
|
when TD::Types::AuthorizationState::Closed |
|
|
|
@logger.info 'Session closed.' |
|
|
|
self.disconnect() |
|
|
|
end |
|
|
|
when TD::Types::AuthorizationState::LoggingOut # logout |
|
|
|
@logger.warn 'Logging out..' |
|
|
|
@session[:login] = nil |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
# message from telegram network handler # |
|
|
|
def message_handler(update, show_date = false) |
|
|
|
## message received |
|
|
|
def update_newmessage(update, show_date = false) |
|
|
|
return if update.message.is_outgoing and update.message.sending_state.instance_of? TD::Types::MessageSendingState::Pending # ignore self outgoing messages |
|
|
|
@logger.warn 'New message from chat %s' % update.message.chat_id |
|
|
|
|
|
|
|
@logger.debug 'Got NewMessage update' |
|
|
|
@logger.debug update.message.to_json |
|
|
|
@logger.info 'New message from Telegram chat %s' % update.message.chat_id |
|
|
|
|
|
|
|
# add to contact list |
|
|
|
self.process_chat_info(update.message.chat_id, true) if not @cache[:subscribed].include? update.message.chat_id |
|
|
|
|
|
|
|
# message content |
|
|
|
prefix = [] |
|
|
|
content = update.message.content |
|
|
|
|
|
|
|
# file handling |
|
|
|
file = case content |
|
|
|
when TD::Types::MessageContent::Sticker then [content.sticker.sticker, 'sticker.webp'] |
|
|
|
when TD::Types::MessageContent::VoiceNote then [content.voice_note.voice, 'voicenote (%i s.).oga' % content.voice_note.duration] |
|
|
|
when TD::Types::MessageContent::VideoNote then [content.video_note.video, 'videonote (%i s.).mp4' % content.video_note.duration] |
|
|
|
when TD::Types::MessageContent::Animation then [content.animation.animation, 'animation.mp4' ] |
|
|
|
when TD::Types::MessageContent::Photo then [content.photo.sizes[-1].photo, 'photo' + content.photo.id + '.jpg'] |
|
|
|
when TD::Types::MessageContent::Audio then [content.audio.audio, 'audio' + content.audio.file_name] |
|
|
|
when TD::Types::MessageContent::Video then [content.video.video, 'video' + content.video.file_name] |
|
|
|
when TD::Types::MessageContent::Document then [content.document.document, 'doc' + content.document.file_name] |
|
|
|
end |
|
|
|
|
|
|
|
# text handling |
|
|
|
text = case content |
|
|
|
content, prefix = update.message.content, [] |
|
|
|
text = case content # text |
|
|
|
when TD::Types::MessageContent::Sticker then content.sticker.emoji |
|
|
|
when TD::Types::MessageContent::BasicGroupChatCreate, TD::Types::MessageContent::SupergroupChatCreate then "has created chat" |
|
|
|
when TD::Types::MessageContent::ChatJoinByLink then "joined chat via invite link" |
|
|
|
when TD::Types::MessageContent::ChatAddMembers then "invited %s" % self.format_contact(message.content.member_user_ids.first) |
|
|
|
when TD::Types::MessageContent::ChatDeleteMember then "kicked %s" % self.format_contact(update.message.content.user_id) |
|
|
|
when TD::Types::MessageContent::PinMessage then "pinned message: %s" % self.format_message(update.message.chat_id, content.message_id) |
|
|
|
when TD::Types::MessageContent::ChatChangeTitle then "chat title set to: %s" % update.message.content.title.to_s |
|
|
|
when TD::Types::MessageContent::ChatChangeTitle then "chat title set to: %s" % update.message.content.title |
|
|
|
when TD::Types::MessageContent::Location then "coordinates: %s | https://www.google.com/maps/search/%s,%s/" % [content.location.latitude, content.location.longitude] |
|
|
|
when TD::Types::MessageContent::Photo, TD::Types::MessageContent::Audio, TD::Types::MessageContent::Video, TD::Types::MessageContent::Document then content.caption.text |
|
|
|
when TD::Types::MessageContent::Text then content.text.text |
|
|
|
when TD::Types::MessageContent::VoiceNote then content.caption.text |
|
|
|
when TD::Types::MessageContent::VideoNote then '' |
|
|
|
when TD::Types::MessageContent::Animation then '' |
|
|
|
else "unknown message type %s" % update.message.content.class |
|
|
|
else "unknown message (%s)" % update.message.content.class |
|
|
|
end |
|
|
|
|
|
|
|
# download file if needed |
|
|
|
@client.download_file(file[0].id) if file and not file[0].local.is_downloading_completed |
|
|
|
|
|
|
|
# forwards, replies and message id.. |
|
|
|
prefix << DateTime.strptime((update.message.date+Time.now.getlocal(@timezone).utc_offset).to_s,'%s').strftime("%d %b %Y %H:%M:%S") if show_date # show date if its |
|
|
|
file = case content # file(s) |
|
|
|
when TD::Types::MessageContent::Sticker then [content.sticker.sticker, 'sticker.webp'] |
|
|
|
when TD::Types::MessageContent::VoiceNote then [content.voice_note.voice, 'voice note (%i s.).oga' % content.voice_note.duration] |
|
|
|
when TD::Types::MessageContent::VideoNote then [content.video_note.video, 'video note (%i s.).mp4' % content.video_note.duration] |
|
|
|
when TD::Types::MessageContent::Animation then [content.animation.animation, 'animation.mp4' ] |
|
|
|
when TD::Types::MessageContent::Photo then [content.photo.sizes[-1].photo, content.photo.id + '.jpg'] |
|
|
|
when TD::Types::MessageContent::Audio then [content.audio.audio, content.audio.file_name] |
|
|
|
when TD::Types::MessageContent::Video then [content.video.video, 'video' + content.video.file_name + '.mp4'] |
|
|
|
when TD::Types::MessageContent::Document then [content.document.document, content.document.file_name] |
|
|
|
end |
|
|
|
@telegram.download_file(file[0].id) if file and not file[0].local.is_downloading_completed # download file(s) |
|
|
|
prefix << DateTime.strptime((update.message.date+Time.now.getlocal(@session[:timezone]).utc_offset).to_s,'%s').strftime("%d %b %Y %H:%M:%S") if show_date # show date if its |
|
|
|
prefix << (update.message.is_outgoing ? '➡ ' : '⬅ ') + update.message.id.to_s # message direction |
|
|
|
prefix << "%s" % self.format_contact(update.message.sender_user_id) if update.message.chat_id < 0 # show sender in group chats |
|
|
|
prefix << "%s" % self.format_contact(update.message.sender_user_id) if update.message.chat_id < 0 and update.message.sender_user_id # show sender in group chats |
|
|
|
prefix << "fwd: %s" % self.format_contact(update.message.forward_info.sender_user_id) if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd from user |
|
|
|
prefix << "fwd: %s%s" % [self.format_contact(update.message.forward_info.chat_id), (update.message.forward_info.author_signature != '') ? " (%s)"%update.message.forward_info.author_signature : ''] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedPost # fwd from chat |
|
|
|
prefix << "reply: %s" % self.format_message(update.message.chat_id, update.message.reply_to_message_id, false) if update.message.reply_to_message_id.to_i != 0 # reply to |
|
|
|
prefix << "file: %s" % self.format_file(file[0], file[1]) if file |
|
|
|
prefix << "reply: %s" % self.format_message(update.message.chat_id, update.message.reply_to_message_id, true) if update.message.reply_to_message_id.to_i != 0 # reply to |
|
|
|
prefix << "file: %s" % self.format_content(file[0], file[1]) if file |
|
|
|
prefix = prefix.join(' | ') |
|
|
|
prefix += (update.message.chat_id < 0 and text and text != "") ? "\n" : '' # \n if it is groupchat and message is not empty |
|
|
|
prefix += (update.message.chat_id > 0 and text and text != "") ? " | " : '' |
|
|
|
|
|
|
|
# OTR support |
|
|
|
text = prefix + text unless text.start_with? '?OTR' |
|
|
|
|
|
|
|
# read message & send it to xmpp |
|
|
|
@client.view_messages(update.message.chat_id, [update.message.id], force_read: true) |
|
|
|
@xmpp.message(@jid, update.message.chat_id.to_s, text) |
|
|
|
text = prefix + text unless text.start_with? '?OTR' # OTR support (I do not know why would you need it, seriously) |
|
|
|
@telegram.view_messages(update.message.chat_id, [update.message.id], force_read: true) # mark message as read |
|
|
|
@xmpp.send_message(@jid, update.message.chat_id, text) # forward message to XMPP |
|
|
|
end |
|
|
|
|
|
|
|
# new chat update -- when tg client discovers new chat # |
|
|
|
def new_chat_handler(update) |
|
|
|
@logger.debug 'Got NewChat update' |
|
|
|
@logger.debug update.to_json |
|
|
|
self.process_chat_info(update.chat.id) |
|
|
|
end |
|
|
|
|
|
|
|
# user -- something changed in user data # |
|
|
|
def user_handler(update) |
|
|
|
@logger.debug 'Got User update' |
|
|
|
@logger.debug update.to_json |
|
|
|
self.process_user_info(update.user.id) |
|
|
|
end |
|
|
|
|
|
|
|
# edited msg # |
|
|
|
def message_edited_handler(update) |
|
|
|
@logger.debug 'Got MessageEdited update' |
|
|
|
@logger.debug update.to_json |
|
|
|
|
|
|
|
# formatting |
|
|
|
text = "✎ %s | %s" % [update.message_id.to_s, update.new_content.text.text.to_s] |
|
|
|
@xmpp.message(@jid, update.chat_id.to_s, text) |
|
|
|
## message content updated |
|
|
|
def update_messagecontent(update) |
|
|
|
text = "✎ %s | %s" % [update.message_id, update.new_content.text.text] |
|
|
|
@xmpp.send_message(@jid, update.chat_id, text) |
|
|
|
end |
|
|
|
|
|
|
|
# deleted msg # |
|
|
|
def message_deleted_handler(update) |
|
|
|
@logger.debug 'Got MessageDeleted update' |
|
|
|
@logger.debug update.to_json |
|
|
|
return if not update.is_permanent |
|
|
|
text = "✗ %s |" % update.message_ids.join(',') |
|
|
|
@xmpp.message(@jid, update.chat_id.to_s, text) |
|
|
|
## message(s) deleted |
|
|
|
def update_deletemessages(update) |
|
|
|
text = "✗ %s" % update.message_ids.join(',') |
|
|
|
@xmpp.send_message(@jid, update.chat_id, text) if update.is_permanent |
|
|
|
end |
|
|
|
|
|
|
|
# status update handler # |
|
|
|
def status_update_handler(update) |
|
|
|
@logger.debug 'Got new StatusUpdate' |
|
|
|
@logger.debug update.to_json |
|
|
|
return if update.user_id == @me.id # ignore self statuses |
|
|
|
self.process_status_update(update.user_id, update.status, false) |
|
|
|
## new chat discovered |
|
|
|
def update_newchat(update) |
|
|
|
@telegram.download_file(update.chat.photo.small.id).wait if update.chat.photo |
|
|
|
@cache[:chats][update.chat.id] = update.chat |
|
|
|
@xmpp.send_presence(@jid, update.chat.id, :subscribe, nil, nil, update.chat.title.to_s) unless (update.chat.type.instance_of? TD::Types::ChatType::Supergroup and update.chat.type.is_channel and update.chat.last_read_inbox_message_id == 0) |
|
|
|
self.process_status_update(update.chat.id, update.chat.title, :chat) if update.chat.id < 0 |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# file msg -- symlink to download path # |
|
|
|
def file_handler(update) |
|
|
|
@logger.debug 'Got File update' |
|
|
|
@logger.debug update.to_json |
|
|
|
if update.file.local.is_downloading_completed then |
|
|
|
source = update.file.local.path.to_s |
|
|
|
target = self.format_file(update.file, update.file.local.path, true) |
|
|
|
@logger.debug 'Downloading of <%s> completed! Created link to <%s>' % [source, target] |
|
|
|
File.symlink(source, target) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
########################################### |
|
|
|
## LooP handlers ######################### |
|
|
|
########################################### |
|
|
|
|
|
|
|
# processing authorization # |
|
|
|
def process_auth(typ, auth_data) |
|
|
|
@logger.info "Authorizing with :%s.." % typ |
|
|
|
@client.check_authentication_code(auth_data) if typ == '/code' |
|
|
|
@client.check_authentication_password(auth_data) if typ == '/password' |
|
|
|
## new user discovered |
|
|
|
def update_user(update) |
|
|
|
@cache[:users][update.user.id] = update.user |
|
|
|
self.process_status_update(update.user.id, update.user.status) |
|
|
|
end |
|
|
|
|
|
|
|
# /command # |
|
|
|
def process_command(chat_id, text) |
|
|
|
arg = text[0..2] == '/s/' ? ['/sed', text[3..-1]] : text.split |
|
|
|
|
|
|
|
# .. |
|
|
|
if arg[1] and arg[1][0] == '@' then @client.search_public_chat(arg[1][1..-1]).then {|c| resolve = c}.wait end # try to resolve @username from second arg # |
|
|
|
if arg[1].to_i < 0 then resolve = self.process_chat_info(arg[1].to_i, false) end # try to resolve chat_id/user_id from second arg |
|
|
|
if arg[1].to_i > 0 then resolve = self.process_user_info(arg[1].to_i) end # try to resolve user_id from second arg |
|
|
|
|
|
|
|
# command... |
|
|
|
response = nil |
|
|
|
current = @cache[:chats][chat_id] # current chat |
|
|
|
resolve = resolve || nil # resolved chat or nil |
|
|
|
chat = resolve || current # resolved chat or current |
|
|
|
case arg[0] |
|
|
|
when '/info' then response = self.format_contact(chat.id) # print information |
|
|
|
when '/add' then (chat.id > 0) ? self.process_chat_info(chat.id, true) : @client.join_chat(chat.id).wait # add contact |
|
|
|
when '/join' then @client.join_chat_by_invite_link(arg[1]).wait if arg[1][0..3] == 'http' # join chat by link |
|
|
|
when '/secret' then @client.create_new_secret_chat(chat.id).wait if chat.id > 0 # new secret chat |
|
|
|
when '/group' then @client.create_new_basic_group_chat(resolve.id, arg[2]).it if resolve and arg[2] |
|
|
|
when '/supergroup' then @client.create_new_supergroup_chat(arg[1], arg[2]).wait if arg[2] |
|
|
|
when '/channel' then @client.create_new_supergroup_chat(arg[1], arg[2], is_channel: true).wait if arg[2] |
|
|
|
when '/invite' then @client.add_chat_member(current.id, resolve.id).wait if resolve |
|
|
|
when '/kick' then @client.set_chat_member_status(current, resolve.id, TD::Types::ChatMemberStatus::Left.new()).wait if resolve |
|
|
|
when '/ban' then @client.set_chat_member_status(current.id, resolve.id, TD::Types::ChatMemberStatus::Banned.new(banned_until_date: (arg[1]) ? Time.now.getutc.to_i + arg[1].to_i * 3600 : 0)).wait if resolve |
|
|
|
when '/block' then @client.block_user(current.id).wait |
|
|
|
when '/unblock' then @client.unblock_user(current.id).wait |
|
|
|
when '/members' then members = [] |
|
|
|
response = "- Members of chat %s -\n\n" % current.title |
|
|
|
@client.search_chat_members(current.id,filter:TD::Types::ChatMembersFilter::Members.new).then{ |m| members+=m.members }.wait if current.type.instance_of? TD::Types::ChatType::BasicGroup # basic |
|
|
|
@client.get_supergroup_members(current.type.supergroup_id).then{|m| members+=m.members }.wait if current.type.instance_of? TD::Types::ChatType::Supergroup # super |
|
|
|
members.each do |user| response += "%s | Role: %s \n" % [self.format_contact(user.user_id, true, false), user.status.class] end |
|
|
|
when '/leave','/delete' then @client.close_chat(current.id).wait |
|
|
|
@client.leave_chat(current.id) if current.type.instance_of? TD::Types::ChatType::BasicGroup or current.type.instance_of? TD::Types::ChatType::Supergroup |
|
|
|
@client.close_secret_chat(current.type.secret_chat_id).wait if current.type.instance_of? TD::Types::ChatType::Secret |
|
|
|
@client.delete_chat_history(current.id, true).wait |
|
|
|
@xmpp.presence(@jid, current.id.to_s, :unsubscribed) |
|
|
|
@xmpp.presence(@jid, current.id.to_s, :unavailable) |
|
|
|
@cache[:chats].delete(current.id) if @cache[:chats].key? current.id |
|
|
|
@cache[:users].delete(current.id) if @cache[:users].key? current.id |
|
|
|
when '/sed' then id, edited = nil, nil |
|
|
|
sed = arg[1].split('/') |
|
|
|
@client.search_chat_messages(current.id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then{|m| id,edited = m.messages[0].id,m.messages[0].content.text.text.to_s}.wait |
|
|
|
@client.edit_message_text(current.id,id,TD::Types::InputMessageContent::Text.new(text: {text: edited.gsub(Regexp.new(sed[0]),sed[1]), entities: []},disable_web_page_preview: false, clear_draft: true)).wait if id |
|
|
|
when '/d' then id = arg[1].to_i |
|
|
|
@client.search_chat_messages(current.id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|m| id = m.messages[0].id }.wait if id == 0 |
|
|
|
@client.delete_messages(current.id, [id], true) |
|
|
|
when '/search' then count = arg[1] || 10 |
|
|
|
query = arg[2] || nil |
|
|
|
@client.search_chat_messages(current.id, 0, count, query: query, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs| |
|
|
|
msgs.messages.reverse.each do |msg| self.message_handler(TD::Types::Update::NewMessage.new(message: msg, disable_notification: false, contains_mention: false), true) end |
|
|
|
}.wait |
|
|
|
when '/setusername' then @client.set_username(arg[1] || '') |
|
|
|
when '/setname' then @client.set_name(arg[1] || '', arg[2] || '') |
|
|
|
when '/setbio' then @client.set_bio(arg[1..99].join(' ')) |
|
|
|
when '/setpassword' then old_password, new_password = arg[1], arg[2] |
|
|
|
old_password = '' if old_password == 'nil' |
|
|
|
new_password = nil if new_password == 'nil' |
|
|
|
@client.set_password(old_password, new_password: new_password) |
|
|
|
when '/dump' then response = current.to_json |
|
|
|
else response = 'Unknown command. |
|
|
|
|
|
|
|
/s/mitsake/mistake/ — Edit last message |
|
|
|
/d — Delete last message |
|
|
|
|
|
|
|
/info id — Information about user/chat by its id |
|
|
|
/add @username or id — Create conversation with specified user or chat id |
|
|
|
/join chat_link or id — Join chat by its link or id |
|
|
|
|
|
|
|
/secret @username — Create "secret chat" with specified user |
|
|
|
/group @username groupname — Create group chat named groupname with @username |
|
|
|
/supergroup name description — Create supergroup chat |
|
|
|
/channel name description — Create channel |
|
|
|
|
|
|
|
/members — Supergroup members |
|
|
|
/search count query — Search in chat history |
|
|
|
|
|
|
|
/invite @username — Invite @username to current chat |
|
|
|
/kick @username — Remove @username from current chat |
|
|
|
/ban @username [hours] — Ban @username in current chat for [hours] hrs or forever if [hours] not specified |
|
|
|
/block — Blacklistscurrent user |
|
|
|
/unblock — Remove current user from blacklist |
|
|
|
/delete — Delete current chat |
|
|
|
/leave — Leave current chat |
|
|
|
|
|
|
|
/setusername username — Set username |
|
|
|
/setname First Last — Set name |
|
|
|
/setbio Bio — Set bio |
|
|
|
/setpassword old new — Set 2FA password (use "nil" for no password") |
|
|
|
' |
|
|
|
end |
|
|
|
|
|
|
|
@xmpp.message(@jid, chat_id.to_s, response) if response |
|
|
|
## user status changed |
|
|
|
def update_userstatus(update) |
|
|
|
self.process_status_update(update.user_id, update.status, nil, false) |
|
|
|
end |
|
|
|
|
|
|
|
# processing outgoing message from queue # |
|
|
|
def process_outgoing_msg(chat_id, text) |
|
|
|
@logger.info 'Sending message to Telegram chat %s...' % chat_id |
|
|
|
|
|
|
|
# processing /commands # |
|
|
|
return if not @cache[:chats].key? chat_id # null chat |
|
|
|
return self.process_command(chat_id, text) if text[0] == '/' |
|
|
|
|
|
|
|
# handling replies # |
|
|
|
reply_to = 0 |
|
|
|
if text[0] == '>' and text.match(Regexp.new /^>( )?[0-9]{10,20}/) then |
|
|
|
text = text.split("\n") |
|
|
|
reply_to = text[0].scan(/\d+/).first.to_i |
|
|
|
text = text.drop(1).join("\n") |
|
|
|
end |
|
|
|
|
|
|
|
# handling files received from xmpp # |
|
|
|
message = TD::Types::InputMessageContent::Text.new(:text => { :text => text, :entities => []}, :disable_web_page_preview => false, :clear_draft => true ) |
|
|
|
message = TD::Types::InputMessageContent::Document.new(document: TD::Types::InputFile::Remote.new(id: text), caption: { :text => '', :entities => []}) if text.start_with? @@content_upload_prefix |
|
|
|
|
|
|
|
# send message and mark chat as read # |
|
|
|
@client.send_message(chat_id, message, reply_to_message_id: reply_to) |
|
|
|
## file downloaded |
|
|
|
def update_file(update) |
|
|
|
return unless update.file.local.is_downloading_completed # not really |
|
|
|
File.symlink(update.file.local.path, "%s/%s%s" % [@@config[:content][:path], Digest::SHA256.hexdigest(update.file.remote.id), File.extname(update.file.local.path)]) |
|
|
|
end |
|
|
|
|
|
|
|
# update users information and save it to cache # |
|
|
|
def process_chat_info(chat_id, subscription = false) |
|
|
|
@logger.debug 'Updating chat id %s..' % chat_id.to_s |
|
|
|
@client.get_chat(chat_id).then { |chat| |
|
|
|
@cache[:chats][chat_id] = chat # cache chat |
|
|
|
@client.download_file(chat.photo.small.id).then{|f| @cache[:photos][chat_id] = f}.wait if chat.photo # download userpic |
|
|
|
if subscription then # send subscription request |
|
|
|
@xmpp.presence(@jid, chat_id.to_s, :subscribe, nil, nil, chat.title.to_s) |
|
|
|
@cache[:subscribed] << chat_id |
|
|
|
end |
|
|
|
self.process_status_update(chat_id, chat.title.to_s, true) if chat.id < 0 # groups presence |
|
|
|
}.wait |
|
|
|
return @cache[:chats][chat_id] if @cache[:chats].key? chat_id |
|
|
|
end |
|
|
|
|
|
|
|
# update user info in cache and sync status to roster if needed # |
|
|
|
def process_user_info(user_id) |
|
|
|
@logger.debug 'Updating user id %s..' % user_id |
|
|
|
@client.get_user(user_id).then { |user| |
|
|
|
@cache[:users][user_id] = user # add to cache |
|
|
|
@client.get_user_full_info(user_id).then{ |bio| @cache[:chats][user_id].attributes[:client_data] = bio.bio }.wait |
|
|
|
self.process_status_update(user_id, user.status, true) # status update |
|
|
|
}.wait |
|
|
|
return @cache[:users][user_id] if @cache[:users].key? user_id |
|
|
|
######################################################################### |
|
|
|
# xmpp to telegram gateway functions #################################### |
|
|
|
######################################################################### |
|
|
|
|
|
|
|
## get user and chat information from cache (or try to retrieve it, if missing) |
|
|
|
def get_contact(id) |
|
|
|
return unless self.online? # we're offline. |
|
|
|
@telegram.search_public_chat(id).then{|chat| id = chat.id }.wait if id[0] == '@' |
|
|
|
@telegram.get_user(id).wait if not @cache[:users][id] and (id>0) |
|
|
|
@telegram.get_chat(id).wait if not @cache[:chats][id] |
|
|
|
return @cache[:chats][id], @cache[:users][id] |
|
|
|
end |
|
|
|
|
|
|
|
# sync statuses with XMPP roster |
|
|
|
def sync_status() |
|
|
|
@logger.debug "Syncing statuses with roster.." |
|
|
|
@cache[:chats].each_value do |chat| self.process_status_update(chat.id, (chat.id > 0 and @cache[:users].include? chat.id) ? @cache[:users][chat.id].status : chat.title.to_s, true) end |
|
|
|
end |
|
|
|
|
|
|
|
# convert telegram status to XMPP one |
|
|
|
def process_status_update(user_id, status, immed = true) |
|
|
|
@logger.debug "Processing status update for user id %s.." % user_id.to_s |
|
|
|
xmpp_show, xmpp_status, xmpp_photo = nil |
|
|
|
case status |
|
|
|
when TD::Types::UserStatus::Online then xmpp_show, xmpp_status = nil, "Online" |
|
|
|
when TD::Types::UserStatus::Offline then xmpp_show, xmpp_status = (Time.now.getutc.to_i - status.was_online.to_i < 3600) ? :away : :xa, DateTime.strptime((status.was_online+Time.now.getlocal(@timezone).utc_offset).to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y") |
|
|
|
when TD::Types::UserStatus::Recently then xmpp_show, xmpp_status = :dnd, "Last seen recently" |
|
|
|
when TD::Types::UserStatus::LastWeek then xmpp_show, xmpp_status = :unavailable, "Last seen last week" |
|
|
|
when TD::Types::UserStatus::LastMonth then xmpp_show, xmpp_status = :unavailable, "Last seen last month" |
|
|
|
else xmpp_show, xmpp_status = :chat, status |
|
|
|
## set contact status |
|
|
|
def process_status_update(chat_id, status=nil, show=nil, immed=true) |
|
|
|
return unless self.online? # we're offline. |
|
|
|
@logger.info "Status update for %s" % chat_id |
|
|
|
chat, user = self.get_contact(chat_id) |
|
|
|
photo = Digest::SHA1.hexdigest(IO.binread(chat.photo.small.local.path)) if chat and chat.photo and File.exist? chat.photo.small.local.path |
|
|
|
status ||= user.status if user and user.status |
|
|
|
case status |
|
|
|
when nil then show, status = :chat, chat ? chat.title : nil |
|
|
|
when TD::Types::UserStatus::Online then show, status = nil, "Online" |
|
|
|
when TD::Types::UserStatus::Recently then show, status = :dnd, "Last seen recently" |
|
|
|
when TD::Types::UserStatus::LastWeek then show, status = :unavailable, "Last seen last week" |
|
|
|
when TD::Types::UserStatus::LastMonth then show, status = :unavailable, "Last seen last month" |
|
|
|
when TD::Types::UserStatus::Empty then show, status = :unavailable, "Last seen a long time ago" |
|
|
|
when TD::Types::UserStatus::Offline then show, status = (Time.now.getutc.to_i-status.was_online.to_i<3600) ? :away : :xa, |
|
|
|
DateTime.strptime((status.was_online+Time.now.getlocal(@session[:timezone]).utc_offset).to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y") |
|
|
|
end |
|
|
|
|
|
|
|
xmpp_photo = self.format_file(@cache[:photos][user_id], 'image.jpg', true) if @cache[:photos].include? user_id |
|
|
|
xmpp_photo = (File.exist? xmpp_photo.to_s) ? Digest::SHA1.hexdigest(IO.binread(xmpp_photo)) : nil |
|
|
|
# ... |
|
|
|
return @xmpp.presence(@jid, user_id.to_s, nil, xmpp_show, xmpp_status, nil, xmpp_photo, immed) |
|
|
|
@xmpp.send_presence(@jid, chat_id, nil, show, status, nil, photo, immed) |
|
|
|
end |
|
|
|
|
|
|
|
# get contact information (for vcard). |
|
|
|
def get_contact_info(chat_id) |
|
|
|
return if not @cache[:chats].key? chat_id # no such chat # |
|
|
|
|
|
|
|
username, firstname, lastname, phone, bio, userpic = nil |
|
|
|
title = @cache[:chats][chat_id].title # <FN> |
|
|
|
|
|
|
|
# user information |
|
|
|
if @cache[:users].key? chat_id then # its an user |
|
|
|
firstname = @cache[:users][chat_id].first_name # <N/GIVEN> |
|
|
|
lastname = @cache[:users][chat_id].last_name # <N/FAMILY> |
|
|
|
username = @cache[:users][chat_id].username # <NICKNAME> |
|
|
|
phone = @cache[:users][chat_id].phone_number # <TEL> |
|
|
|
bio = @cache[:chats][chat_id].client_data # <DESC> |
|
|
|
userpic = self.format_file(@cache[:photos][chat_id], 'image.jpg', true) if @cache[:photos].include? chat_id |
|
|
|
userpic = (File.exist? userpic.to_s) ? Base64.encode64(IO.binread(userpic)) : nil |
|
|
|
end |
|
|
|
## send outgoing message to telegram user |
|
|
|
def process_outgoing_message(chat_id, text, message_id = nil) |
|
|
|
return if self.process_command(chat_id, text.split.first, text.split[1..-1]) # try to execute a command (and do not send on success) |
|
|
|
return unless self.online? # we're offline. |
|
|
|
@logger.warn 'Send message to chat %s' % chat_id |
|
|
|
reply = text.lines[0].scan(/\d+/).first.to_i if text.lines[0] =~ /^> ?[0-9]{10}/ # quotations |
|
|
|
file = TD::Types::InputFile::Remote.new(id: text) if text.start_with? @@config[:content][:upload] # attach a file |
|
|
|
text = TD::Types::FormattedText.new(text: (reply or file) ? text.lines[1..-1].join : text, entities: []) # remove first line from text |
|
|
|
message = TD::Types::InputMessageContent::Text.new(text: text, disable_web_page_preview: false, clear_draft: false) # compile our message |
|
|
|
document = TD::Types::InputMessageContent::Document.new(document: file, caption: text) if file # we can try to send a document |
|
|
|
message_id ? @telegram.edit_message_text(chat_id, message_id, message) : @telegram.send_message(chat_id, document || message, reply_to_message_id: reply || 0).rescue{@telegram.send_message(chat_id, message, 0)} |
|
|
|
end |
|
|
|
|
|
|
|
# .. |
|
|
|
return title, username, firstname, lastname, phone, bio, userpic |
|
|
|
## /commands (some telegram actions) |
|
|
|
def process_command(chat_id, cmd, args) |
|
|
|
chat, user = self.get_contact(chat_id) unless chat_id == 0 # get chat information |
|
|
|
if chat_id == 0 then # transport commands |
|
|
|
case cmd |
|
|
|
when '/login' then @telegram.set_authentication_phone_number(args[0]).then{|_| @session[:login] = args[0]} unless @session[:login] # sign in |
|
|
|
when '/logout' then @telegram.log_out().then{|_| @cache[:chats].each_key do |chat| @xmpp.send_presence(@jid, chat, :unsubscribed); @session[:login] = nil end } # sign out |
|
|
|
when '/code' then @telegram.check_authentication_code(args[0]) # check auth code |
|
|
|
when '/password' then @telegram.check_authentication_password(args[0]) # chech auth password |
|
|
|
when '/setusername' then @telegram.set_username(args[0] || '') # set @username |
|
|
|
when '/setname' then @telegram.set_name(args[0] || '', args[1] || '') # set My Name |
|
|
|
when '/setbio' then @telegram.set_bio(args[0] || '') # set About |
|
|
|
when '/setpassword' then @telegram.set_password((args[1] ? args[0] : ''), args[1]) # set password |
|
|
|
else @xmpp.send_message(@jid, nil, ::HELP_GATE_CMD) |
|
|
|
end |
|
|
|
return true # stop executing |
|
|
|
else # chat commands |
|
|
|
case cmd |
|
|
|
when '/d' then @telegram.delete_messages(chat.id, @telegram.search_chat_messages(chat.id, 0, args[0]||1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).value.messages.map(&:id), true) # delete last message(s) |
|
|
|
when '/s' then @telegram.search_chat_messages(chat.id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).value.messages.each do |msg| self.process_outgoing_message(chat.id, msg.content.text.text.to_s.gsub(Regexp.new(args[0]),args[1..-1].join(' ')), msg.id) end # edit last message |
|
|
|
when '/add' then @telegram.search_public_chat(args[0]).then{|chat| @xmpp.send_presence(@jid, chat.id, :subscribe)}.wait # add @contact |
|
|
|
when '/join' then @telegram.join_chat_by_invite_link(args[0]) # join https://t.me/publichat |
|
|
|
when '/supergroup' then @telegram.create_new_supergroup_chat(args[0], args[1..-1].join(' '), is_channel: false) # create new supergroup |
|
|
|
when '/channel' then @telegram.create_new_supergroup_chat(args[0], args[1..-1].join(' '), is_channel: true) # create new channel |
|
|
|
when '/secret' then @telegram.create_new_secret_chat(chat.id) if user # create secret chat with current user |
|
|
|
when '/group' then @telegram.create_new_basic_group_chat(chat.id, args[0]) if user # create group chat with current user |
|
|
|
when '/block' then @telegram.block_user(chat.id) if user # blacklists current user |
|
|
|
when '/unblock' then @telegram.unblock_user(chat.id) if user # unblacklists current user |
|
|
|
when '/invite' then @telegram.add_chat_member(chat.id, (args[0].to_i == 0 ? @telegram.search_public_chat(args[0]).value.id : args[0].to_i)) if chat.id < 0 # invite @username to current groupchat |
|
|
|
when '/kick' then @telegram.set_chat_member_status(chat.id, (args[0].to_i == 0 ? @telegram.search_public_chat(args[0]).value.id : args[0].to_i)) if chat.id < 0 # kick @username from current group chat |
|
|
|
when '/ban' then @telegram.set_chat_member_status(chat.id, (args[0].to_i == 0 ? @telegram.search_public_chat(args[0]).value.id : args[0].to_i), TD::Types::ChatMemberStatus::Banned(banned_until_date: (args[1].to_i > 0 ? Time.now.getutc.to_i+(args[1].to_i*3600) : 0))) if chat.id < 0 # ban @username from current chat [for N hours] |
|
|
|
when '/leave' then @telegram.leave_chat(chat.id).then{|result| @xmpp.send_presence(@jid, chat_id, :unsubscribed)} if chat.type.instance_of? TD::Types::ChatType::Supergroup or chat.type.instance_of? TD::Types::ChatType::BasicGroup # leave current chat |
|
|
|
when '/close' then @telegram.close_secret_chat(chat.type.secret_chat_id).then{|result| @xmpp.send_presence(@jid, chat_id, :unsubscribed)} if chat.type.instance_of? TD::Types::ChatType::Secret # close secret chat |
|
|
|
when '/delete' then @telegram.delete_chat_history(chat.id, true).then{|result| @xmpp.send_presence(@jid, chat_id, :unsubscribed)} # delete current chat |
|
|
|
when '/search' then @telegram.search_chat_messages(chat.id, 0, args[1]||10, query: args[0]||nil, filter: TD::Types::SearchMessagesFilter::Empty.new).value.messages.reverse.each do |msg| @xmpp.send_message(@jid, chat_id, self.format_message(nil,nil,nil,msg)) end # search messages within current chat |
|
|
|
when '/history' then @telegram.get_chat_history(chat.id, 0, 0, args[0]||10).value.messages.reverse.each do |msg| @xmpp.send_message(@jid, chat_id, self.format_message(nil,nil,msg)) end # get latest entries from history |
|
|
|
when '/help' then @xmpp.send_message(@jid, chat_id, ::HELP_CHAT_CMD) |
|
|
|
else return # continue executing |
|
|
|
end |
|
|
|
return true # stop executing |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
# resolve id by @username (or just return id) |
|
|
|
def resolve_username(username) |
|
|
|
resolved = username |
|
|
|
if username[0] == '@' then @client.search_public_chat(username[1..-1]).then {|chat| resolved = '@' + chat.id.to_s}.wait end |
|
|
|
if username[0..3] == 'http' or username[0..3] == 't.me' then @client.join_chat_by_invite_link(username) end |
|
|
|
return resolved |
|
|
|
end |
|
|
|
######################################################################### |
|
|
|
# formatting functions ################################################# |
|
|
|
######################################################################### |
|
|
|
|
|
|
|
########################################### |
|
|
|
## Format functions ####################### |
|
|
|
########################################### |
|
|
|
# format tg user name # |
|
|
|
def format_contact(id, show_id = false, resolve = true) |
|
|
|
fmt = '' |
|
|
|
if id < 0 then # its chat |
|
|
|
fmt = (@cache[:chats].key? id) ? "%s" % @cache[:chats][id].title : "%s" % id |
|
|
|
elsif id > 0 then # its user |
|
|
|
self.process_user_info(id) if not @cache[:users].key? id and resolve |
|
|
|
user = @cache[:users][id] if @cache[:users].key? id |
|
|
|
fmt += user.first_name if user and user.first_name != '' |
|
|
|
fmt += " " + user.last_name if user and user.last_name != '' |
|
|
|
fmt += " (@%s)" % user.username if user and user.username != '' |
|
|
|
fmt += " (%s)" % id if (user and user.username == '') or show_id |
|
|
|
else |
|
|
|
fmt = "unknown (%s)" % id |
|
|
|
end |
|
|
|
|
|
|
|
return fmt |
|
|
|
end |
|
|
|
|
|
|
|
# format reply# |
|
|
|
def format_message(chat_id, message_id, full = true) |
|
|
|
text = '' |
|
|
|
@client.get_message(chat_id, message_id).then { |message| text = message.content.text.text }.wait |
|
|
|
return (not full) ? "%s >> %s.." % [message_id, text.split("\n")[0]] : "%s | %s " % [message_id, text] |
|
|
|
def format_contact(chat_id) |
|
|
|
return if not chat_id or chat_id == 0 |
|
|
|
chat, user = self.get_contact(chat_id) |
|
|
|
str = chat_id |
|
|
|
str = "%s (%s)" % [chat.title, chat.id] if chat |
|
|
|
str = "%s %s (%s)" % [user.first_name, user.last_name, (user.username.empty?) ? user.id : user.username] if user |
|
|
|
str = str.gsub(' ', ' ') |
|
|
|
return str |
|
|
|
end |
|
|
|
|
|
|
|
def format_file(file, filename, local = false) |
|
|
|
if local then return "%s/%s%s" % [@@content_path, Digest::SHA256.hexdigest(file.remote.id), File.extname(filename)] end |
|
|
|
return "%s (%d kbytes) | %s/%s%s" % [filename, file.size/1024, @@content_link, Digest::SHA256.hexdigest(file.remote.id), File.extname(filename).to_s] |
|
|
|
def format_content(file, fname) |
|
|
|
str = "%s (%d kbytes) | %s/%s%s" % [fname, file.size/1024, @@config[:content][:link], Digest::SHA256.hexdigest(file.remote.id), File.extname(fname).to_s] |
|
|
|
return str |
|
|
|
end |
|
|
|
|
|
|
|
def format_message(chat_id, message_id, preview=false, message=nil) |
|
|
|
message ||= @telegram.get_message(chat_id, message_id).value |
|
|
|
return unless message |
|
|
|
str = "%s | %s | " % [message.id, self.format_contact(message.sender_user_id)] |
|
|
|
str += DateTime.strptime((message.date+Time.now.getlocal(@session[:timezone]).utc_offset).to_s,'%s').strftime("%d %b %Y %H:%M:%S | ") unless preview |
|
|
|
str += (not preview or message.content.text.text.lines.count <= 1) ? message.content.text.text : message.content.text.text.lines.first |
|
|
|
return str |
|
|
|
end |
|
|
|
|
|
|
|
# state functions # |
|
|
|
def online?() @online end |
|
|
|
def tz_set?() return @timezone != '-00:00' end |
|
|
|
end |