o3ma/o3

Post message to group

Closed this issue · 1 comments

I am using your library to write a bot which is meant to work inside a Threema group. Therefore I need to be able to dispatch group text messages. There is a method in place called SendGroupTextMessage expecting a Group as parameter. I could not find a way to get a hold of an appropriate group object, still I tried facilitating one by hand (see below).

case o3.GroupTextMessage:
	fmt.Println("Got group message", msg.Text())
	var members []o3.IDString
	group := o3.Group{
		CreatorID: msg.GroupCreator(),
		GroupID:   msg.GroupID(),
		Name:      "Testgruppe",
		Members:   append(members, o3.NewIDString(rid), o3.NewIDString(rid2))
        }
	ctx.SendGroupTextMessage(group, "Response", sendMsgChan)

Yet, with this setup, when my bot respondes, the messages get delivered to the members individually. They are not being posted into the correct group chat. Now, I've looked at the code for group text messages and promptly found the creation of the individual messages here:

in o3/messagetypes.go

// NewGroupTextMessages returns a slice of GroupMemberTextMessages ready to be encrypted
func NewGroupTextMessages(sc *SessionContext, group Group, text string) ([]GroupTextMessage, error) {
	gtm := make([]GroupTextMessage, len(group.Members))
	var tm TextMessage
	var err error

	for i, member := range group.Members {
		tm, err = NewTextMessage(sc, member.String(), text)
		if err != nil {
			return []GroupTextMessage{}, err
		}

		gtm[i] = GroupTextMessage{
			groupMessageHeader{
				creatorID: group.CreatorID,
				groupID:   group.GroupID},
			tm}
	}

	return gtm, nil

}

I think that due to Threema's security concept, it may be mandatory to compose individual messages for every group member. The clients will probably assign the messages to groups by using the groupMessageHeaders. However, as I looked further through the code, I discovered that these essential headers are left out during the actual message dispatchment, as to be seen below

in o3/packetdispatcher.go

func (sc *SessionContext) dispatchMessage(wr io.Writer, m Message) {
	mh := m.header()
        ...
	messagePkt := messagePacket{
		PktType:    sendingMsg,
		Sender:     mh.sender,
		Recipient:  mh.recipient,
		ID:         mh.id,
		Time:       mh.time,
		Flags:      msgFlags{PushMessage: true},
		PubNick:    mh.pubNick,
		Nonce:      randNonce,
		Ciphertext: msgCipherText,
	}
        ...
}

Am I missing something or are the headers really lost during dispatch, thus preventing sending of proper group messages? Otherwise I'd really like to know how to change my code so that I can post into groups somehow. Furthermore it would be really nice to have a way for retrieving group members programmatically.

Thanks :)

EDIT
So, apparently there was a serializer in place which could serialize group text messages appropriately. Unfortunately, this serializer would not be called but instead the one for plain text messages would be used. I have overridden the Serialize() call for group text messages to use the correct one now. Please review my corresponding pull request.

Sorry, for the late response! I was offline for the last two weeks...
It looks like you indeed found the problem and wrote the appropriate fix.
I'm a little bit confused because I was pretty sure we tested the group messaging, but it really couldn't have worked without the proper "Serialize" method.
Thank you for your contribution! :)