From a799c1244b234de9610c6f98859dfa126798ba45 Mon Sep 17 00:00:00 2001 From: annelin Date: Sun, 14 Apr 2019 05:56:29 +0300 Subject: [PATCH] Release 0.5 [NEW] Now using local Jabber timezone --- inc/telegramclient.rb | 55 +++++++++++++++++++++++++--------- inc/xmppcomponent.rb | 68 +++++++++++++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 33 deletions(-) diff --git a/inc/telegramclient.rb b/inc/telegramclient.rb index 46513af..6377389 100644 --- a/inc/telegramclient.rb +++ b/inc/telegramclient.rb @@ -145,11 +145,11 @@ class TelegramClient @client.download_file(file.id) if file # download it if already not # forwards, replies and message id.. - text = "[Forward from %s] %s" % [self.format_username(update.message.forward_info.sender_user_id), text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd from user - text = "[Forward from channel %s (%s)] %s" % [update.message.forward_info.chat_id.to_s, update.message.forward_info.author_signature.to_s, text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedPost # fwd from chat - text = "[Reply to MSG %s] %s" % [update.message.reply_to_message_id.to_s, text] if update.message.reply_to_message_id.to_i != 0 # reply - text = "[MSG %s] [%s] %s" % [update.message.id.to_s, self.format_username(update.message.sender_user_id), text] # username/id - + text = "| fwd %s | %s" % [self.format_username(update.message.forward_info.sender_user_id), text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd from user + text = "| fwd %s(%s) | %s" % [self.format_chatname(update.message.forward_info.chat_id), update.message.forward_info.author_signature.to_s, text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedPost # fwd from chat + text = "| reply %s | %s" % [self.format_reply(update.message.chat_id, update.message.reply_to_message_id), text] if update.message.reply_to_message_id.to_i != 0 # reply + text = "%s | %s | %s" % [update.message.id.to_s, self.format_username(update.message.sender_user_id), text] # username/id + # send and add message id to unreads @cache[:unread_msg][update.message.chat_id] = update.message.id @xmpp.incoming_message(update.message.chat_id.to_s, text) @@ -184,7 +184,7 @@ class TelegramClient @logger.debug 'Got MessageDeleted update' @logger.debug update.to_json return if not update.is_permanent - text = "[MSG ID %s DELETE]" % update.message_ids.join(',') + text = "[MSG %s DELETE]" % update.message_ids.join(',') @xmpp.incoming_message(update.chat_id.to_s, text) end @@ -265,6 +265,8 @@ class TelegramClient @client.search_chat_messages(chat_id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs| @client.delete_messages(chat_id, [msgs.messages[0].id], true) }.wait + when '/dump' + response = @cache[:chats][chat_id].to_json else response = 'Unknown command. @@ -315,15 +317,15 @@ class TelegramClient end # update users information and save it to cache # - def process_chat_info(chat_id) + def process_chat_info(chat_id, no_subscription = false) @logger.debug 'Updating chat id %s..' % chat_id.to_s # fullfil cache.. pasha durov, privet. # @client.get_chat(chat_id).then { |chat| @cache[:chats][chat_id] = chat # cache chat @client.download_file(chat.photo.small.id) if chat.photo # download userpic - @xmpp.presence(chat_id.to_s, :subscribe, nil, nil, @cache[:chats][chat_id].title.to_s) # send subscription request - @xmpp.presence(chat_id.to_s, nil, :chat, nil, @cache[:chats][chat_id].title.to_s) if chat.type.instance_of? TD::Types::ChatType::BasicGroup or chat.type.instance_of? TD::Types::ChatType::Supergroup # send :chat status if its group/supergroup + @xmpp.presence(chat_id.to_s, :subscribe, nil, nil, @cache[:chats][chat_id].title.to_s) if not no_subscription # send subscription request + @xmpp.presence(chat_id.to_s, nil, :chat, @cache[:chats][chat_id].title.to_s) if chat.type.instance_of? TD::Types::ChatType::BasicGroup or chat.type.instance_of? TD::Types::ChatType::Supergroup # send :chat status if its group/supergroup self.process_user_info(chat.type.user_id) if chat.type.instance_of? TD::Types::ChatType::Private # process user if its a private chat }.wait end @@ -350,7 +352,7 @@ class TelegramClient xmpp_status = "Online" when TD::Types::UserStatus::Offline xmpp_show = (Time.now.getutc.to_i - status.was_online.to_i < 3600) ? :away : :xa - xmpp_status = DateTime.strptime(status.was_online.to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y") + xmpp_status = DateTime.strptime((status.was_online+Time.now.getlocal(@xmpp.timezone).utc_offset).to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y") when TD::Types::UserStatus::Recently xmpp_show = :dnd xmpp_status = "Last seen recently" @@ -390,6 +392,12 @@ class TelegramClient return title, username, firstname, lastname, phone, bio, userpic end + # roster status sync # + def sync_status() + @logger.debug "Syncing statuses.." + @cache[:users].each_value do |user| process_status_update(user.id, user.status) end + end + # graceful disconnect def disconnect(logout) @logger.info 'Disconnect request received..' @@ -404,12 +412,30 @@ class TelegramClient # format tg user name # def format_username(user_id) - if not @cache[:users].key? user_id then self.process_user_info(user_id) end - id = (@cache[:users][user_id].username == '') ? user_id : @cache[:users][user_id].username - name = '%s %s (@%s)' % [@cache[:users][user_id].first_name, @cache[:users][user_id].last_name, id] - name.sub! ' ]', ']' + user_id = @me.id if user_id == 0 # @me + if not @cache[:users].key? user_id then self.process_user_info(user_id) end # update cache + if not @cache[:users].key? user_id then return user_id end # return id if not found anything about this user + id = (@cache[:users][user_id].username == '') ? user_id : @cache[:users][user_id].username # username or user id + name = @cache[:users][user_id].first_name # firstname + name = name + ' ' + @cache[:users][user_id].last_name if @cache[:users][user_id].last_name != '' # lastname + return "%s (@%s)" % [name, id] + end + + # format tg chat name # + def format_chatname(chat_id) + if not @cache[:chats].key? chat_id then self.process_chat_info(chat_id, true) 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 + + # format reply# + def format_reply(chat_id, message_id) + text = '' + @client.get_message(chat_id, message_id).then { |message| text = "%s" % message.content.text.text.to_s }.wait + text = (text.lines.count > 1) ? "%s..." % text.split("\n")[0] : text + return "MSG %s (%s..)" % [message_id.to_s, text] + end # format content link # def format_content_link(file_id, fname, local = false) @@ -417,4 +443,5 @@ class TelegramClient path = "%s/%s%s" % [prefix, Digest::SHA256.hexdigest(file_id), File.extname(fname)] return path end + end diff --git a/inc/xmppcomponent.rb b/inc/xmppcomponent.rb index 838ab9d..789ca8f 100644 --- a/inc/xmppcomponent.rb +++ b/inc/xmppcomponent.rb @@ -88,8 +88,8 @@ class XMPPComponent # new message to XMPP component # def message_handler(msg) @logger.info 'New message from [%s] to [%s]' % [msg.from, msg.to] - return self.process_internal_command(msg.from.bare.to_s, msg.first_element_text('body') ) if msg.to == @@transport.jid # treat message as internal command if received as transport jid - return @sessions[msg.from.bare.to_s].tg_outgoing(msg.to.to_s, msg.first_element_text('body')) #if @sessions.key? msg.from.bare.to_s and @sessions[msg.from.bare.to_s].online? # queue message for processing session is active for jid from + return self.process_internal_command(msg.from, msg.first_element_text('body') ) if msg.to == @@transport.jid # treat message as internal command if received as transport jid + return @sessions[msg.from.bare.to_s].tg_outgoing(msg.from, msg.to.to_s, msg.first_element_text('body')) #if @sessions.key? msg.from.bare.to_s and @sessions[msg.from.bare.to_s].online? # queue message for processing session is active for jid from end def presence_handler(presence) @@ -97,20 +97,27 @@ class XMPPComponent @logger.debug(presence) if presence.type == :subscribe then reply = presence.answer(false); reply.type = :subscribed; @@transport.send(reply); end # send "subscribed" reply to "subscribe" presence if presence.to == @@transport.jid and @sessions.key? presence.from.bare.to_s and presence.type == :unavailable then @sessions[presence.from.bare.to_s].disconnect(); return; end # go offline when received offline presence from jabber user - if presence.to == @@transport.jid and @sessions.key? presence.from.bare.to_s then @sessions[presence.from.bare.to_s].connect(); return; end # connect if we have session + if presence.to == @@transport.jid and @sessions.key? presence.from.bare.to_s then @sessions[presence.from.bare.to_s].request_tz(presence.from); @sessions[presence.from.bare.to_s].connect(); return; end # connect if we have session end def iq_handler(iq) @logger.debug "New iq received" @logger.debug(iq.to_s) - if iq.vcard and @sessions.key? iq.from.bare.to_s then + # vcard request # + if iq.type == :get and iq.vcard and @sessions.key? iq.from.bare.to_s then + @logger.debug "Got VCard request" vcard = @sessions[iq.from.bare.to_s].make_vcard(iq.to.to_s) reply = iq.answer reply.type = :result reply.elements["vCard"] = vcard - @@transport.send(reply) - else + @@transport.send(reply) + # time response # + elsif iq.type == :result and iq.elements["time"] and @sessions.key? iq.from.bare.to_s then + @logger.debug "Got Timezone response" + timezone = iq.elements["time"].elements["tzo"].text + @sessions[iq.from.bare.to_s].set_tz(timezone) + elsif iq.type == :get then reply = iq.answer reply.type = :error end @@ -122,26 +129,27 @@ class XMPPComponent ############################# # process internal /command # - def process_internal_command(jfrom, body) + def process_internal_command(from, body) case body.split[0] # /command argument = [command, argument] when '/login' # creating new session if not exists and connect if user already has session - @sessions[jfrom] = XMPPSession.new(jfrom, body.split[1]) if not @sessions.key? jfrom - @sessions[jfrom].connect() - self.update_db(jfrom) + @sessions[from.bare.to_s] = XMPPSession.new(from.bare.to_s, body.split[1]) if not @sessions.key? from.bare.to_s + @sessions[from.bare.to_s].request_tz(from) + @sessions[from.bare.to_s].connect() + self.update_db(from.bare.to_s) when '/code', '/password' # pass auth data if we have session - @sessions[jfrom].tg_auth(body.split[0], body.split[1]) if @sessions.key? jfrom + @sessions[from.bare.to_s].tg_auth(body.split[0], body.split[1]) if @sessions.key? from.bare.to_s when '/connect' # going online - @sessions[jfrom].connect() if @sessions.key? jfrom + @sessions[from.bare.to_s].connect() if @sessions.key? from.bare.to_s when '/disconnect' # going offline without destroying a session - @sessions[jfrom].disconnect() if @sessions.key? jfrom + @sessions[from.bare.to_s].disconnect() if @sessions.key? from.bare.to_s when '/logout' # destroying session - @sessions[jfrom].disconnect(true) if @sessions.key? jfrom - self.update_db(jfrom, true) - @sessions.delete(jfrom) + @sessions[from.bare.to_s].disconnect(true) if @sessions.key? from.bare.to_s + self.update_db(from.bare.to_s, true) + @sessions.delete(from.bare.to_s) else # unknown command -- display help # msg = Jabber::Message.new msg.from = @@transport.jid - msg.to = jfrom + msg.to = from.bare.to_s msg.body = ::HELP_MESSAGE msg.type = :chat @@transport.send(msg) @@ -154,7 +162,7 @@ end ## XMPP Session Class ####### ############################# class XMPPSession < XMPPComponent - attr_reader :user_jid, :tg_login + attr_reader :user_jid, :tg_login, :timezone attr_accessor :online # start XMPP user session and Telegram client instance # @@ -162,6 +170,7 @@ class XMPPSession < XMPPComponent @logger = Logger.new(STDOUT); @logger.level = @@loglevel; @logger.progname = '[XMPPSession: %s/%s]' % [jid, tg_login] # init logger @logger.info "Initializing new session.." @user_jid, @tg_login = jid, tg_login + @timezone = '-00:00' end # connect to tg # @@ -210,8 +219,9 @@ class XMPPSession < XMPPComponent ########################################### # queue message (we will share this queue within :message_queue to Telegram client thread) # - def tg_outgoing(to, text = '') + def tg_outgoing(from, to, text = '') @logger.debug "Sending message to be sent to Telegram network user -> " % to + self.request_tz(from) if not self.tz_set? @telegram.process_outgoing_msg(to.split('@')[0].to_i, text) end @@ -245,6 +255,25 @@ class XMPPSession < XMPPComponent return vcard end + ## timezones ## + def request_tz(jid) + @logger.debug "Request timezone from JID %s" % jid.to_s + iq = Jabber::Iq.new + iq.type = :get + iq.to = jid + iq.from = @@transport.jid + iq.id = 'time_req_1' + iq.add_element("time", {"xmlns" => "urn:xmpp:time"}) + @logger.debug iq.to_s + @@transport.send(iq) + end + + def set_tz(timezone) + @logger.debug "Set TZ to %s" % timezone + @timezone = timezone + @logger.debug "Resyncing contact list.." + @telegram.sync_status() + end ########################################### @@ -252,4 +281,5 @@ class XMPPSession < XMPPComponent def online?() @online end def online!() @logger.info "Connection established"; @online = true; self.presence(nil, :subscribe); self.presence(nil, nil, nil, "Logged in as " + @tg_login.to_s) end def offline!() @online = false; self.presence(nil, :unavailable, nil, "Logged out"); @telegram = nil; end + def tz_set?() return @timezone != '-00:00' end end