aboutsummaryrefslogtreecommitdiff
path: root/telegram/utils.go
diff options
context:
space:
mode:
authorBohdan Horbeshko <bodqhrohro@gmail.com>2024-01-10 22:30:00 +0300
committerBohdan Horbeshko <bodqhrohro@gmail.com>2024-01-10 22:30:00 +0300
commit4532748c8458971151dfb6b535b11b2a3e17a372 (patch)
treed74a5aabce0a9c614a8fa7f8eb27dfdf6b9d95d6 /telegram/utils.go
parentf2807779aad0dd0d463d396d7ae7e2de48a83c3b (diff)
Support chosen quotes in replies and replies from other chats
Diffstat (limited to 'telegram/utils.go')
-rw-r--r--telegram/utils.go215
1 files changed, 144 insertions, 71 deletions
diff --git a/telegram/utils.go b/telegram/utils.go
index 9370839..b17d692 100644
--- a/telegram/utils.go
+++ b/telegram/utils.go
@@ -37,6 +37,14 @@ type VCardInfo struct {
Info string
}
+type messageStub struct {
+ MessageId int64
+ ChatId int64
+ Sender string
+ Date int32
+ Text string
+}
+
var errOffline = errors.New("TDlib instance is offline")
var spaceRegex = regexp.MustCompile(`\s+`)
@@ -342,33 +350,74 @@ 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) {
+func (c *Client) messageToStub(message *client.Message, preview bool, text string) *messageStub {
+ if text == "" {
+ text = c.messageContentToText(message.Content, message.ChatId, preview)
+ }
+ return &messageStub{
+ MessageId: message.Id,
+ ChatId: message.ChatId,
+ Sender: c.formatSender(message),
+ Date: message.Date,
+ Text: text,
+ }
+}
+
+func (c *Client) getMessageReply(message *client.Message, preview bool, noContent bool) (gatewayReply *gateway.Reply, tgReply *messageStub) {
if message.ReplyTo != nil && message.ReplyTo.MessageReplyToType() == client.TypeMessageReplyToMessage {
replyTo, _ := message.ReplyTo.(*client.MessageReplyToMessage)
- // TODO: support replies from other chats
- if message.ChatId != replyTo.ChatId {
- log.Warn("Reply from other/unknown chat")
- log.Debugf("replyTo: %#v", replyTo)
- return
- }
+ var text string
+ if replyTo.Quote != nil && !noContent {
+ text = formatter.Format(
+ replyTo.Quote.Text,
+ replyTo.Quote.Entities,
+ c.getFormatter(),
+ )
+ // make the whole quote fit one line
+ text = strings.ReplaceAll(text, "\n", " ")
+ }
+ if message.ChatId == replyTo.ChatId {
+ // obtain message from this chat
+ replyMsg, err := c.client.GetMessage(&client.GetMessageRequest{
+ ChatId: message.ChatId,
+ MessageId: replyTo.MessageId,
+ })
+ if err != nil {
+ log.Errorf("<error fetching message: %s>", err.Error())
+ return
+ }
- var err error
- replyMsg, err = c.client.GetMessage(&client.GetMessageRequest{
- ChatId: message.ChatId,
- MessageId: replyTo.MessageId,
- })
- if err != nil {
- log.Errorf("<error fetching message: %s>", err.Error())
- return
- }
+ if !noContent {
+ tgReply = c.messageToStub(replyMsg, preview, text)
+ }
- replyId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, message.ChatId, replyTo.MessageId)
- if err != nil {
- replyId = strconv.FormatInt(replyTo.MessageId, 10)
- }
- reply = &gateway.Reply{
- Author: fmt.Sprintf("%v@%s", c.getSenderId(replyMsg), gateway.Jid.Full()),
- Id: replyId,
+ replyId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, message.ChatId, replyTo.MessageId)
+ if err != nil {
+ replyId = strconv.FormatInt(replyTo.MessageId, 10)
+ }
+
+ gatewayReply = &gateway.Reply{
+ Author: fmt.Sprintf("%v@%s", c.getSenderId(replyMsg), gateway.Jid.Full()),
+ Id: replyId,
+ }
+ } else if !noContent {
+ // it's safe to assume there's no need to pass ChatId here
+ // as it's needed only for pin messages which are not allowed in replies
+ if text == "" && replyTo.Content != nil {
+ text = c.messageContentToText(replyTo.Content, 0, preview)
+ }
+
+ if text == "" {
+ log.Error("Empty reply from other/unknown chat")
+ log.Debugf("replyTo: %#v", replyTo)
+ return
+ }
+
+ tgReply = &messageStub{
+ Sender: c.formatOrigin(replyTo.Origin) + " @ " + c.formatContact(replyTo.ChatId),
+ Date: replyTo.OriginSendDate,
+ Text: text,
+ }
}
}
@@ -391,9 +440,16 @@ func (c *Client) formatMessage(chatID int64, messageID int64, preview bool, mess
return ""
}
+ return c.formatMessageContent(preview, c.messageToStub(message, preview, ""))
+}
+
+func (c *Client) formatMessageContent(preview bool, message *messageStub) string {
var str strings.Builder
// add messageid and sender
- str.WriteString(fmt.Sprintf("%v | %s | ", message.Id, c.formatSender(message)))
+ if message.MessageId != 0 {
+ str.WriteString(fmt.Sprintf("%v | ", message.MessageId))
+ }
+ str.WriteString(fmt.Sprintf("%s | ", message.Sender))
// add date
if !preview {
str.WriteString(
@@ -404,10 +460,7 @@ func (c *Client) formatMessage(chatID int64, messageID int64, preview bool, mess
}
// text message
- var text string
- if message.Content != nil {
- text = c.messageToText(message, preview)
- }
+ text := message.Text
if text != "" {
if !preview {
str.WriteString(text)
@@ -424,30 +477,33 @@ func (c *Client) formatMessage(chatID int64, messageID int64, preview bool, mess
return str.String()
}
-func (c *Client) formatForward(fwd *client.MessageForwardInfo) string {
- switch fwd.Origin.MessageOriginType() {
+func (c *Client) formatOrigin(origin client.MessageOrigin) string {
+ if origin == nil {
+ return ""
+ }
+ switch origin.MessageOriginType() {
case client.TypeMessageOriginUser:
- originUser := fwd.Origin.(*client.MessageOriginUser)
+ originUser := origin.(*client.MessageOriginUser)
return c.formatContact(originUser.SenderUserId)
case client.TypeMessageOriginChat:
- originChat := fwd.Origin.(*client.MessageOriginChat)
+ originChat := origin.(*client.MessageOriginChat)
var signature string
if originChat.AuthorSignature != "" {
signature = fmt.Sprintf(" (%s)", originChat.AuthorSignature)
}
return c.formatContact(originChat.SenderChatId) + signature
case client.TypeMessageOriginHiddenUser:
- originUser := fwd.Origin.(*client.MessageOriginHiddenUser)
+ originUser := origin.(*client.MessageOriginHiddenUser)
return originUser.SenderName
case client.TypeMessageOriginChannel:
- channel := fwd.Origin.(*client.MessageOriginChannel)
+ channel := origin.(*client.MessageOriginChannel)
var signature string
if channel.AuthorSignature != "" {
signature = fmt.Sprintf(" (%s)", channel.AuthorSignature)
}
return c.formatContact(channel.ChatId) + signature
}
- return "Unknown forward type"
+ return "Unknown origin type"
}
func (c *Client) formatFile(file *client.File, compact bool) (string, string) {
@@ -593,20 +649,24 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
return "<empty message>"
}
+ return c.messageContentToText(message.Content, message.ChatId, preview)
+}
+
+func (c *Client) messageContentToText(content client.MessageContent, chatId int64, preview bool) string {
markupMode := c.getFormatter()
- switch message.Content.MessageContentType() {
+ switch content.MessageContentType() {
case client.TypeMessageSticker:
- sticker, _ := message.Content.(*client.MessageSticker)
+ sticker, _ := content.(*client.MessageSticker)
return sticker.Sticker.Emoji
case client.TypeMessageAnimatedEmoji:
- animatedEmoji, _ := message.Content.(*client.MessageAnimatedEmoji)
+ animatedEmoji, _ := content.(*client.MessageAnimatedEmoji)
return animatedEmoji.Emoji
case client.TypeMessageBasicGroupChatCreate, client.TypeMessageSupergroupChatCreate:
return "has created chat"
case client.TypeMessageChatJoinByLink:
return "joined chat via invite link"
case client.TypeMessageChatAddMembers:
- addMembers, _ := message.Content.(*client.MessageChatAddMembers)
+ addMembers, _ := content.(*client.MessageChatAddMembers)
text := "invited "
if len(addMembers.MemberUserIds) > 0 {
@@ -615,19 +675,19 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
return text
case client.TypeMessageChatDeleteMember:
- deleteMember, _ := message.Content.(*client.MessageChatDeleteMember)
+ deleteMember, _ := content.(*client.MessageChatDeleteMember)
return "kicked " + c.formatContact(deleteMember.UserId)
case client.TypeMessagePinMessage:
- pinMessage, _ := message.Content.(*client.MessagePinMessage)
- return "pinned message: " + c.formatMessage(message.ChatId, pinMessage.MessageId, preview, nil)
+ pinMessage, _ := content.(*client.MessagePinMessage)
+ return "pinned message: " + c.formatMessage(chatId, pinMessage.MessageId, preview, nil)
case client.TypeMessageChatChangeTitle:
- changeTitle, _ := message.Content.(*client.MessageChatChangeTitle)
+ changeTitle, _ := content.(*client.MessageChatChangeTitle)
return "chat title set to: " + changeTitle.Title
case client.TypeMessageLocation:
- location, _ := message.Content.(*client.MessageLocation)
+ location, _ := content.(*client.MessageLocation)
return c.formatLocation(location.Location)
case client.TypeMessageVenue:
- venue, _ := message.Content.(*client.MessageVenue)
+ venue, _ := content.(*client.MessageVenue)
if preview {
return venue.Venue.Title
} else {
@@ -639,7 +699,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessagePhoto:
- photo, _ := message.Content.(*client.MessagePhoto)
+ photo, _ := content.(*client.MessagePhoto)
if preview {
return photo.Caption.Text
} else {
@@ -650,7 +710,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageAudio:
- audio, _ := message.Content.(*client.MessageAudio)
+ audio, _ := content.(*client.MessageAudio)
if preview {
return audio.Caption.Text
} else {
@@ -661,7 +721,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageVideo:
- video, _ := message.Content.(*client.MessageVideo)
+ video, _ := content.(*client.MessageVideo)
if preview {
return video.Caption.Text
} else {
@@ -672,7 +732,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageDocument:
- document, _ := message.Content.(*client.MessageDocument)
+ document, _ := content.(*client.MessageDocument)
if preview {
return document.Caption.Text
} else {
@@ -683,7 +743,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageText:
- text, _ := message.Content.(*client.MessageText)
+ text, _ := content.(*client.MessageText)
if preview {
return text.Text.Text
} else {
@@ -694,7 +754,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageVoiceNote:
- voice, _ := message.Content.(*client.MessageVoiceNote)
+ voice, _ := content.(*client.MessageVoiceNote)
if preview {
return voice.Caption.Text
} else {
@@ -707,7 +767,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
case client.TypeMessageVideoNote:
return ""
case client.TypeMessageAnimation:
- animation, _ := message.Content.(*client.MessageAnimation)
+ animation, _ := content.(*client.MessageAnimation)
if preview {
return animation.Caption.Text
} else {
@@ -718,7 +778,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageContact:
- contact, _ := message.Content.(*client.MessageContact)
+ contact, _ := content.(*client.MessageContact)
if preview {
return contact.Contact.FirstName + " " + contact.Contact.LastName
} else {
@@ -736,10 +796,10 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
)
}
case client.TypeMessageDice:
- dice, _ := message.Content.(*client.MessageDice)
+ dice, _ := content.(*client.MessageDice)
return fmt.Sprintf("%s 1d6: [%v]", dice.Emoji, dice.Value)
case client.TypeMessagePoll:
- poll, _ := message.Content.(*client.MessagePoll)
+ poll, _ := content.(*client.MessagePoll)
if preview {
return poll.Poll.Question
@@ -765,7 +825,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
return strings.Join(rows, "\n")
}
case client.TypeMessageChatSetMessageAutoDeleteTime:
- ttl, _ := message.Content.(*client.MessageChatSetMessageAutoDeleteTime)
+ ttl, _ := content.(*client.MessageChatSetMessageAutoDeleteTime)
name := c.formatContact(ttl.FromUserId)
if name == "" {
if ttl.MessageAutoDeleteTime == 0 {
@@ -782,7 +842,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
}
}
- return fmt.Sprintf("unknown message (%s)", message.Content.MessageContentType())
+ return fmt.Sprintf("unknown message (%s)", content.MessageContentType())
}
func (c *Client) contentToFile(content client.MessageContent) (*client.File, *client.File) {
@@ -856,7 +916,7 @@ func (c *Client) countCharsInLines(lines *[]string) (count int) {
return
}
-func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string, replyMsg *client.Message) (string, int, int) {
+func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string) (string, *gateway.Reply) {
isPM, err := c.IsPM(message.ChatId)
if err != nil {
log.Errorf("Could not determine if chat is PM: %v", err)
@@ -865,7 +925,6 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string,
// with carbons, hide for all messages in PM and only for outgoing in group chats
hideSender := isCarbonsEnabled && (message.IsOutgoing || isPM)
- var replyStart, replyEnd int
prefix := []string{}
// message direction
var directionChar string
@@ -894,21 +953,34 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string,
prefix = append(prefix, sender)
}
}
+
// reply to
- if message.ReplyTo != nil && message.ReplyTo.MessageReplyToType() == client.TypeMessageReplyToMessage {
- replyTo, _ := message.ReplyTo.(*client.MessageReplyToMessage)
+ preview := true
+ reply, tgReply := c.getMessageReply(message, preview, false)
+
+ if tgReply != nil {
+ var replyStart, replyEnd int
+
if len(prefix) > 0 {
replyStart = c.countCharsInLines(&prefix) + (len(prefix)-1)*len(messageHeaderSeparator)
}
- replyLine := "reply: " + c.formatMessage(message.ChatId, replyTo.MessageId, true, replyMsg)
+
+ replyLine := "reply: " + c.formatMessageContent(preview, tgReply)
prefix = append(prefix, replyLine)
+
replyEnd = replyStart + utf8.RuneCountInString(replyLine)
if len(prefix) > 0 {
replyEnd += len(messageHeaderSeparator)
}
+
+ if reply != nil {
+ reply.Start = uint64(replyStart)
+ reply.End = uint64(replyEnd)
+ }
}
+
if message.ForwardInfo != nil {
- prefix = append(prefix, "fwd: "+c.formatForward(message.ForwardInfo))
+ prefix = append(prefix, "fwd: "+c.formatOrigin(message.ForwardInfo.Origin))
}
// preview
if previewString != "" {
@@ -919,7 +991,7 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string,
prefix = append(prefix, "file: "+fileString)
}
- return strings.Join(prefix, messageHeaderSeparator), replyStart, replyEnd
+ return strings.Join(prefix, messageHeaderSeparator), reply
}
func (c *Client) ensureDownloadFile(file *client.File) *client.File {
@@ -944,8 +1016,8 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
jids := c.getCarbonFullJids(isCarbon, "")
var text, oob, auxText string
-
- reply, replyMsg := c.getMessageReply(message)
+ var reply *gateway.Reply
+ var replyObtained bool
content := message.Content
if content != nil && content.MessageContentType() == client.TypeMessageChatChangePhoto {
@@ -981,12 +1053,10 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
} else if !c.Session.RawMessages {
var newText strings.Builder
- prefix, replyStart, replyEnd := c.messageToPrefix(message, previewName, fileName, replyMsg)
+ prefix, prefixReply := c.messageToPrefix(message, previewName, fileName)
+ reply = prefixReply
+ replyObtained = true
newText.WriteString(prefix)
- if reply != nil {
- reply.Start = uint64(replyStart)
- reply.End = uint64(replyEnd)
- }
if text != "" {
// \n if it is groupchat and message is not empty
@@ -1004,6 +1074,9 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
}
}
}
+ if !replyObtained {
+ reply, _ = c.getMessageReply(message, false, true)
+ }
// mark message as read
c.client.ViewMessages(&client.ViewMessagesRequest{