group message support - WIP
This commit is contained in:
parent
b535a6f685
commit
887d6ac3ff
|
@ -4,4 +4,5 @@
|
||||||
branch = fixtests
|
branch = fixtests
|
||||||
[submodule "vendor/gosrc.io/xmpp"]
|
[submodule "vendor/gosrc.io/xmpp"]
|
||||||
path = vendor/gosrc.io/xmpp
|
path = vendor/gosrc.io/xmpp
|
||||||
url = https://github.com/FluuxIO/go-xmpp.git
|
url = https://github.com/genofire/go-xmpp.git
|
||||||
|
branch = fix-component
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package component
|
package component
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/bdlm/log"
|
||||||
"gosrc.io/xmpp"
|
"gosrc.io/xmpp"
|
||||||
"gosrc.io/xmpp/stanza"
|
"gosrc.io/xmpp/stanza"
|
||||||
)
|
)
|
||||||
|
@ -17,10 +18,10 @@ type Config struct {
|
||||||
comp Component
|
comp Component
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Start() (err error) {
|
func (c *Config) Start() error {
|
||||||
out, err := c.comp.Connect()
|
out, err := c.comp.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
router := xmpp.NewRouter()
|
router := xmpp.NewRouter()
|
||||||
|
@ -38,10 +39,14 @@ func (c *Config) Start() (err error) {
|
||||||
Type: "service",
|
Type: "service",
|
||||||
}, router)
|
}, router)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
cm := xmpp.NewStreamManager(c.xmpp, nil)
|
cm := xmpp.NewStreamManager(c.xmpp, nil)
|
||||||
go cm.Run()
|
go func() {
|
||||||
|
if err := cm.Run(); err != nil {
|
||||||
|
log.WithField("host", c.Host).Panicf("xmpp stream not started: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
go c.sender(out)
|
go c.sender(out)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -43,7 +43,7 @@ func (c *Config) handleDiscoInfo(s xmpp.Sender, p stanza.Packet) {
|
||||||
iq.Payload = &payload
|
iq.Payload = &payload
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]interface{}{
|
||||||
"type": c.Type,
|
"type": c.Type,
|
||||||
"from": s,
|
"from": attrs.From,
|
||||||
"to": attrs.To,
|
"to": attrs.To,
|
||||||
}).Debug("disco info")
|
}).Debug("disco info")
|
||||||
s.Send(iq)
|
s.Send(iq)
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package component
|
package component
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/bdlm/log"
|
"github.com/bdlm/log"
|
||||||
"gosrc.io/xmpp/stanza"
|
"gosrc.io/xmpp/stanza"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) sender(packets chan stanza.Packet) {
|
func (c *Config) sender(packets chan stanza.Packet) {
|
||||||
|
log.Debugf("start xmpp sender for: %s", c.Host)
|
||||||
for packet := range packets {
|
for packet := range packets {
|
||||||
if p := c.sending(packet); p != nil {
|
if p := c.sending(packet); p != nil {
|
||||||
c.xmpp.Send(p)
|
c.xmpp.Send(p)
|
||||||
|
@ -19,6 +22,8 @@ func (c *Config) sending(packet stanza.Packet) stanza.Packet {
|
||||||
case stanza.Message:
|
case stanza.Message:
|
||||||
if p.From == "" {
|
if p.From == "" {
|
||||||
p.From = c.Host
|
p.From = c.Host
|
||||||
|
} else if strings.Contains(p.From, "{{DOMAIN}}") {
|
||||||
|
p.From = strings.Replace(p.From, "{{DOMAIN}}", c.Host, 1)
|
||||||
} else {
|
} else {
|
||||||
p.From += "@" + c.Host
|
p.From += "@" + c.Host
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
type Account struct {
|
type Account struct {
|
||||||
models.AccountThreema
|
models.AccountThreema
|
||||||
threema *Threema
|
threema *Threema
|
||||||
Session o3.SessionContext
|
ThreemaID *o3.ThreemaID
|
||||||
send chan<- o3.Message
|
send chan<- o3.Message
|
||||||
receive <-chan o3.ReceivedMsg
|
receive <-chan o3.ReceivedMsg
|
||||||
deliveredMSG map[uint64]string
|
deliveredMSG map[uint64]string
|
||||||
|
@ -46,10 +46,11 @@ func (t *Threema) getAccount(jid *models.JID) (*Account, error) {
|
||||||
|
|
||||||
a := &Account{
|
a := &Account{
|
||||||
AccountThreema: account,
|
AccountThreema: account,
|
||||||
Session: o3.NewSessionContext(tid),
|
ThreemaID: &tid,
|
||||||
threema: t,
|
threema: t,
|
||||||
}
|
}
|
||||||
a.send, a.receive, err = a.Session.Run()
|
session := o3.NewSessionContext(tid)
|
||||||
|
a.send, a.receive, err = session.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -70,7 +70,13 @@ func (t *Threema) send(packet stanza.Packet) stanza.Packet {
|
||||||
case stanza.Message:
|
case stanza.Message:
|
||||||
from := models.ParseJID(p.Attrs.From)
|
from := models.ParseJID(p.Attrs.From)
|
||||||
to := models.ParseJID(p.Attrs.To)
|
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" {
|
||||||
|
msg.Body = "please join groupchat xmpp:" + to.String() + "?join"
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
if to.IsDomain() {
|
if to.IsDomain() {
|
||||||
if from == nil {
|
if from == nil {
|
||||||
log.Warn("receive message without sender")
|
log.Warn("receive message without sender")
|
||||||
|
@ -87,6 +93,13 @@ func (t *Threema) send(packet stanza.Packet) stanza.Packet {
|
||||||
msg.Body = "It was not possible to send, because we have no account for you.\nPlease generate one, by sending `generate` to this gateway"
|
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
|
return msg
|
||||||
}
|
}
|
||||||
|
if to == nil {
|
||||||
|
log.WithFields(map[string]interface{}{
|
||||||
|
"from": from,
|
||||||
|
"to": to,
|
||||||
|
}).Panicf("no to found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
threemaID := strings.ToUpper(to.Local)
|
threemaID := strings.ToUpper(to.Local)
|
||||||
if err := account.Send(threemaID, p); err != nil {
|
if err := account.Send(threemaID, p); err != nil {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package threema
|
package threema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base32"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/bdlm/log"
|
"github.com/bdlm/log"
|
||||||
"github.com/o3ma/o3"
|
"github.com/o3ma/o3"
|
||||||
|
@ -40,15 +42,29 @@ func requestExtensions(xMSG *stanza.Message) {
|
||||||
xMSG.Extensions = append(xMSG.Extensions, stanza.StateActive{})
|
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, error) {
|
||||||
header := receivedMessage.Header()
|
header := receivedMessage.Header()
|
||||||
sender := header.Sender.String()
|
sender := header.Sender.String()
|
||||||
logger := log.WithFields(map[string]interface{}{
|
logger := log.WithFields(map[string]interface{}{
|
||||||
"from": header.Sender.String(),
|
"from": sender,
|
||||||
|
"to_t": header.Recipient.String(),
|
||||||
"to": a.XMPP.String(),
|
"to": a.XMPP.String(),
|
||||||
})
|
})
|
||||||
|
sender = strings.ToLower(sender)
|
||||||
switch msg := receivedMessage.(type) {
|
switch msg := receivedMessage.(type) {
|
||||||
case o3.TextMessage:
|
case *o3.GroupTextMessage:
|
||||||
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeGroupchat, From: jidFromThreemaGroup(sender, msg.GroupMessageHeader), To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
||||||
|
xMSG.Body = msg.Body
|
||||||
|
requestExtensions(&xMSG)
|
||||||
|
logger.WithField("text", xMSG.Body).Debug("send text")
|
||||||
|
return xMSG, nil
|
||||||
|
case *o3.TextMessage:
|
||||||
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
||||||
xMSG.Body = msg.Body
|
xMSG.Body = msg.Body
|
||||||
requestExtensions(&xMSG)
|
requestExtensions(&xMSG)
|
||||||
|
@ -93,7 +109,7 @@ func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
||||||
logger.WithField("url", xMSG.Body).Debug("send image")
|
logger.WithField("url", xMSG.Body).Debug("send image")
|
||||||
return xMSG, nil
|
return xMSG, nil
|
||||||
*/
|
*/
|
||||||
case o3.DeliveryReceiptMessage:
|
case *o3.DeliveryReceiptMessage:
|
||||||
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String()})
|
||||||
state := ""
|
state := ""
|
||||||
|
|
||||||
|
@ -122,15 +138,14 @@ func (a *Account) receiving(receivedMessage o3.Message) (stanza.Packet, error) {
|
||||||
return xMSG, nil
|
return xMSG, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case o3.TypingNotificationMessage:
|
case *o3.TypingNotificationMessage:
|
||||||
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
xMSG := stanza.NewMessage(stanza.Attrs{Type: stanza.MessageTypeChat, From: sender, To: a.XMPP.String(), Id: strconv.FormatUint(header.ID, 10)})
|
||||||
if msg.OnOff != 0 {
|
if msg.OnOff != 0 {
|
||||||
logger.Debug("composing")
|
|
||||||
xMSG.Extensions = append(xMSG.Extensions, stanza.StateComposing{})
|
xMSG.Extensions = append(xMSG.Extensions, stanza.StateComposing{})
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("inactive")
|
|
||||||
xMSG.Extensions = append(xMSG.Extensions, stanza.StateInactive{})
|
xMSG.Extensions = append(xMSG.Extensions, stanza.StateInactive{})
|
||||||
}
|
}
|
||||||
|
logger.Debug(msg.String())
|
||||||
return xMSG, nil
|
return xMSG, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("not known data format")
|
return nil, errors.New("not known data format")
|
||||||
|
|
|
@ -19,12 +19,14 @@ func (a *Account) Send(to string, msg stanza.Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
||||||
|
from := string(a.AccountThreema.TID)
|
||||||
logger := log.WithFields(map[string]interface{}{
|
logger := log.WithFields(map[string]interface{}{
|
||||||
"from": a.XMPP.String(),
|
"from": a.XMPP.String(),
|
||||||
|
"from_t": from,
|
||||||
"to": to,
|
"to": to,
|
||||||
})
|
})
|
||||||
msg3To := o3.NewIDString(to)
|
msg3To := o3.NewIDString(to)
|
||||||
msg3From := o3.NewIDString(string(a.AccountThreema.TID))
|
msg3From := o3.NewIDString(from)
|
||||||
|
|
||||||
chatState := false
|
chatState := false
|
||||||
chatStateComposing := false
|
chatStateComposing := false
|
||||||
|
@ -63,11 +65,12 @@ func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
drm := o3.DeliveryReceiptMessage{
|
drm := &o3.DeliveryReceiptMessage{
|
||||||
MessageHeader: &o3.MessageHeader{
|
MessageHeader: &o3.MessageHeader{
|
||||||
Sender: msg3From,
|
Sender: msg3From,
|
||||||
ID: id,
|
ID: id,
|
||||||
Recipient: msg3To,
|
Recipient: msg3To,
|
||||||
|
PubNick: a.ThreemaID.Nick,
|
||||||
},
|
},
|
||||||
Status: o3.MSGDELIVERED,
|
Status: o3.MSGDELIVERED,
|
||||||
}
|
}
|
||||||
|
@ -81,9 +84,11 @@ func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
||||||
return drm, nil
|
return drm, nil
|
||||||
}
|
}
|
||||||
if chatState {
|
if chatState {
|
||||||
tnm := o3.TypingNotificationMessage{
|
tnm := &o3.TypingNotificationMessage{
|
||||||
MessageHeader: &o3.MessageHeader{
|
MessageHeader: &o3.MessageHeader{
|
||||||
Sender: o3.NewIDString(string(a.AccountThreema.TID)),
|
Sender: msg3From,
|
||||||
|
Recipient: msg3To,
|
||||||
|
PubNick: a.ThreemaID.Nick,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if chatStateComposing {
|
if chatStateComposing {
|
||||||
|
@ -91,18 +96,19 @@ func (a *Account) sending(to string, msg stanza.Message) (o3.Message, error) {
|
||||||
}
|
}
|
||||||
logger.WithFields(map[string]interface{}{
|
logger.WithFields(map[string]interface{}{
|
||||||
"state": chatStateComposing,
|
"state": chatStateComposing,
|
||||||
}).Debug("not send typing")
|
}).Debug("send typing")
|
||||||
return nil, nil
|
return tnm, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg3ID := o3.NewMsgID()
|
msg3ID := o3.NewMsgID()
|
||||||
|
|
||||||
// send text message
|
// send text message
|
||||||
msg3 := o3.TextMessage{
|
msg3 := &o3.TextMessage{
|
||||||
MessageHeader: &o3.MessageHeader{
|
MessageHeader: &o3.MessageHeader{
|
||||||
Sender: o3.NewIDString(string(a.AccountThreema.TID)),
|
Sender: o3.NewIDString(string(a.AccountThreema.TID)),
|
||||||
ID: msg3ID,
|
ID: msg3ID,
|
||||||
Recipient: msg3To,
|
Recipient: msg3To,
|
||||||
|
PubNick: a.ThreemaID.Nick,
|
||||||
},
|
},
|
||||||
Body: msg.Body,
|
Body: msg.Body,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0c0e14982ac6e2886901faef423ed731911b3b39
|
Subproject commit 2f9fc2c25d42892f10eff4c22e8b14fa12f7c39e
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8794ea6ed8e17c357c7398adef3e84838b2f9b87
|
Subproject commit 294fe3d7148eefdb27515b465e767b88c290885d
|
Reference in New Issue