first group fix
This commit is contained in:
parent
eef58dcfba
commit
91e2aa41b8
|
@ -72,7 +72,7 @@ func (c *Config) handleDiscoItems(s xmpp.Sender, p stanza.Packet) {
|
|||
|
||||
log.WithFields(map[string]interface{}{
|
||||
"type": c.Type,
|
||||
"from": s,
|
||||
"id": attrs.Id,
|
||||
"to": attrs.To,
|
||||
}).Debug("disco items")
|
||||
s.Send(iq)
|
||||
|
@ -92,28 +92,32 @@ func (c *Config) handleIQ(s xmpp.Sender, p stanza.Packet) {
|
|||
|
||||
log.WithFields(map[string]interface{}{
|
||||
"type": c.Type,
|
||||
"from": s,
|
||||
"to": attrs.To,
|
||||
}).Debugf("ignore: %s", iq.Payload)
|
||||
"id": attrs.Id,
|
||||
}).Debugf("ignore: %v", iq.Payload)
|
||||
s.Send(resp)
|
||||
}
|
||||
func (c *Config) handleMessage(s xmpp.Sender, p stanza.Packet) {
|
||||
msg, ok := p.(stanza.Message)
|
||||
attr := msg.Attrs
|
||||
attrs := msg.Attrs
|
||||
if !ok {
|
||||
pr, ok := p.(stanza.Message)
|
||||
attr = pr.Attrs
|
||||
pr, ok := p.(stanza.Presence)
|
||||
attrs = pr.Attrs
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
if c.XMPPDebug {
|
||||
log.WithFields(map[string]interface{}{
|
||||
logger := log.WithFields(map[string]interface{}{
|
||||
"type": c.Type,
|
||||
"from": s,
|
||||
"to": attr.To,
|
||||
"id": attr.Id,
|
||||
}).Debug(msg.XMPPFormat())
|
||||
"id": attrs.Id,
|
||||
"to": attrs.To,
|
||||
})
|
||||
if attrs.Type == "error" {
|
||||
logger.Error(msg.XMPPFormat())
|
||||
return
|
||||
}
|
||||
if c.XMPPDebug {
|
||||
logger.Debug(msg.XMPPFormat())
|
||||
}
|
||||
c.comp.Send(p)
|
||||
}
|
||||
|
|
|
@ -16,16 +16,32 @@ func (c *Config) sender(packets chan stanza.Packet) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Config) fixAddr(addr string) string {
|
||||
if addr == "" {
|
||||
return c.Host
|
||||
}
|
||||
if strings.Contains(addr, "{{DOMAIN}}") {
|
||||
return strings.Replace(addr, "{{DOMAIN}}", c.Host, 1)
|
||||
}
|
||||
if !strings.Contains(addr, "@") {
|
||||
return addr + "@" + c.Host
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func (c *Config) sending(packet stanza.Packet) stanza.Packet {
|
||||
logger := log.WithField("type", c.Type)
|
||||
switch p := packet.(type) {
|
||||
case stanza.Presence:
|
||||
p.From = c.fixAddr(p.From)
|
||||
if p.To != "" {
|
||||
p.To = c.fixAddr(p.To)
|
||||
}
|
||||
return p
|
||||
case stanza.Message:
|
||||
if p.From == "" {
|
||||
p.From = c.Host
|
||||
} else if strings.Contains(p.From, "{{DOMAIN}}") {
|
||||
p.From = strings.Replace(p.From, "{{DOMAIN}}", c.Host, 1)
|
||||
} else {
|
||||
p.From += "@" + c.Host
|
||||
p.From = c.fixAddr(p.From)
|
||||
if p.To != "" {
|
||||
p.To = c.fixAddr(p.To)
|
||||
}
|
||||
if c.XMPPDebug {
|
||||
logger.WithFields(map[string]interface{}{
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
|
||||
"github.com/o3ma/o3"
|
||||
"gosrc.io/xmpp/stanza"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
|
@ -16,8 +17,10 @@ type Account struct {
|
|||
ThreemaID *o3.ThreemaID
|
||||
send chan<- o3.Message
|
||||
receive <-chan o3.ReceivedMsg
|
||||
xmpp chan<- stanza.Packet
|
||||
deliveredMSG map[uint64]string
|
||||
readedMSG map[uint64]string
|
||||
XMPPResource map[string]map[string]bool
|
||||
}
|
||||
|
||||
func (t *Threema) getAccount(jid *models.JID) (*Account, error) {
|
||||
|
@ -48,6 +51,10 @@ func (t *Threema) getAccount(jid *models.JID) (*Account, error) {
|
|||
AccountThreema: account,
|
||||
ThreemaID: &tid,
|
||||
threema: t,
|
||||
xmpp: t.out,
|
||||
XMPPResource: make(map[string]map[string]bool),
|
||||
deliveredMSG: make(map[uint64]string),
|
||||
readedMSG: make(map[uint64]string),
|
||||
}
|
||||
session := o3.NewSessionContext(tid)
|
||||
a.send, a.receive, err = session.Run()
|
||||
|
@ -57,10 +64,8 @@ func (t *Threema) getAccount(jid *models.JID) (*Account, error) {
|
|||
}
|
||||
|
||||
a.XMPP = *jid
|
||||
a.deliveredMSG = make(map[uint64]string)
|
||||
a.readedMSG = make(map[uint64]string)
|
||||
|
||||
go a.receiver(t.out)
|
||||
go a.receiver()
|
||||
|
||||
t.accountJID[jid.String()] = a
|
||||
return a, nil
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package threema
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/o3ma/o3"
|
||||
"gosrc.io/xmpp"
|
||||
)
|
||||
|
||||
func strFromThreemaGroup(header *o3.GroupMessageHeader) string {
|
||||
cid := strings.ToLower(header.CreatorID.String())
|
||||
gid := strings.ToLower(base32.StdEncoding.EncodeToString(header.GroupID[:]))
|
||||
return fmt.Sprintf("%s-%s", cid, gid)
|
||||
}
|
||||
func jidFromThreemaGroup(sender string, header *o3.GroupMessageHeader) string {
|
||||
return fmt.Sprintf("%s@{{DOMAIN}}/%s", strFromThreemaGroup(header), sender)
|
||||
}
|
||||
func jidToThreemaGroup(jidS string) (string, *o3.GroupMessageHeader) {
|
||||
jid, err := xmpp.NewJid(jidS)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
node := strings.ToUpper(jid.Node)
|
||||
a := strings.SplitN(node, "-", 2)
|
||||
if len(a) != 2 {
|
||||
return "", nil
|
||||
}
|
||||
header := &o3.GroupMessageHeader{
|
||||
CreatorID: o3.NewIDString(a[0]),
|
||||
}
|
||||
|
||||
result, err := base32.StdEncoding.DecodeString(a[1])
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
copy(header.GroupID[:], []byte(result))
|
||||
|
||||
return jid.Resource, header
|
||||
}
|
|
@ -68,11 +68,19 @@ func (t *Threema) Send(packet stanza.Packet) {
|
|||
func (t *Threema) send(packet stanza.Packet) stanza.Packet {
|
||||
switch p := packet.(type) {
|
||||
case stanza.Presence:
|
||||
log.Debug(p)
|
||||
from := models.ParseJID(p.Attrs.From)
|
||||
account, err := t.getAccount(from)
|
||||
if err != nil {
|
||||
msg := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, To: from.String()})
|
||||
msg.Body = "It was not possible to send, because we have no account for you.\nPlease generate one, by sending `generate` to this gateway"
|
||||
return msg
|
||||
}
|
||||
account.handlePresence(p)
|
||||
return nil
|
||||
case stanza.Message:
|
||||
from := models.ParseJID(p.Attrs.From)
|
||||
to := models.ParseJID(p.Attrs.To)
|
||||
|
||||
if p.Attrs.Type == stanza.MessageTypeError {
|
||||
msg := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, To: from.String()})
|
||||
if p.Error.Text == "User session not found" {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package threema
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
@ -9,16 +8,17 @@ import (
|
|||
|
||||
"github.com/bdlm/log"
|
||||
"github.com/o3ma/o3"
|
||||
"gosrc.io/xmpp"
|
||||
"gosrc.io/xmpp/stanza"
|
||||
)
|
||||
|
||||
func (a *Account) receiver(out chan<- stanza.Packet) {
|
||||
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)
|
||||
out <- xMSG
|
||||
a.xmpp <- xMSG
|
||||
continue
|
||||
}
|
||||
header := receivedMessage.Msg.Header()
|
||||
|
@ -26,12 +26,36 @@ func (a *Account) receiver(out chan<- stanza.Packet) {
|
|||
if string(a.TID) == sender {
|
||||
continue
|
||||
}
|
||||
if p, err := a.receiving(receivedMessage.Msg); err != nil {
|
||||
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)
|
||||
out <- xMSG
|
||||
} else if p != nil {
|
||||
out <- p
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,13 +66,7 @@ func requestExtensions(xMSG *stanza.Message) {
|
|||
xMSG.Extensions = append(xMSG.Extensions, stanza.StateActive{})
|
||||
}
|
||||
|
||||
func jidFromThreemaGroup(sender string, header *o3.GroupMessageHeader) string {
|
||||
cid := strings.ToLower(header.CreatorID.String())
|
||||
gid := strings.ToLower(base32.StdEncoding.EncodeToString(header.GroupID[:]))
|
||||
return fmt.Sprintf("%s-%s@{{DOMAIN}}/%s", cid, gid, sender)
|
||||
}
|
||||
|
||||
func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
||||
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{}{
|
||||
|
@ -62,53 +80,65 @@ func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
|||
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 {
|
||||
xMSG = stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeGroupchat, From: jidFromThreemaGroup(sender, msg.GroupMessageHeader), To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
||||
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)
|
||||
}
|
||||
xMSG.Body = msg.Body
|
||||
logger.WithFields(map[string]interface{}{
|
||||
"from_x": xMSG.From,
|
||||
"id": xMSG.Id,
|
||||
"text": xMSG.Body,
|
||||
}).Debug(dbText)
|
||||
return xMSG, nil
|
||||
return xMSG, msg.GroupMessageHeader, nil
|
||||
case *o3.AudioMessage:
|
||||
if a.threema.httpUploadPath == "" {
|
||||
return nil, errors.New("no place to store files at transport configurated")
|
||||
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, 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, err
|
||||
return nil, nil, err
|
||||
}
|
||||
requestExtensions(&xMSG)
|
||||
logger.WithField("url", xMSG.Body).Debug("recv audio")
|
||||
return xMSG, nil
|
||||
return xMSG, nil, nil
|
||||
|
||||
case *o3.ImageMessage:
|
||||
if a.threema.httpUploadPath == "" {
|
||||
return nil, errors.New("no place to store files at transport configurated")
|
||||
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, 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, err
|
||||
return nil, nil, err
|
||||
}
|
||||
requestExtensions(&xMSG)
|
||||
logger.WithField("url", xMSG.Body).Debug("recv image")
|
||||
return xMSG, nil
|
||||
return xMSG, nil, nil
|
||||
|
||||
case *o3.DeliveryReceiptMessage:
|
||||
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
||||
state := ""
|
||||
|
@ -135,9 +165,9 @@ func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
|||
|
||||
if len(xMSG.Extensions) > 0 {
|
||||
logger.WithField("state", state).Debug("recv state")
|
||||
return xMSG, nil
|
||||
return xMSG, nil, nil
|
||||
}
|
||||
return 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 {
|
||||
|
@ -146,7 +176,7 @@ func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
|||
xMSG.Extensions = append(xMSG.Extensions, stanza.StateInactive{})
|
||||
}
|
||||
logger.WithField("on", msg.OnOff).Debug("recv typing")
|
||||
return xMSG, nil
|
||||
return xMSG, nil, nil
|
||||
}
|
||||
return nil, errors.New("not known data format")
|
||||
return nil, nil, errors.New("not known data format")
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ func createDummyAccount() Account {
|
|||
a := Account{
|
||||
deliveredMSG: make(map[uint64]string),
|
||||
readedMSG: make(map[uint64]string),
|
||||
xmpp: make(chan<- stanza.Packet),
|
||||
}
|
||||
a.TID = make([]byte, len(threemaFromIDByte))
|
||||
copy(a.TID, threemaFromIDByte[:])
|
||||
|
|
|
@ -2,14 +2,73 @@ package threema
|
|||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/xml"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bdlm/log"
|
||||
"github.com/o3ma/o3"
|
||||
"gosrc.io/xmpp"
|
||||
"gosrc.io/xmpp/stanza"
|
||||
)
|
||||
|
||||
type PresMUCUserItem struct {
|
||||
XMLName xml.Name `xml:"item"`
|
||||
Affiliation string `xml:"affiliation,attr"`
|
||||
Role string `xml:"role,attr"`
|
||||
}
|
||||
type PresMUCUserStatus struct {
|
||||
XMLName xml.Name `xml:"status"`
|
||||
Code int `xml:"code,attr"`
|
||||
}
|
||||
|
||||
type PresMUCUserList struct {
|
||||
XMLName xml.Name `xml:"http://jabber.org/protocol/muc#user x"`
|
||||
Items []PresMUCUserItem
|
||||
Status *PresMUCUserStatus
|
||||
}
|
||||
|
||||
func (a *Account) handlePresence(p stanza.Presence) error {
|
||||
logger := log.WithFields(map[string]interface{}{
|
||||
"from": p.Attrs.From,
|
||||
"to": p.Attrs.To,
|
||||
})
|
||||
_, header := jidToThreemaGroup(p.To)
|
||||
if header == nil {
|
||||
logger.Debug("no group presence")
|
||||
return nil
|
||||
}
|
||||
|
||||
from, _ := xmpp.NewJid(p.From)
|
||||
to, _ := xmpp.NewJid(p.To)
|
||||
|
||||
if a.XMPPResource[to.Node] == nil {
|
||||
a.XMPPResource[to.Node] = make(map[string]bool)
|
||||
}
|
||||
a.XMPPResource[to.Node][from.Resource] = true
|
||||
|
||||
ownsender := strings.ToLower(a.ThreemaID.ID.String())
|
||||
//TODO list current users
|
||||
senders := []string{header.CreatorID.String(), ownsender}
|
||||
for _, sender := range senders {
|
||||
sender = strings.ToLower(sender)
|
||||
pres := stanza.NewPresence(stanza.Attrs{To: p.Attrs.From, From: jidFromThreemaGroup(sender, header)})
|
||||
presMUCUserList := PresMUCUserList{
|
||||
Items: []PresMUCUserItem{
|
||||
{
|
||||
Affiliation: "admin",
|
||||
Role: "moderator",
|
||||
},
|
||||
},
|
||||
}
|
||||
if sender == ownsender {
|
||||
presMUCUserList.Status = &PresMUCUserStatus{Code: 110}
|
||||
}
|
||||
pres.Extensions = append(pres.Extensions, presMUCUserList)
|
||||
a.xmpp <- pres
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (a *Account) Send(to string, msg stanza.Message) error {
|
||||
m, err := a.sending(to, msg)
|
||||
if err != nil {
|
||||
|
@ -125,6 +184,7 @@ func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
|||
if groupHeader != nil {
|
||||
logger.Debug("send grouptext")
|
||||
// TODO iterate of all occupants
|
||||
//msg3.GroupMessageHeader.Recipient: o3.NewIDString(to),
|
||||
return msg3, nil
|
||||
}
|
||||
a.deliveredMSG[msg3ID] = msg.Id
|
||||
|
|
Reference in New Issue