183 lines
5.7 KiB
Go
183 lines
5.7 KiB
Go
package threema
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/bdlm/log"
|
|
"github.com/o3ma/o3"
|
|
"gosrc.io/xmpp"
|
|
"gosrc.io/xmpp/stanza"
|
|
)
|
|
|
|
func (a *Account) receiver() {
|
|
for receivedMessage := range a.receive {
|
|
if receivedMessage.Err != nil {
|
|
log.Warnf("Error Receiving Message: %s\n", receivedMessage.Err)
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, To: a.XMPP.String()})
|
|
xMSG.Body = fmt.Sprintf("error on decoding message:\n%v", receivedMessage.Err)
|
|
a.xmpp <- xMSG
|
|
continue
|
|
}
|
|
header := receivedMessage.Msg.Header()
|
|
sender := header.Sender.String()
|
|
if string(a.TID) == sender {
|
|
continue
|
|
}
|
|
if p, gh, err := a.receiving(receivedMessage.Msg); err != nil {
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
|
xMSG.Body = fmt.Sprintf("error on decoding message: %s\n%v", err, receivedMessage.Msg)
|
|
a.xmpp <- xMSG
|
|
} else {
|
|
if gh != nil {
|
|
xid := &xmpp.Jid{
|
|
Node: a.XMPP.Local,
|
|
Domain: a.XMPP.Domain,
|
|
}
|
|
id := strFromThreemaGroup(gh)
|
|
if len(a.XMPPResource[id]) == 0 {
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
|
//TODO please join
|
|
xMSG.Body = fmt.Sprintf(`ERROR: group message not delievered, please join
|
|
xmpp:%s@{{DOMAIN}}?join`, id)
|
|
a.xmpp <- xMSG
|
|
continue
|
|
}
|
|
for r := range a.XMPPResource[id] {
|
|
xid.Resource = r
|
|
switch m := p.(type) {
|
|
case stanza.Message:
|
|
m.Attrs.To = xid.Full()
|
|
a.xmpp <- m
|
|
}
|
|
}
|
|
} else {
|
|
a.xmpp <- p
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func requestExtensions(xMSG *stanza.Message) {
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.ReceiptRequest{})
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.Markable{})
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.StateActive{})
|
|
}
|
|
|
|
func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, *o3.GroupMessageHeader, error) {
|
|
header := receivedMessage.Header()
|
|
sender := header.Sender.String()
|
|
logger := log.WithFields(map[string]interface{}{
|
|
"from": sender,
|
|
"to_t": header.Recipient.String(),
|
|
"to": a.XMPP.String(),
|
|
})
|
|
sender = strings.ToLower(sender)
|
|
switch msg := receivedMessage.(type) {
|
|
case *o3.TextMessage:
|
|
dbText := "recv text"
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
|
if msg.GroupMessageHeader != nil {
|
|
to := a.XMPP.String()
|
|
ad := strings.SplitN(msg.Body, "=", 2)
|
|
from := sender
|
|
if len(ad) == 2 {
|
|
from = strings.ToLower(ad[0])[:len(ad[0])-3]
|
|
}
|
|
xMSG = stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeGroupchat, From: jidFromThreemaGroup(from, msg.GroupMessageHeader), To: to, Id: strconv.FormatUint(header.ID, 10)})
|
|
if len(ad) == 2 {
|
|
xMSG.Body = ad[1][4:]
|
|
} else {
|
|
xMSG.Body = msg.Body
|
|
}
|
|
dbText = "recv grouptext"
|
|
} else {
|
|
xMSG.Body = msg.Body
|
|
requestExtensions(&xMSG)
|
|
}
|
|
logger.WithFields(map[string]interface{}{
|
|
"from_x": xMSG.From,
|
|
"id": xMSG.Id,
|
|
"text": xMSG.Body,
|
|
}).Debug(dbText)
|
|
return xMSG, msg.GroupMessageHeader, nil
|
|
case *o3.AudioMessage:
|
|
if a.threema.httpUploadPath == "" {
|
|
return nil, nil, errors.New("no place to store files at transport configurated")
|
|
}
|
|
data, err := msg.GetData()
|
|
if err != nil {
|
|
logger.Warnf("unable to read data from message: %s", err)
|
|
return nil, nil, err
|
|
}
|
|
xMSG, err := a.FileToXMPP(sender, header.ID, "mp3", data)
|
|
if err != nil {
|
|
logger.Warnf("unable to create data from message: %s", err)
|
|
return nil, nil, err
|
|
}
|
|
requestExtensions(&xMSG)
|
|
logger.WithField("url", xMSG.Body).Debug("recv audio")
|
|
return xMSG, nil, nil
|
|
|
|
case *o3.ImageMessage:
|
|
if a.threema.httpUploadPath == "" {
|
|
return nil, nil, errors.New("no place to store files at transport configurated")
|
|
}
|
|
data, err := msg.GetData(a.ThreemaID)
|
|
if err != nil {
|
|
logger.Warnf("unable to read data from message: %s", err)
|
|
return nil, nil, err
|
|
}
|
|
xMSG, err := a.FileToXMPP(sender, header.ID, "jpg", data)
|
|
if err != nil {
|
|
logger.Warnf("unable to create data from message: %s", err)
|
|
return nil, nil, err
|
|
}
|
|
requestExtensions(&xMSG)
|
|
logger.WithField("url", xMSG.Body).Debug("recv image")
|
|
return xMSG, nil, nil
|
|
|
|
case *o3.DeliveryReceiptMessage:
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
|
state := ""
|
|
|
|
if msg.Status == o3.MSGDELIVERED {
|
|
state = "delivered"
|
|
if id, ok := a.deliveredMSG[msg.MessageID]; ok {
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.ReceiptReceived{ID: id})
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.MarkReceived{ID: id})
|
|
delete(a.deliveredMSG, msg.MessageID)
|
|
} else {
|
|
logger.Warnf("found not id in cache to announce received on xmpp side")
|
|
}
|
|
}
|
|
if msg.Status == o3.MSGREAD {
|
|
state = "displayed"
|
|
if id, ok := a.readedMSG[msg.MessageID]; ok {
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.MarkDisplayed{ID: id})
|
|
delete(a.readedMSG, msg.MessageID)
|
|
} else {
|
|
logger.Warnf("found not id in cache to announce readed on xmpp side")
|
|
}
|
|
}
|
|
|
|
if len(xMSG.Extensions) > 0 {
|
|
logger.WithField("state", state).Debug("recv state")
|
|
return xMSG, nil, nil
|
|
}
|
|
return nil, nil, nil
|
|
case *o3.TypingNotificationMessage:
|
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
|
if msg.OnOff != 0 {
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.StateComposing{})
|
|
} else {
|
|
xMSG.Extensions = append(xMSG.Extensions, stanza.StateInactive{})
|
|
}
|
|
logger.WithField("on", msg.OnOff).Debug("recv typing")
|
|
return xMSG, nil, nil
|
|
}
|
|
return nil, nil, errors.New("not known data format")
|
|
}
|