From 4a5b83dff5c568871d5624202e2ee27e5d0de242 Mon Sep 17 00:00:00 2001
From: Bohdan Horbeshko <bodqhrohro@gmail.com>
Date: Sun, 5 Mar 2023 03:00:53 -0500
Subject: Show XEP-0461 replies from Telegram

---
 telegram/commands.go   |  2 +
 telegram/connect.go    |  8 ++--
 telegram/handlers.go   |  4 +-
 telegram/utils.go      | 99 +++++++++++++++++++++++++++++---------------------
 telegram/utils_test.go | 62 ++++++++++++++++++++++++++++---
 5 files changed, 123 insertions(+), 52 deletions(-)

(limited to 'telegram')

diff --git a/telegram/commands.go b/telegram/commands.go
index 957c335..943d071 100644
--- a/telegram/commands.go
+++ b/telegram/commands.go
@@ -184,6 +184,7 @@ func (c *Client) unsubscribe(chatID int64) error {
 func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message) {
 	for i := len(messages) - 1; i >= 0; i-- {
 		message := messages[i]
+		reply, _ := c.getMessageReply(message)
 
 		gateway.SendMessage(
 			c.jid,
@@ -191,6 +192,7 @@ func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message) {
 			c.formatMessage(0, 0, false, message),
 			strconv.FormatInt(message.Id, 10),
 			c.xmpp,
+			reply,
 		)
 	}
 }
diff --git a/telegram/connect.go b/telegram/connect.go
index b4957b1..2633980 100644
--- a/telegram/connect.go
+++ b/telegram/connect.go
@@ -219,20 +219,20 @@ func (c *Client) interactor() {
 			if c.Session.Login != "" {
 				c.authorizer.PhoneNumber <- c.Session.Login
 			} else {
-				gateway.SendMessage(c.jid, "", "Please, enter your Telegram login via /login 12345", "", c.xmpp)
+				gateway.SendServiceMessage(c.jid, "Please, enter your Telegram login via /login 12345", c.xmpp)
 			}
 		// stage 1: wait for auth code
 		case client.TypeAuthorizationStateWaitCode:
 			log.Warn("Waiting for authorization code...")
-			gateway.SendMessage(c.jid, "", "Please, enter authorization code via /code 12345", "", c.xmpp)
+			gateway.SendServiceMessage(c.jid, "Please, enter authorization code via /code 12345", c.xmpp)
 		// stage 1b: wait for registration
 		case client.TypeAuthorizationStateWaitRegistration:
 			log.Warn("Waiting for full name...")
-			gateway.SendMessage(c.jid, "", "This number is not registered yet! Please, enter your name via /setname John Doe", "", c.xmpp)
+			gateway.SendServiceMessage(c.jid, "This number is not registered yet! Please, enter your name via /setname John Doe", c.xmpp)
 		// stage 2: wait for 2fa
 		case client.TypeAuthorizationStateWaitPassword:
 			log.Warn("Waiting for 2FA password...")
-			gateway.SendMessage(c.jid, "", "Please, enter 2FA passphrase via /password 12345", "", c.xmpp)
+			gateway.SendServiceMessage(c.jid, "Please, enter 2FA passphrase via /password 12345", c.xmpp)
 		}
 	}
 }
diff --git a/telegram/handlers.go b/telegram/handlers.go
index 517fb54..307562a 100644
--- a/telegram/handlers.go
+++ b/telegram/handlers.go
@@ -242,7 +242,7 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
 			textContent.Text.Entities,
 			markupFunction,
 		))
-		gateway.SendMessage(c.jid, strconv.FormatInt(update.ChatId, 10), text, "e" + strconv.FormatInt(update.MessageId, 10), c.xmpp)
+		gateway.SendMessage(c.jid, strconv.FormatInt(update.ChatId, 10), text, "e" + strconv.FormatInt(update.MessageId, 10), c.xmpp, nil)
 	}
 }
 
@@ -256,7 +256,7 @@ func (c *Client) updateDeleteMessages(update *client.UpdateDeleteMessages) {
 			deleteChar = "✗ "
 		}
 		text := deleteChar + strings.Join(int64SliceToStringSlice(update.MessageIds), ",")
