From 47fa7bca492f9d78c3bea009c7686a6bf4d8fc3b Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Fri, 29 Sep 2023 16:17:25 -0400 Subject: [PATCH] Return outgoing message errors as message error stanzas (only in groupchats yet) --- telegram/utils.go | 35 ++++++++++++++++++++------------ xmpp/gateway/gateway.go | 45 +++++++++++++++++++++++++++++++++-------- xmpp/handlers.go | 5 +++-- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/telegram/utils.go b/telegram/utils.go index 21c4ad3..eba500c 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -1188,7 +1188,7 @@ func (c *Client) PrepareOutgoingMessageContent(text string) client.InputMessageC } // ProcessOutgoingMessage executes commands or sends messages to mapped chats, returns message id -func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid string, replyId int64, replaceId int64) *client.Message { +func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid string, replyId int64, replaceId int64, isGroupchat bool) *client.Message { if !c.Online() { // we're offline return nil @@ -1198,7 +1198,7 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str // try to execute commands response, isCommand := c.ProcessChatCommand(chatID, text) if response != "" { - c.returnMessage(returnJid, chatID, response) + c.returnMessage(returnJid, chatID, response, 0, isGroupchat) } // do not send on success if isCommand { @@ -1224,27 +1224,31 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str if c.content.Upload != "" && strings.HasPrefix(text, c.content.Upload) { response, err := http.Get(text) if err != nil { - c.returnError(returnJid, chatID, "Failed to fetch the uploaded file", err) + c.returnError(returnJid, chatID, "Failed to fetch the uploaded file", err, 500, isGroupchat) } if response != nil && response.Body != nil { defer response.Body.Close() if response.StatusCode != 200 { - c.returnMessage(returnJid, chatID, fmt.Sprintf("Received status code %v", response.StatusCode)) + c.returnMessage(returnJid, chatID, fmt.Sprintf("Received status code %v", response.StatusCode), response.StatusCode, isGroupchat) + return nil } tempDir, err := ioutil.TempDir("", "telegabber-*") if err != nil { - c.returnError(returnJid, chatID, "Failed to create a temporary directory", err) + c.returnError(returnJid, chatID, "Failed to create a temporary directory", err, 500, isGroupchat) + return nil } tempFile, err := os.Create(filepath.Join(tempDir, filepath.Base(text))) if err != nil { - c.returnError(returnJid, chatID, "Failed to create a temporary file", err) + c.returnError(returnJid, chatID, "Failed to create a temporary file", err, 500, isGroupchat) + return nil } _, err = io.Copy(tempFile, response.Body) if err != nil { - c.returnError(returnJid, chatID, "Failed to write a temporary file", err) + c.returnError(returnJid, chatID, "Failed to write a temporary file", err, 500, isGroupchat) + return nil } file = &client.InputFileLocal{ @@ -1272,7 +1276,7 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str InputMessageContent: content, }) if err != nil { - c.returnError(returnJid, chatID, "Not edited", err) + c.returnError(returnJid, chatID, "Not edited", err, 400, isGroupchat) return nil } return tgMessage @@ -1284,18 +1288,23 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str InputMessageContent: content, }) if err != nil { - c.returnError(returnJid, chatID, "Not sent", err) + c.returnError(returnJid, chatID, "Not sent", err, 400, isGroupchat) return nil } return tgMessage } -func (c *Client) returnMessage(returnJid string, chatID int64, text string) { - gateway.SendTextMessage(returnJid, strconv.FormatInt(chatID, 10), text, c.xmpp) +func (c *Client) returnMessage(returnJid string, chatID int64, text string, code int, isGroupchat bool) { + sChatId := strconv.FormatInt(chatID, 10) + if isGroupchat { + gateway.SendErrorMessage(returnJid, sChatId + "@" + gateway.Jid.Bare(), text, code, isGroupchat, c.xmpp) + } else { + gateway.SendTextMessage(returnJid, sChatId, text, c.xmpp) + } } -func (c *Client) returnError(returnJid string, chatID int64, msg string, err error) { - c.returnMessage(returnJid, chatID, fmt.Sprintf("%s: %s", msg, err.Error())) +func (c *Client) returnError(returnJid string, chatID int64, msg string, err error, code int, isGroupchat bool) { + c.returnMessage(returnJid, chatID, fmt.Sprintf("%s: %s", msg, err.Error()), code, isGroupchat) } func (c *Client) prepareOutgoingMessageContent(text string, file *client.InputFileLocal) client.InputMessageContent { diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 89f1eb8..9a42077 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -44,30 +44,35 @@ var MessageOutgoingPermissionVersion = 0 // SendMessage creates and sends a message stanza func SendMessage(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, isCarbon, isGroupchat bool, originalFrom string) { - sendMessageWrapper(to, from, body, "", id, component, reply, timestamp, "", isCarbon, isGroupchat, false, originalFrom) + sendMessageWrapper(to, from, body, "", id, component, reply, timestamp, "", isCarbon, isGroupchat, false, originalFrom, 0) } // SendServiceMessage creates and sends a simple message stanza from transport func SendServiceMessage(to, body string, component *xmpp.Component) { - sendMessageWrapper(to, "", body, "", "", component, nil, 0, "", false, false, false, "") + sendMessageWrapper(to, "", body, "", "", component, nil, 0, "", false, false, false, "", 0) } // SendTextMessage creates and sends a simple message stanza func SendTextMessage(to, from, body string, component *xmpp.Component) { - sendMessageWrapper(to, from, body, "", "", component, nil, 0, "", false, false, false, "") + sendMessageWrapper(to, from, body, "", "", component, nil, 0, "", false, false, false, "", 0) +} + +// SendErrorMessage creates and sends an error message stanza +func SendErrorMessage(to, from, text string, code int, isGroupchat bool, component *xmpp.Component) { + sendMessageWrapper(to, from, text, "", "", component, nil, 0, "", false, isGroupchat, false, "", code) } // SendMessageWithOOB creates and sends a message stanza with OOB URL func SendMessageWithOOB(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob string, isCarbon, isGroupchat bool, originalFrom string) { - sendMessageWrapper(to, from, body, "", id, component, reply, timestamp, oob, isCarbon, isGroupchat, false, originalFrom) + sendMessageWrapper(to, from, body, "", id, component, reply, timestamp, oob, isCarbon, isGroupchat, false, originalFrom, 0) } // SendSubjectMessage creates and sends a MUC subject func SendSubjectMessage(to, from, subject, id string, component *xmpp.Component, timestamp int64) { - sendMessageWrapper(to, from, "", subject, id, component, nil, timestamp, "", false, true, true, "") + sendMessageWrapper(to, from, "", subject, id, component, nil, timestamp, "", false, true, true, "", 0) } -func sendMessageWrapper(to, from, body, subject, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob string, isCarbon, isGroupchat, forceSubject bool, originalFrom string) { +func sendMessageWrapper(to, from, body, subject, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob string, isCarbon, isGroupchat, forceSubject bool, originalFrom string, errorCode int) { toJid, err := stanza.NewJid(to) if err != nil { log.WithFields(log.Fields{ @@ -107,7 +112,9 @@ func sendMessageWrapper(to, from, body, subject, id string, component *xmpp.Comp }).Warn("Got message") var messageType stanza.StanzaType - if isGroupchat { + if errorCode != 0 { + messageType = stanza.MessageTypeError + } else if isGroupchat { messageType = stanza.MessageTypeGroupchat } else { messageType = stanza.MessageTypeChat @@ -121,7 +128,29 @@ func sendMessageWrapper(to, from, body, subject, id string, component *xmpp.Comp Id: id, }, Subject: subject, - Body: body, + } + if errorCode == 0 { + message.Body = body + } else { + message.Error = stanza.Err{ + Code: errorCode, + Text: body, + } + switch errorCode { + case 400: + message.Error.Type = stanza.ErrorTypeModify + message.Error.Reason = "bad-request" + case 404: + message.Error.Type = stanza.ErrorTypeCancel + message.Error.Reason = "item-not-found" + case 500: + message.Error.Type = stanza.ErrorTypeWait + message.Error.Reason = "internal-server-error" + default: + log.Error("Unknown error code, falling back with empty reason") + message.Error.Type = stanza.ErrorTypeCancel + message.Error.Reason = "undefined-condition" + } } if oob != "" { diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 0b3e71f..72b46eb 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -194,10 +194,11 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { return } } + isGroupchat := msg.Type == "groupchat" session.SendMessageLock.Lock() defer session.SendMessageLock.Unlock() - tgMessage := session.ProcessOutgoingMessage(toID, text, msg.From, replyId, replaceId) + tgMessage := session.ProcessOutgoingMessage(toID, text, msg.From, replyId, replaceId, isGroupchat) if tgMessage != nil { if replaceId != 0 { // not needed (is it persistent among clients though?) @@ -214,7 +215,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { } // pong groupchat messages back - if msg.Type == "groupchat" { + if isGroupchat { toJid, err := stanza.NewJid(msg.To) if err == nil && toJid.Resource == "" { session.SendMessageToGateway(