From ae31905df4ca17a0e3b3e270029b85d7600b76ec Mon Sep 17 00:00:00 2001 From: cleitonme Date: Sat, 10 Jan 2026 10:12:20 -0300 Subject: [PATCH 1/2] Adiciona suporte a QuotedMessage, refatora tratamento de mensagens citadas. --- handlers.go | 53 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/handlers.go b/handlers.go index 0711ce83..52dc0eb5 100644 --- a/handlers.go +++ b/handlers.go @@ -2100,28 +2100,23 @@ func (s *server) SetStatusMessage() http.HandlerFunc { // Sends a regular text message func (s *server) SendMessage() http.HandlerFunc { - type textStruct struct { - Phone string - Body string - LinkPreview bool - Id string - ContextInfo waE2E.ContextInfo - QuotedText string `json:"QuotedText,omitempty"` + Phone string + Body string + LinkPreview bool + Id string + ContextInfo waE2E.ContextInfo + QuotedText string `json:"QuotedText,omitempty"` + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } - return func(w http.ResponseWriter, r *http.Request) { - txtid := r.Context().Value("userinfo").(Values).Get("Id") - if clientManager.GetWhatsmeowClient(txtid) == nil { s.Respond(w, r, http.StatusInternalServerError, errors.New("no session")) return } - msgid := "" var resp whatsmeow.SendResponse - decoder := json.NewDecoder(r.Body) var t textStruct err := decoder.Decode(&t) @@ -2129,44 +2124,37 @@ func (s *server) SendMessage() http.HandlerFunc { s.Respond(w, r, http.StatusBadRequest, errors.New("could not decode Payload")) return } - if t.Phone == "" { s.Respond(w, r, http.StatusBadRequest, errors.New("missing Phone in Payload")) return } - if t.Body == "" { s.Respond(w, r, http.StatusBadRequest, errors.New("missing Body in Payload")) return } - recipient, err := validateMessageFields(t.Phone, t.ContextInfo.StanzaID, t.ContextInfo.Participant) if err != nil { log.Error().Msg(fmt.Sprintf("%s", err)) s.Respond(w, r, http.StatusBadRequest, err) return } - if t.Id == "" { msgid = clientManager.GetWhatsmeowClient(txtid).GenerateMessageID() } else { msgid = t.Id } - var ( url string title string description string imageData []byte ) - if t.LinkPreview { url = extractFirstURL(t.Body) if url != "" { title, description, imageData = getOpenGraphData(r.Context(), url, txtid) } } - msg := &waE2E.Message{ ExtendedTextMessage: &waE2E.ExtendedTextMessage{ Text: proto.String(t.Body), @@ -2176,16 +2164,24 @@ func (s *server) SendMessage() http.HandlerFunc { JPEGThumbnail: imageData, }, } - if t.ContextInfo.StanzaID != nil { - qm := &waE2E.Message{} - if t.QuotedText != "" { - qm.ExtendedTextMessage = &waE2E.ExtendedTextMessage{ - Text: proto.String(t.QuotedText), - } + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage } else { - qm.Conversation = proto.String("") + // Otherwise, use the old logic with QuotedText. + qm = &waE2E.Message{} + if t.QuotedText != "" { + qm.ExtendedTextMessage = &waE2E.ExtendedTextMessage{ + Text: proto.String(t.QuotedText), + } + } else { + qm.Conversation = proto.String("") + } } + msg.ExtendedTextMessage.ContextInfo = &waE2E.ContextInfo{ StanzaID: proto.String(*t.ContextInfo.StanzaID), Participant: proto.String(*t.ContextInfo.Participant), @@ -2198,24 +2194,20 @@ func (s *server) SendMessage() http.HandlerFunc { } msg.ExtendedTextMessage.ContextInfo.MentionedJID = t.ContextInfo.MentionedJID } - if t.ContextInfo.IsForwarded != nil && *t.ContextInfo.IsForwarded { if msg.ExtendedTextMessage.ContextInfo == nil { msg.ExtendedTextMessage.ContextInfo = &waE2E.ContextInfo{} } msg.ExtendedTextMessage.ContextInfo.IsForwarded = proto.Bool(true) } - resp, err = clientManager.GetWhatsmeowClient(txtid).SendMessage(context.Background(), recipient, msg, whatsmeow.SendRequestExtra{ID: msgid}) if err != nil { s.Respond(w, r, http.StatusInternalServerError, errors.New(fmt.Sprintf("error sending message: %v", err))) return } - historyStr := r.Context().Value("userinfo").(Values).Get("History") historyLimit, _ := strconv.Atoi(historyStr) s.saveOutgoingMessageToHistory(txtid, recipient.String(), msgid, "text", t.Body, "", historyLimit) - log.Info().Str("timestamp", fmt.Sprintf("%v", resp.Timestamp)).Str("id", msgid).Msg("Message sent") response := map[string]interface{}{"Details": "Sent", "Timestamp": resp.Timestamp.Unix(), "Id": msgid} responseJson, err := json.Marshal(response) @@ -2224,7 +2216,6 @@ func (s *server) SendMessage() http.HandlerFunc { } else { s.Respond(w, r, http.StatusOK, string(responseJson)) } - return } } From b38a59dc1b1f481ba9a33826135468d35f32614f Mon Sep 17 00:00:00 2001 From: cleitonme Date: Sat, 10 Jan 2026 10:25:30 -0300 Subject: [PATCH 2/2] Adiciona QuotedMessage nos tipos de mensagem e usa se informado. --- handlers.go | 151 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 31 deletions(-) diff --git a/handlers.go b/handlers.go index 52dc0eb5..285a7a2f 100644 --- a/handlers.go +++ b/handlers.go @@ -817,6 +817,7 @@ func (s *server) SendDocument() http.HandlerFunc { Id string MimeType string ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -906,10 +907,22 @@ func (s *server) SendDocument() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.DocumentMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.DocumentMessage.ContextInfo == nil { + msg.DocumentMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil { @@ -961,6 +974,7 @@ func (s *server) SendAudio() http.HandlerFunc { Seconds uint32 Waveform []byte ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1059,10 +1073,22 @@ func (s *server) SendAudio() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.AudioMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.AudioMessage.ContextInfo == nil { + msg.AudioMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil { @@ -1105,12 +1131,13 @@ func (s *server) SendAudio() http.HandlerFunc { func (s *server) SendImage() http.HandlerFunc { type imageStruct struct { - Phone string - Image string - Caption string - Id string - MimeType string - ContextInfo waE2E.ContextInfo + Phone string + Image string + Caption string + Id string + MimeType string + ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1243,11 +1270,21 @@ func (s *server) SendImage() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + if msg.ImageMessage.ContextInfo == nil { msg.ImageMessage.ContextInfo = &waE2E.ContextInfo{ StanzaID: proto.String(*t.ContextInfo.StanzaID), Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + QuotedMessage: qm, } } } @@ -1302,6 +1339,7 @@ func (s *server) SendSticker() http.HandlerFunc { PackPublisher string Emojis []string ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1382,10 +1420,22 @@ func (s *server) SendSticker() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.StickerMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.StickerMessage.ContextInfo == nil { + msg.StickerMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil { @@ -1435,6 +1485,7 @@ func (s *server) SendVideo() http.HandlerFunc { JPEGThumbnail []byte MimeType string ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1538,10 +1589,22 @@ func (s *server) SendVideo() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.VideoMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.VideoMessage.ContextInfo == nil { + msg.VideoMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil { @@ -1589,6 +1652,7 @@ func (s *server) SendContact() http.HandlerFunc { Name string Vcard string ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1642,10 +1706,22 @@ func (s *server) SendContact() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.ContactMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.ContactMessage.ContextInfo == nil { + msg.ContactMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil { @@ -1694,6 +1770,7 @@ func (s *server) SendLocation() http.HandlerFunc { Latitude float64 Longitude float64 ContextInfo waE2E.ContextInfo + QuotedMessage *waE2E.Message `json:"QuotedMessage,omitempty"` } return func(w http.ResponseWriter, r *http.Request) { @@ -1748,10 +1825,22 @@ func (s *server) SendLocation() http.HandlerFunc { }} if t.ContextInfo.StanzaID != nil { - msg.LocationMessage.ContextInfo = &waE2E.ContextInfo{ - StanzaID: proto.String(*t.ContextInfo.StanzaID), - Participant: proto.String(*t.ContextInfo.Participant), - QuotedMessage: &waE2E.Message{Conversation: proto.String("")}, + var qm *waE2E.Message + + // If QuotedMessage was provided, use it. + if t.QuotedMessage != nil { + qm = t.QuotedMessage + } else { + // Otherwise, it uses the old logic (empty message). + qm = &waE2E.Message{Conversation: proto.String("")} + } + + if msg.LocationMessage.ContextInfo == nil { + msg.LocationMessage.ContextInfo = &waE2E.ContextInfo{ + StanzaID: proto.String(*t.ContextInfo.StanzaID), + Participant: proto.String(*t.ContextInfo.Participant), + QuotedMessage: qm, + } } } if t.ContextInfo.MentionedJID != nil {