Release v1.2

Added support of Voice Notes
Small fixes in messages formatting
Minor code cleaning
Fixed error on /info command
Added /reconnect command
[-] Removed /history command as it does not work, use /search count as it provides same fuctionality :(
This commit is contained in:
annelin 2019-06-01 01:35:03 +03:00
parent 5997f8632b
commit d4863a50b0
2 changed files with 147 additions and 204 deletions

View file

@ -45,14 +45,14 @@ class TelegramClient
return if @client and @client.ready? return if @client and @client.ready?
@logger.info 'Connecting to Telegram network..' @logger.info 'Connecting to Telegram network..'
@client = TD::Client.new(database_directory: 'sessions/' + @jid, files_directory: 'sessions/' + @jid + '/files/') # create telegram client instance @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::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::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::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::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::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::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::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.on(TD::Types::Update::UserStatus) do |update| self.status_update_handler(update) end # register status handler
@client.connect() @client.connect()
end end
@ -124,7 +124,8 @@ class TelegramClient
# file handling # file handling
file = case content file = case content
when TD::Types::MessageContent::Sticker then [content.sticker.sticker, content.sticker.emoji + '.webp'] when TD::Types::MessageContent::Sticker then [content.sticker.sticker, content.sticker.emoji + '.webp']
when TD::Types::MessageContent::VoiceNote then [content.voice_note.voice, 'voice message %i s.' % content.voice_note.duration + '.oga'] when TD::Types::MessageContent::VoiceNote then [content.voice_note.voice, 'voice message (%i seconds).oga' % content.voice_note.duration]
when TD::Types::MessageContent::VideoNote then [content.video_note.video, 'video message (%i seconds).mp4' % content.video_note.duration]
when TD::Types::MessageContent::Animation then [content.animation.animation, content.animation.file_name + '.mp4' ] when TD::Types::MessageContent::Animation then [content.animation.animation, content.animation.file_name + '.mp4' ]
when TD::Types::MessageContent::Photo then [content.photo.sizes[-1].photo, content.photo.id + '.jpg'] 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::Audio then [content.audio.audio, content.audio.file_name]
@ -136,13 +137,15 @@ class TelegramClient
text = case content text = case content
when TD::Types::MessageContent::BasicGroupChatCreate, TD::Types::MessageContent::SupergroupChatCreate then "has created chat" 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::ChatJoinByLink then "joined chat via invite link"
when TD::Types::MessageContent::ChatAddMembers then "invited %s" % self.format_username(message.content.member_user_ids.first) 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_username(update.message.content.user_id) 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::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.to_s
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::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::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::Text then content.text.text
when TD::Types::MessageContent::VoiceNote then content.caption.text
when TD::Types::MessageContent::VideoNote then ''
else "unknown message type %s" % update.message.content.class else "unknown message type %s" % update.message.content.class
end end
@ -152,17 +155,18 @@ class TelegramClient
# forwards, replies and message id.. # 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 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
prefix << (update.message.is_outgoing ? '➡ ' : '⬅ ') + update.message.id.to_s # message direction prefix << (update.message.is_outgoing ? '➡ ' : '⬅ ') + update.message.id.to_s # message direction
prefix << "fwd: %s" % self.format_username(update.message.forward_info.sender_user_id) if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd from user prefix << "%s" % self.format_contact(update.message.sender_user_id) if update.message.chat_id < 0 # show sender in group chats
prefix << "fwd: %s" % self.format_chatname(update.message.forward_info.chat_id) if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedPost # fwd from chat 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 << "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 << "file: %s" % self.format_file(file[0], file[1]) if file
prefix << "user: %s" % self.format_username(update.message.sender_user_id) if update.message.chat_id < 0 # show sender in group chats prefix = prefix.join(' | ')
prefix += (update.message.chat_id < 0 and text and text != "") ? "\n" : '' # \n if it is groupchat and message is not empty
text = (prefix << text).join(' | ') prefix += (update.message.chat_id > 0 and text and text != "") ? " | " : ''
# read message & send it to xmpp # read message & send it to xmpp
@client.view_messages(update.message.chat_id, [update.message.id], force_read: true) @client.view_messages(update.message.chat_id, [update.message.id], force_read: true)
@xmpp.message(@jid, update.message.chat_id.to_s, text) @xmpp.message(@jid, update.message.chat_id.to_s, prefix + text)
end end
# new chat update -- when tg client discovers new chat # # new chat update -- when tg client discovers new chat #
@ -232,139 +236,94 @@ class TelegramClient
# /command # # /command #
def process_command(chat_id, text) def process_command(chat_id, text)
splitted = text.split # splitted[0] = command, splitted[1] = argument arg = text[0..2] == '/s/' ? ['/sed', text[3..-1]] : text.split
splitted = ['/sed', text[3..-1]] if text[0..2] == '/s/' # sed-like edit
resolved = nil; response = nil
# if second argument starts with @, try to resolve it # ..
@client.search_public_chat(splitted[1][1..-1]).then {|chat| resolved = chat}.wait if splitted[1] and splitted[1][0] == '@' 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
case splitted[0] # command...
when '/info' # information about user / chat response = nil
response = '' current = @cache[:chats][chat_id] # current chat
id = (resolved) ? resolved.id : splitted[1] resolve = resolve || nil # resolved chat or nil
id ||= chat_id chat = resolve || current # resolved chat or current
id = id.to_i case arg[0]
self.process_user_info(id) if id and id > 0 and not @cache[:users].key? id when '/info' then response = self.format_contact(chat.id) # print information
self.process_chat_info(id, false) if id and id < 0 and not @cache[:cache].key? id when '/add' then (chat.id > 0) ? self.process_chat_info(chat.id, true) : @client.join_chat(chat.id).wait # add contact
response = self.format_chatname(id) if @cache[:chats].key? id when '/join' then @client.join_chat_by_invite_link(arg[1]).wait if arg[1][0..3] == 'http' # join chat by link
response = self.format_username(id, true) if @cache[:users].key? id when '/secret' then @client.create_new_secret_chat(chat.id).wait if chat.id > 0 # new secret chat
when '/add' # open new private chat by its id when '/group' then @client.create_new_basic_group_chat(resolve.id, arg[2]).it if resolve and arg[2]
chat = (resolved) ? resolved.id : splitted[1].to_i when '/supergroup' then @client.create_new_supergroup_chat(arg[1], arg[2]).wait if arg[2]
self.process_chat_info(chat) if chat != 0 when '/channel' then @client.create_new_supergroup_chat(arg[1], arg[2], is_channel: true).wait if arg[2]
when '/join' # join group/supergroup by invite link or by id when '/invite' then @client.add_chat_member(current.id, resolve.id).wait if resolve
chat = (resolved) ? resolved.id : splitted[1] when '/kick' then @client.set_chat_member_status(current, resolve.id, TD::Types::ChatMemberStatus::Left.new()).wait if resolve
chat ||= chat_id 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
chat.to_s[0..3] == "http" ? @client.join_chat_by_invite_link(chat).wait : @client.join_chat(chat.to_i).wait when '/block' then @client.block_user(current.id).wait
when '/secret' # create new secret chat when '/unblock' then @client.unblock_user(current.id).wait
uid = (resolved) ? resolved.id : chat_id when '/members' then members = []
@client.create_new_secret_chat(uid) if uid > 0 response = "- Members of chat %s -\n\n" % current.title
when '/group' # create new group with @user_id @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.create_new_basic_group_chat([resolved.id], splitted[2]) if resolved and splitted[2] @client.get_supergroup_members(current.type.supergroup_id).then{|m| members+=m.members }.wait if current.type.instance_of? TD::Types::ChatType::Supergroup # super
when '/supergroup' # create new supergroup members.each do |user| response += "%s | Role: %s \n" % [self.format_contact(user.user_id, true, false), user.status.class] end
@client.create_new_supergroup_chat(splitted[1], splitted[2]) if splitted[2] when '/leave','/delete' then @client.close_chat(current.id).wait
when '/channel' # create new channel @client.leave_chat(current.id) if current.type.instance_of? TD::Types::ChatType::BasicGroup or current.type.instance_of? TD::Types::ChatType::Supergroup
@client.create_new_supergroup_chat(splitted[1], splitted[2], is_channel: true) if splitted[2] @client.close_secret_chat(current.type.secret_chat_id).wait if current.type.instance_of? TD::Types::ChatType::Secret
when '/members' # view members of a group @client.delete_chat_history(current.id, true).wait
response = "- Members of chat %s -\n\n" % @cache[:chats][chat_id].title @xmpp.presence(@jid, current.id.to_s, :unsubscribed)
# supergroup @xmpp.presence(@jid, current.id.to_s, :unavailable)
if @cache[:chats][chat_id].type.instance_of? TD::Types::ChatType::Supergroup then @cache[:chats].delete(current.id) if @cache[:chats].key? current.id
@client.get_supergroup_members(@cache[:chats][chat_id].type.supergroup_id, TD::Types::SupergroupMembersFilter::Recent.new(), 0, 200).then { |members| members.members.each do |member| @cache[:users].delete(current.id) if @cache[:users].key? current.id
self.process_user_info(member.user_id) if not @cache[:users].key? member.user_id # fetch userdata if noinfo when '/sed' then id, edited = nil, nil
response += (@cache[:users].key? member.user_id) ? self.format_username(member.user_id, true) : "ID %s" % member.user_id sed = arg[1].split('/')
response += " | %s\n" % member.status.class.to_s @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
end }.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
# normal group when '/d' then id = arg[1].to_i
elsif @cache[:chats][chat_id].type.instance_of? TD::Types::ChatType::BasicGroup then @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
@cache[:chats][chat_id].last_message.content.member_user_ids.each do |member| response += (@cache[:users].key? member) ? self.format_username(member, true) : "ID %s" % member; response += "\n" end @client.delete_messages(current.id, [id], true)
end when '/search' then count = arg[1] || 10
when '/invite' # invite user to chat query = arg[2] || nil
@client.add_chat_member(chat_id, resolved.id).wait if resolved @client.search_chat_messages(current.id, 0, count, query: query, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs|
when '/kick' # removes user from chat msgs.messages.reverse.each do |msg| self.message_handler(TD::Types::Update::NewMessage.new(message: msg, disable_notification: false, contains_mention: false), true) end
@client.set_chat_member_status(chat_id, resolved.id, TD::Types::ChatMemberStatus::Left.new()).wait if resolved }.wait
when '/ban' # removes user from chat. argument = hours to ban. when '/setusername' then @client.set_username(arg[1] || '')
until_date = (splitted[1]) ? Time.now.getutc.to_i + splitted[1].to_i * 3600 : 0 when '/setname' then @client.set_name(arg[1] || '', arg[2] || '')
@client.set_chat_member_status(chat_id, resolved.id, TD::Types::ChatMemberStatus::Banned.new(banned_until_date: until_date)).wait if resolved when '/setbio' then @client.set_bio(arg[1..99].join(' '))
when '/block' # add user to blacklist when '/setpassword' then old_password, new_password = arg[1], arg[2]
@client.block_user(chat_id) old_password = '' if old_password == 'nil'
when '/unblock' # add user to blacklist new_password = nil if new_password == 'nil'
@client.unblock_user(chat_id) @client.set_password(old_password, new_password: new_password)
when '/leave', '/delete' # delete / leave chat when '/dump' then response = current.to_json
@client.close_chat(chat_id).wait else response = 'Unknown command.
@client.leave_chat(chat_id).wait
@client.close_secret_chat(@cache[:chats][chat_id].type.secret_chat_id).wait if @cache[:chats][chat_id].type.instance_of? TD::Types::ChatType::Secret
@client.delete_chat_history(chat_id, true).wait
@xmpp.presence(@jid, chat_id, :unsubscribed)
@xmpp.presence(@jid, chat_id, :unavailable)
@cache[:chats].delete(chat_id)
when '/sed' # sed-like edit
sed = splitted[1].split('/')
@client.search_chat_messages(chat_id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs|
original = msgs.messages[0].content.text.text.to_s
edited = (sed[0] != '' ) ? original.gsub(Regexp.new(sed[0]), sed[1]) : sed[1]
@client.edit_message_text(chat_id, msgs.messages[0].id, TD::Types::InputMessageContent::Text.new(:text => { :text => edited, :entities => []}, :disable_web_page_preview => false, :clear_draft => true )) if edited != original
}.wait
when '/d' # delete last message
id = splitted[1].to_i
@client.search_chat_messages(chat_id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs| id = msgs.messages[0].id }.wait if not id or id == 0
@client.delete_messages(chat_id, [id], true)
when '/dump'
response = @cache[:chats][chat_id].to_json
when '/search'
count = (splitted[1]) ? splitted[1].to_i : 10
query = (splitted[2]) ? splitted[2] : nil
@client.search_chat_messages(chat_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 '/history'
count = (splitted[1]) ? splitted[1].to_i : 10
@client.get_chat_history(chat_id, 0, 0, count).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'
@client.set_username(splitted[1]) if splitted[1]
when '/setname'
@client.set_name(splitted[1], splitted[2]) if splitted[1]
when '/setbio'
@client.set_bio(splitted[1]) if splitted[1]
when '/setpassword'
old_password = splitted[1]
new_password = splitted[2]
old_password = '' if old_password == 'nil'
new_password = nil if new_password == 'nil'
@client.set_password(old_password, new_password: new_password)
else
response = 'Unknown command.
/s/mitsake/mistake/ Edit last message /s/mitsake/mistake/ Edit last message
/d — Delete last message /d — Delete last message
/info id — Information about user/chat by its id /info id — Information about user/chat by its id
/add @username or id — Create conversation with specified user or chat 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 /join chat_link or id — Join chat by its link or id
/secret @username — Create "secret chat" with specified user /secret @username — Create "secret chat" with specified user
/group @username groupname — Create group chat named groupname with @username /group @username groupname — Create group chat named groupname with @username
/supergroup name description — Create supergroup chat /supergroup name description — Create supergroup chat
/channel name description — Create channel /channel name description — Create channel
/members — Supergroup members /members — Supergroup members
/history count — Retrieve chat history /search count query — Search in chat history
/search count query — Search in chat history
/invite @username — Invite @username to current chat /invite @username — Invite @username to current chat
/kick @username — Remove @username from 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 /ban @username [hours] — Ban @username in current chat for [hours] hrs or forever if [hours] not specified
/block — Blacklistscurrent user /block — Blacklistscurrent user
/unblock — Remove current user from blacklist /unblock — Remove current user from blacklist
/delete — Delete current chat /delete — Delete current chat
/leave — Leave current chat /leave — Leave current chat
/setusername username — Set username /setusername username — Set username
/setname First Last — Set name /setname First Last — Set name
/setbio Bio — Set bio /setbio Bio — Set bio
/setpassword old new — Set 2FA password (use "nil" for no password") /setpassword old new — Set 2FA password (use "nil" for no password")
' '
end end
@xmpp.message(@jid, chat_id.to_s, response) if response @xmpp.message(@jid, chat_id.to_s, response) if response
@ -379,21 +338,17 @@ class TelegramClient
return self.process_command(chat_id, text) if text[0] == '/' return self.process_command(chat_id, text) if text[0] == '/'
# handling replies # # handling replies #
reply_to = 0
if text[0] == '>' then if text[0] == '>' then
splitted = text.split("\n") text = text.split("\n")
reply_to = splitted[0].scan(/\d/).join('').to_i reply_to = text[0].scan(/\d/).to_i
reply_to = 0 if reply_to < 10000 # o_O reply_to = 0 if reply_to < 10000
text = splitted.drop(1).join("\n") if reply_to != 0 text = splitted.drop(1).join("\n") if reply_to != 0
else
reply_to = 0
end end
# handling files received from xmpp # # handling files received from xmpp #
if text.start_with? @@content_upload_prefix then 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 => []}) message = TD::Types::InputMessageContent::Document.new(document: TD::Types::InputFile::Remote.new(id: text), caption: { :text => '', :entities => []}) if text.start_with? @@content_upload_prefix
else
message = TD::Types::InputMessageContent::Text.new(:text => { :text => text, :entities => []}, :disable_web_page_preview => false, :clear_draft => true )
end
# send message and mark chat as read # # send message and mark chat as read #
@client.send_message(chat_id, message, reply_to_message_id: reply_to) @client.send_message(chat_id, message, reply_to_message_id: reply_to)
@ -408,6 +363,7 @@ class TelegramClient
@xmpp.presence(@jid, chat_id.to_s, :subscribe, nil, nil, chat.title.to_s) if subscription # send subscription request @xmpp.presence(@jid, chat_id.to_s, :subscribe, nil, nil, chat.title.to_s) if subscription # send subscription request
self.process_status_update(chat_id, chat.title.to_s, true) if chat.id < 0 # groups presence self.process_status_update(chat_id, chat.title.to_s, true) if chat.id < 0 # groups presence
}.wait }.wait
return @cache[:chats][chat_id] if @cache[:chats].key? chat_id
end end
# update user info in cache and sync status to roster if needed # # update user info in cache and sync status to roster if needed #
@ -418,6 +374,7 @@ class TelegramClient
@client.get_user_full_info(user_id).then{ |bio| @cache[:chats][user_id].attributes[:client_data] = bio.bio }.wait @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 self.process_status_update(user_id, user.status, true) # status update
}.wait }.wait
return @cache[:users][user_id] if @cache[:users].key? user_id
end end
# convert telegram status to XMPP one # convert telegram status to XMPP one
@ -425,29 +382,18 @@ class TelegramClient
@logger.debug "Processing status update for user id %s.." % user_id.to_s @logger.debug "Processing status update for user id %s.." % user_id.to_s
xmpp_show, xmpp_status, xmpp_photo = nil xmpp_show, xmpp_status, xmpp_photo = nil
case status case status
when TD::Types::UserStatus::Online when TD::Types::UserStatus::Online then xmpp_show, xmpp_status = nil, "Online"
xmpp_show = nil 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")
xmpp_status = "Online" when TD::Types::UserStatus::Recently then xmpp_show, xmpp_status = :dnd, "Last seen recently"
when TD::Types::UserStatus::Offline when TD::Types::UserStatus::LastWeek then xmpp_show, xmpp_status = :unavailable, "Last seen last week"
xmpp_show = (Time.now.getutc.to_i - status.was_online.to_i < 3600) ? :away : :xa when TD::Types::UserStatus::LastMonth then xmpp_show, xmpp_status = :unavailable, "Last seen last month"
xmpp_status = DateTime.strptime((status.was_online+Time.now.getlocal(@timezone).utc_offset).to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y") else xmpp_show, xmpp_status = :chat, status
when TD::Types::UserStatus::Recently
xmpp_show = :dnd
xmpp_status = "Last seen recently"
when TD::Types::UserStatus::LastWeek
xmpp_show = :unavailable
xmpp_status = "Last seen last week"
when TD::Types::UserStatus::LastMonth
xmpp_show = :unavailable
xmpp_status = "Last seen last month"
else
xmpp_show = :chat
xmpp_status = status
end end
xmpp_photo = self.format_file(@cache[:photos][user_id], 'image.jpg', true) if @cache[:photos].include? user_id 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) ? Base64.encode64(IO.binread(xmpp_photo)) : nil xmpp_photo = (File.exist? xmpp_photo.to_s) ? Base64.encode64(IO.binread(xmpp_photo)) : nil
@xmpp.presence(@jid, user_id.to_s, nil, xmpp_show, xmpp_status, nil, xmpp_photo, immed) # ...
return @xmpp.presence(@jid, user_id.to_s, nil, xmpp_show, xmpp_status, nil, xmpp_photo, immed)
end end
# get contact information (for vcard). # get contact information (for vcard).
@ -474,47 +420,39 @@ class TelegramClient
# resolve id by @username (or just return id) # resolve id by @username (or just return id)
def resolve_username(username) def resolve_username(username)
resolved = nil resolved = username
if username[0] == '@' then # @username if username[0] == '@' then @client.search_public_chat(username[1..-1]).then {|chat| resolved = '@' + chat.id.to_s}.wait end
@client.search_public_chat(username[1..-1]).then {|chat| resolved = '@' + chat.id.to_s}.wait if username[0..3] == 'http' or username[0..3] == 't.me' then @client.join_chat_by_invite_link(username) end
elsif username[0..3] == 'http' or username[0..3] == 't.me' then # chat link return resolved
@client.join_chat_by_invite_link(username)
elsif username.to_i != 0 then # user id
resolved = username
end
return resolved || ''
end end
########################################### ###########################################
## Format functions ####################### ## Format functions #######################
########################################### ###########################################
# format tg user name # # format tg user name #
def format_username(user_id, show_id = false) def format_contact(id, show_id = false, resolve = true)
return if user_id == 0 # @me fmt = ''
if not @cache[:users].key? user_id then self.process_user_info(user_id) end # update cache if id < 0 then # its chat
if not @cache[:users].key? user_id then return user_id end # return id if not found anything about this user fmt = (@cache[:chats].key? id) ? "%s" % @cache[:chats][id].title : "%s" % id
id = (@cache[:users][user_id].username == '') ? user_id : @cache[:users][user_id].username # username or user id elsif id > 0 then # its user
name = @cache[:users][user_id].first_name # firstname self.process_user_info(id) if not @cache[:users].key? id and resolve
name = name + ' ' + @cache[:users][user_id].last_name if @cache[:users][user_id].last_name != '' # lastname user = @cache[:users][id] if @cache[:users].key? id
id = "%s ID %s" % [id, user_id] if show_id fmt += user.first_name if user and user.first_name != ''
return "%s (@%s)" % [name, id] fmt += " " + user.last_name if user and user.last_name != ''
end 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
# format tg chat name # return fmt
def format_chatname(chat_id)
if not @cache[:chats].key? chat_id then self.process_chat_info(chat_id, false) end
if not @cache[:chats].key? chat_id then return chat_id end
name = '%s (%s)' % [@cache[:chats][chat_id].title, chat_id]
return name
end end
# format reply# # format reply#
def format_message(chat_id, message_id, full = true) def format_message(chat_id, message_id, full = true)
text = '' text = ''
@client.get_message(chat_id, message_id).then { |message| text = message.content.text.text }.wait @client.get_message(chat_id, message_id).then { |message| text = message.content.text.text }.wait
text = (text.lines.count > 1 and not full) ? "%s.." % text.split("\n")[0] : text return (not full) ? "%s >> %s.." % [message_id, text.split("\n")[0]] : "%s | %s " % [message_id, text]
return "msg %s [%s]" % [message_id.to_s, text]
end end
def format_file(file, filename, local = false) def format_file(file, filename, local = false)