-		gateway.SendMessage(c.jid, strconv.FormatInt(update.ChatId, 10), text, "", c.xmpp)
+		gateway.SendTextMessage(c.jid, strconv.FormatInt(update.ChatId, 10), text, c.xmpp)
 	}
 }
 
diff --git a/telegram/utils.go b/telegram/utils.go
index e58f6bf..f06abd7 100644
--- a/telegram/utils.go
+++ b/telegram/utils.go
@@ -261,6 +261,46 @@ func (c *Client) formatContact(chatID int64) string {
 	return str
 }
 
+func (c *Client) getSenderId(message *client.Message) (senderId int64) {
+	if message.SenderId != nil {
+		switch message.SenderId.MessageSenderType() {
+		case client.TypeMessageSenderUser:
+			senderUser, _ := message.SenderId.(*client.MessageSenderUser)
+			senderId = senderUser.UserId
+		case client.TypeMessageSenderChat:
+			senderChat, _ := message.SenderId.(*client.MessageSenderChat)
+			senderId = senderChat.ChatId
+		}
+	}
+
+	return
+}
+
+func (c *Client) formatSender(message *client.Message) string {
+	return c.formatContact(c.getSenderId(message))
+}
+
+func (c *Client) getMessageReply(message *client.Message) (reply *gateway.Reply, replyMsg *client.Message) {
+	if message.ReplyToMessageId != 0 {
+		var err error
+		replyMsg, err = c.client.GetMessage(&client.GetMessageRequest{
+			ChatId:    message.ChatId,
+			MessageId: message.ReplyToMessageId,
+		})
+		if err != nil {
+			log.Errorf("<error fetching message: %s>", err.Error())
+			return
+		}
+
+		reply = &gateway.Reply {
+			Author: fmt.Sprintf("%v@%s", c.getSenderId(replyMsg), gateway.Jid.Full()),
+			Id:     strconv.FormatInt(message.ReplyToMessageId, 10),
+		}
+	}
+
+	return
+}
+
 func (c *Client) formatMessage(chatID int64, messageID int64, preview bool, message *client.Message) string {
 	var err error
 	if message == nil {
@@ -279,18 +319,7 @@ func (c *Client) formatMessage(chatID int64, messageID int64, preview bool, mess
 
 	var str strings.Builder
 	// add messageid and sender
-	var senderId int64
-	if message.SenderId != nil {
-		switch message.SenderId.MessageSenderType() {
-		case client.TypeMessageSenderUser:
-			senderUser, _ := message.SenderId.(*client.MessageSenderUser)
-			senderId = senderUser.UserId
-		case client.TypeMessageSenderChat:
-			senderChat, _ := message.SenderId.(*client.MessageSenderChat)
-			senderId = senderChat.ChatId
-		}
-	}
-	str.WriteString(fmt.Sprintf("%v | %s | ", message.Id, c.formatContact(senderId)))
+	str.WriteString(fmt.Sprintf("%v | %s | ", message.Id, c.formatSender(message)))
 	// add date
 	if !preview {
 		str.WriteString(
@@ -681,7 +710,7 @@ func (c *Client) contentToFile(content client.MessageContent) (*client.File, *cl
 	return nil, nil
 }
 
-func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string) string {
+func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string, replyMsg *client.Message) string {
 	prefix := []string{}
 	// message direction
 	var directionChar string
@@ -700,21 +729,12 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string,
 	}
 	prefix = append(prefix, directionChar+strconv.FormatInt(message.Id, 10))
 	// show sender in group chats
-	if message.ChatId < 0 && message.SenderId != nil {
-		var senderId int64
-		switch message.SenderId.MessageSenderType() {
-		case client.TypeMessageSenderUser:
-			senderUser, _ := message.SenderId.(*client.MessageSenderUser)
-			senderId = senderUser.UserId
-		case client.TypeMessageSenderChat:
-			senderChat, _ := message.SenderId.(*client.MessageSenderChat)
-			senderId = senderChat.ChatId
-		}
-		prefix = append(prefix, c.formatContact(senderId))
+	if message.ChatId < 0 {
+		prefix = append(prefix, c.formatSender(message))
 	}
 	// reply to
 	if message.ReplyToMessageId != 0 {
-		prefix = append(prefix, "reply: "+c.formatMessage(message.ChatId, message.ReplyToMessageId, true, nil))
+		prefix = append(prefix, "reply: "+c.formatMessage(message.ChatId, message.ReplyToMessageId, true, replyMsg))
 	}
 	if message.ForwardInfo != nil {
 		prefix = append(prefix, "fwd: "+c.formatForward(message.ForwardInfo))
@@ -750,6 +770,9 @@ func (c *Client) ensureDownloadFile(file *client.File) *client.File {
 // ProcessIncomingMessage transfers a message to XMPP side and marks it as read on Telegram side
 func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
 	var text, oob, auxText string
+
+	reply, replyMsg := c.getMessageReply(message)
+
 	content := message.Content
 	if content != nil && content.MessageContentType() == client.TypeMessageChatChangePhoto {
 		chat, err := c.client.GetChat(&client.GetChatRequest{
@@ -783,7 +806,7 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
 				text = oob
 			} else if !c.Session.RawMessages {
 				var prefix strings.Builder
-				prefix.WriteString(c.messageToPrefix(message, previewName, fileName))
+				prefix.WriteString(c.messageToPrefix(message, previewName, fileName, replyMsg))
 				if text != "" {
 					// \n if it is groupchat and message is not empty
 					if chatId < 0 {
@@ -808,9 +831,9 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
 	// forward message to XMPP
 	sId := strconv.FormatInt(message.Id, 10)
 	sChatId := strconv.FormatInt(chatId, 10)
-	gateway.SendMessageWithOOB(c.jid, sChatId, text, sId, c.xmpp, oob)
+	gateway.SendMessageWithOOB(c.jid, sChatId, text, sId, c.xmpp, reply, oob)
 	if auxText != "" {
-		gateway.SendMessage(c.jid, sChatId, auxText, sId, c.xmpp)
+		gateway.SendMessage(c.jid, sChatId, auxText, sId, c.xmpp, reply)
 	}
 }
 
@@ -825,7 +848,7 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 		// try to execute commands
 		response, isCommand := c.ProcessChatCommand(chatID, text)
 		if response != "" {
-			gateway.SendMessage(returnJid, strconv.FormatInt(chatID, 10), response, "", c.xmpp)
+			gateway.SendTextMessage(returnJid, strconv.FormatInt(chatID, 10), response, c.xmpp)
 		}
 		// do not send on success
 		if isCommand {
@@ -847,11 +870,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 	if chatID != 0 && c.content.Upload != "" && strings.HasPrefix(text, c.content.Upload) {
 		response, err := http.Get(text)
 		if err != nil {
-			gateway.SendMessage(
+			gateway.SendTextMessage(
 				returnJid,
 				strconv.FormatInt(chatID, 10),
 				fmt.Sprintf("Failed to fetch the uploaded file: %s", err.Error()),
-				"",
 				c.xmpp,
 			)
 			return nil
@@ -860,11 +882,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 			defer response.Body.Close()
 
 			if response.StatusCode != 200 {
-				gateway.SendMessage(
+				gateway.SendTextMessage(
 					returnJid,
 					strconv.FormatInt(chatID, 10),
 					fmt.Sprintf("Received status code %v", response.StatusCode),
-					"",
 					c.xmpp,
 				)
 				return nil
@@ -872,22 +893,20 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 
 			tempDir, err := ioutil.TempDir("", "telegabber-*")
 			if err != nil {
-				gateway.SendMessage(
+				gateway.SendTextMessage(
 					returnJid,
 					strconv.FormatInt(chatID, 10),
 					fmt.Sprintf("Failed to create a temporary directory: %s", err.Error()),
-					"",
 					c.xmpp,
 				)
 				return nil
 			}
 			tempFile, err := os.Create(filepath.Join(tempDir, filepath.Base(text)))
 			if err != nil {
-				gateway.SendMessage(
+				gateway.SendTextMessage(
 					returnJid,
 					strconv.FormatInt(chatID, 10),
 					fmt.Sprintf("Failed to create a temporary file: %s", err.Error()),
-					"",
 					c.xmpp,
 				)
 				return nil
@@ -895,11 +914,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 
 			_, err = io.Copy(tempFile, response.Body)
 			if err != nil {
-				gateway.SendMessage(
+				gateway.SendTextMessage(
 					returnJid,
 					strconv.FormatInt(chatID, 10),
 					fmt.Sprintf("Failed to write a temporary file: %s", err.Error()),
-					"",
 					c.xmpp,
 				)
 				return nil
@@ -946,11 +964,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
 			InputMessageContent: message,
 		})
 		if err != nil {
-			gateway.SendMessage(
+			gateway.SendTextMessage(
 				returnJid,
 				strconv.FormatInt(chatID, 10),
 				fmt.Sprintf("Not sent: %s", err.Error()),
-				"",
 				c.xmpp,
 			)
 		}
diff --git a/telegram/utils_test.go b/telegram/utils_test.go
index bfd6c49..03ab8bd 100644
--- a/telegram/utils_test.go
+++ b/telegram/utils_test.go
@@ -389,7 +389,7 @@ func TestMessageToPrefix1(t *testing.T) {
 			},
 		},
 	}
-	prefix := (&Client{Session: &persistence.Session{}}).messageToPrefix(&message, "", "")
+	prefix := (&Client{Session: &persistence.Session{}}).messageToPrefix(&message, "", "", nil)
 	if prefix != "➡ 42 | fwd: ziz" {
 		t.Errorf("Wrong prefix: %v", prefix)
 	}
@@ -404,7 +404,7 @@ func TestMessageToPrefix2(t *testing.T) {
 			},
 		},
 	}
-	prefix := (&Client{Session: &persistence.Session{}}).messageToPrefix(&message, "y.jpg", "")
+	prefix := (&Client{Session: &persistence.Session{}}).messageToPrefix(&message, "y.jpg", "", nil)
 	if prefix != "⬅ 56 | fwd:  (zaz) | preview: y.jpg" {
 		t.Errorf("Wrong prefix: %v", prefix)
 	}
@@ -419,7 +419,7 @@ func TestMessageToPrefix3(t *testing.T) {
 			},
 		},
 	}
-	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "", "a.jpg")
+	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "", "a.jpg", nil)
 	if prefix != "< 56 | fwd:  (zuz) | file: a.jpg" {
 		t.Errorf("Wrong prefix: %v", prefix)
 	}
@@ -430,7 +430,7 @@ func TestMessageToPrefix4(t *testing.T) {
 		Id:         23,
 		IsOutgoing: true,
 	}
-	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "", "")
+	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "", "", nil)
 	if prefix != "> 23" {
 		t.Errorf("Wrong prefix: %v", prefix)
 	}
@@ -445,8 +445,60 @@ func TestMessageToPrefix5(t *testing.T) {
 			},
 		},
 	}
-	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "h.jpg", "a.jpg")
+	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "h.jpg", "a.jpg", nil)
 	if prefix != "< 560 | fwd:  (zyz) | preview: h.jpg | file: a.jpg" {
 		t.Errorf("Wrong prefix: %v", prefix)
 	}
 }
+
+func TestMessageToPrefix6(t *testing.T) {
+	message := client.Message{
+		Id:               23,
+		IsOutgoing:       true,
+		ReplyToMessageId: 42,
+	}
+	reply := client.Message{
+		Id: 42,
+		Content: &client.MessageText{
+			Text: &client.FormattedText{
+				Text: "tist",
+			},
+		},
+	}
+	prefix := (&Client{Session: &persistence.Session{AsciiArrows: true}}).messageToPrefix(&message, "", "", &reply)
+	if prefix != "> 23 | reply: 42 |  | tist" {
+		t.Errorf("Wrong prefix: %v", prefix)
+	}
+}
+
+func GetSenderIdEmpty(t *testing.T) {
+	message := client.Message{}
+	senderId := (&Client{}).getSenderId(&message)
+	if senderId != 0 {
+		t.Errorf("Wrong sender id: %v", senderId)
+	}
+}
+
+func GetSenderIdUser(t *testing.T) {
+	message := client.Message{
+		SenderId: &client.MessageSenderUser{
+			UserId: 42,
+		},
+	}
+	senderId := (&Client{}).getSenderId(&message)
+	if senderId != 42 {
+		t.Errorf("Wrong sender id: %v", senderId)
+	}
+}
+
+func GetSenderIdChat(t *testing.T) {
+	message := client.Message{
+		SenderId: &client.MessageSenderChat{
+			ChatId: -42,
+		},
+	}
+	senderId := (&Client{}).getSenderId(&message)
+	if senderId != -42 {
+		t.Errorf("Wrong sender id: %v", senderId)
+	}
+}
-- 
cgit v1.2.3