View file

@ -7,6 +7,7 @@
/password secret — Enter 2FA password /password secret — Enter 2FA password
/connect ­— Connect to Telegram network if have active session /connect ­— Connect to Telegram network if have active session
/disconnect ­— Disconnect from Telegram network /disconnect ­— Disconnect from Telegram network
/reconnect ­— Reconnect to Telegram network
/logout — Disconnect from Telegram network and forget session /logout — Disconnect from Telegram network and forget session
/info — Show information and usage statistics of this instance (only for JIDs specified as administrators) /info — Show information and usage statistics of this instance (only for JIDs specified as administrators)
@ -232,6 +233,10 @@ class XMPPComponent
@sessions[from.bare.to_s].connect() if @sessions.key? from.bare.to_s @sessions[from.bare.to_s].connect() if @sessions.key? from.bare.to_s
when '/disconnect' # go offline (without destroying a session) when '/disconnect' # go offline (without destroying a session)
@sessions[from.bare.to_s].disconnect() if @sessions.key? from.bare.to_s @sessions[from.bare.to_s].disconnect() if @sessions.key? from.bare.to_s
when '/reconnect' # reconnect
@sessions[from.bare.to_s].disconnect() if @sessions.key? from.bare.to_s
sleep(0.1)
@sessions[from.bare.to_s].connect() if @sessions.key? from.bare.to_s
when '/logout' # go offline and destroy session when '/logout' # go offline and destroy session
@sessions[from.bare.to_s].disconnect(true) if @sessions.key? from.bare.to_s @sessions[from.bare.to_s].disconnect(true) if @sessions.key? from.bare.to_s
self.update_db(from.bare.to_s, true) self.update_db(from.bare.to_s, true)
@ -242,7 +247,7 @@ class XMPPComponent
response += "Running from: %s\n" % `ps -p #{$$} -o lstart`.lines.last.strip response += "Running from: %s\n" % `ps -p #{$$} -o lstart`.lines.last.strip
response += "System memory used: %d KB\n" % `ps -o rss -p #{$$}`.lines.last.strip.to_i response += "System memory used: %d KB\n" % `ps -o rss -p #{$$}`.lines.last.strip.to_i
response += "\n\nSessions: %d online | %d total \n" % [ @sessions.inject(0){ |cnt, (jid, sess)| cnt = (sess.online?) ? cnt + 1 : cnt }, @sessions.count] response += "\n\nSessions: %d online | %d total \n" % [ @sessions.inject(0){ |cnt, (jid, sess)| cnt = (sess.online?) ? cnt + 1 : cnt }, @sessions.count]
@sessions.each do |jid, session| response += "JID: %s | Login: %s | Status: %s (%s) | %s\n" % [jid, session.login, (session.online == true) ? 'Online' : 'Offline', session.auth_state, (session.me) ? session.format_username(session.me.id) : 'Unknown' ] end @sessions.each do |jid, session| response += "JID: %s | Login: %s | Status: %s (%s) | %s\n" % [jid, session.login, (session.online == true) ? 'Online' : 'Offline', session.auth_state, (session.me) ? session.format_contact(session.me.id) : 'Unknown' ] end
self.message(from.bare, nil, response) self.message(from.bare, nil, response)
when '/restart' # reset transport when '/restart' # reset transport
return if not @config[:admins].include? from.bare.to_s return if not @config[:admins].include? from.bare.to_s