diff --git a/telegram/handlers.go b/telegram/handlers.go index 1ce1636..021280d 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -73,7 +73,7 @@ func (c *Client) sendMarker(chatId, messageId int64, typ gateway.MarkerType) { gateway.SendMessageMarker( c.jid, - strconv.FormatInt(chatId, 10), + gateway.CHATNODE(chatId), c.xmpp, typ, xmppId, @@ -390,6 +390,12 @@ func (c *Client) updateDeleteMessages(update *client.UpdateDeleteMessages) { } } + var isGroupchat bool + chat, _, _ := c.GetContactByID(update.ChatId, nil) + if c.Session.MUC && c.IsGroup(chat) { + isGroupchat = true + } + var deleteChar string if c.Session.AsciiArrows { deleteChar = "X " @@ -397,7 +403,13 @@ func (c *Client) updateDeleteMessages(update *client.UpdateDeleteMessages) { deleteChar = "✗ " } text := deleteChar + strings.Join(int64SliceToStringSlice(update.MessageIds), ",") - gateway.SendTextMessage(c.jid, strconv.FormatInt(update.ChatId, 10), text, c.xmpp) + var fromJid string + if isGroupchat { + fromJid = gateway.MUCJID(update.ChatId) + } else { + fromJid = gateway.CHATNODE(update.ChatId) + } + gateway.SendTextMessage(c.jid, fromJid, text, c.xmpp, isGroupchat) } } @@ -443,7 +455,7 @@ func (c *Client) updateChatTitle(update *client.UpdateChatTitle) { return } - gateway.SetNickname(c.jid, strconv.FormatInt(update.ChatId, 10), update.Title, c.xmpp) + gateway.SetNickname(c.jid, gateway.CHATNODE(update.ChatId), update.Title, c.xmpp) // set also the status (for group chats only) if user == nil { diff --git a/telegram/utils.go b/telegram/utils.go index ee3bc8b..c911001 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -459,14 +459,13 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o } c.locks.mucCacheLock.Lock() - chatJid := strconv.FormatInt(chatID, 10) + "@" + gateway.Jid.Full() + chatJid := gateway.CHATJID(chatID, true) for mucId, state := range c.mucCache { member, ok := state.Members[chatID] if ok { - sMucId := strconv.FormatInt(mucId, 10) newMucArgs := append( newArgs, - gateway.SPFrom(sMucId), + gateway.SPFrom(gateway.MUCNODE(mucId)), gateway.SPResource(member.Nickname), gateway.SPMUCAffiliation(member.Affiliation), gateway.SPMUCJid(chatJid), @@ -529,7 +528,7 @@ func (c *Client) sendMUCStatuses(chatID int64) { c.mucCache[chatID] = mucState } - sChatId := strconv.FormatInt(chatID, 10) + sChatId := gateway.MUCNODE(chatID) myNickname := "me" if c.me != nil { myNickname = c.getFullName(c.me) @@ -542,8 +541,6 @@ func (c *Client) sendMUCStatuses(chatID int64) { Filter: &client.ChatMembersFilterMembers{}, }) if err == nil { - gatewayJidSuffix := "@" + gateway.Jid.Full() - for _, member := range members.Members { var senderId int64 switch member.MemberId.MessageSenderType() { @@ -573,7 +570,7 @@ func (c *Client) sendMUCStatuses(chatID int64) { gateway.SPResource(nickname), gateway.SPImmed(true), gateway.SPMUCAffiliation(affiliation), - gateway.SPMUCJid(strconv.FormatInt(senderId, 10) + gatewayJidSuffix), + gateway.SPMUCJid(gateway.CHATJID(senderId, true)), ) } } @@ -592,7 +589,7 @@ func (c *Client) sendMUCSubject(chatID int64, resource string) { pin, err := c.client.GetChatPinnedMessage(&client.GetChatPinnedMessageRequest{ ChatId: chatID, }) - mucJid := strconv.FormatInt(chatID, 10) + "@" + gateway.Jid.Bare() + mucJid := gateway.MUCJID(chatID) toJid := c.jid + "/" + resource if err == nil { gateway.SendSubjectMessage( @@ -617,7 +614,7 @@ func (c *Client) updateMUCsNickname(memberID int64, newNickname string) { c.locks.mucCacheLock.Lock() defer c.locks.mucCacheLock.Unlock() - realJid := strconv.FormatInt(memberID, 10) + "@" + gateway.Jid.Full() + realJid := gateway.CHATJID(memberID, true) for mucId, state := range c.mucCache { oldMember, ok := state.Members[memberID] if ok { @@ -626,7 +623,7 @@ func (c *Client) updateMUCsNickname(memberID int64, newNickname string) { Affiliation: oldMember.Affiliation, } - sMucId := strconv.FormatInt(mucId, 10) + sMucId := gateway.MUCNODE(mucId) unavailableStatusCodes := []uint16{303, 210} availableStatusCodes := []uint16{100, 210} if c.me != nil && memberID == c.me.Id { @@ -1445,7 +1442,7 @@ func (c *Client) SendMessageToGateway(chatId int64, message *client.Message, id senderId := c.getMessageSenderId(message) if senderId != 0 { - originalFrom = strconv.FormatInt(senderId, 10) + "@" + gateway.Jid.Full() + originalFrom = gateway.CHATJID(senderId, true) } } @@ -1552,7 +1549,7 @@ func (c *Client) SendMessageToGateway(chatId int64, message *client.Message, id var from string if groupChatFrom == "" { - from = strconv.FormatInt(chatId, 10) + from = gateway.CHATNODE(chatId) } else { from = groupChatFrom } @@ -1693,11 +1690,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str } func (c *Client) returnMessage(returnJid string, chatID int64, text string, code int, isGroupchat bool) { - sChatId := strconv.FormatInt(chatID, 10) if isGroupchat { - gateway.SendErrorMessage(returnJid, sChatId + "@" + gateway.Jid.Bare(), text, code, isGroupchat, c.xmpp) + gateway.SendErrorMessage(returnJid, gateway.MUCJID(chatID), text, code, isGroupchat, c.xmpp) } else { - gateway.SendTextMessage(returnJid, sChatId, text, c.xmpp) + gateway.SendTextMessage(returnJid, gateway.CHATNODE(chatID), text, c.xmpp, isGroupchat) } } @@ -2005,7 +2001,7 @@ func (c *Client) subscribeToID(id int64, chat *client.Chat) { args = append(args, gateway.SPNickname(chat.Title)) - gateway.SetNickname(c.jid, strconv.FormatInt(id, 10), chat.Title, c.xmpp) + gateway.SetNickname(c.jid, gateway.CHATNODE(id), chat.Title, c.xmpp) } c.sendPresence(args...) @@ -2080,7 +2076,7 @@ func (c *Client) UpdateChatNicknames() { c.sendPresence(newArgs...) - gateway.SetNickname(c.jid, strconv.FormatInt(id, 10), chat.Title, c.xmpp) + gateway.SetNickname(c.jid, gateway.CHATNODE(id), chat.Title, c.xmpp) } } } @@ -2240,10 +2236,10 @@ func (c *Client) memberStatusToAffiliation(memberStatus client.ChatMemberStatus) } func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message, plain bool, toJid string) { - sChatId := strconv.FormatInt(chatID, 10) + sChatId := gateway.CHATNODE(chatID) var mucJid string if toJid != "" { - mucJid = sChatId + "@" + gateway.Jid.Bare() + mucJid = gateway.MUCJID(chatID) } for i := len(messages) - 1; i >= 0; i-- { diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 990ba42..255fd76 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -61,6 +61,32 @@ var DirtySessions = false // MessageOutgoingPermissionVersion contains a XEP-0356 version to fake outgoing messages by foreign JIDs var MessageOutgoingPermissionVersion = 0 +// CHATNODE converts numeric id to node part of 1-1 chat JID +func CHATNODE(chatId int64) string { + return strconv.FormatInt(chatId, 10) +} + +// CHATJID converts numeric id to 1-1 chat JID +func CHATJID(chatId int64, full bool) string { + var suffix string + if full { + suffix = Jid.Full() + } else { + suffix = Jid.Bare() + } + return CHATNODE(chatId) + "@" + suffix +} + +// MUCNODE converts numeric id to node part of MUC JID +func MUCNODE(chatId int64) string { + return "c" + CHATNODE(chatId) +} + +// MUCJID converts numeric id to MUC JID +func MUCJID(chatId int64) string { + return "c" + CHATJID(chatId, false) +} + // SendMessage creates and sends a message stanza func SendMessage(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom string) { sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, "", replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "") @@ -76,12 +102,12 @@ func SendServiceMessage(to, body string, component *xmpp.Component) { } // SendTextMessage creates and sends a simple message stanza -func SendTextMessage(to, from, body string, component *xmpp.Component) { +func SendTextMessage(to, from, body string, component *xmpp.Component, isGroupchat bool) { var id string if uuid, err := uuid.NewRandom(); err == nil { id = uuid.String() } - sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0, "") + sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", 0, "") } // SendErrorMessage creates and sends an error message stanza @@ -536,7 +562,7 @@ func SendPresence(component *xmpp.Component, to string, args ...args.V) error { // SPAppendFrom appends numeric from and resource to varargs func SPAppendFrom(oldArgs []args.V, id int64) []args.V { - newArgs := append(oldArgs, SPFrom(strconv.FormatInt(id, 10))) + newArgs := append(oldArgs, SPFrom(CHATNODE(id))) newArgs = append(newArgs, SPResource(Jid.Resource)) return newArgs } @@ -626,7 +652,7 @@ func SendPubSubAvatarNotification(component *xmpp.Component, jid string, chatId message := stanza.Message{ Attrs: stanza.Attrs{ - From: strconv.FormatInt(chatId, 10) + "@" + Jid.Bare(), + From: CHATJID(chatId, false), To: jid, Type: stanza.MessageTypeHeadline, }, @@ -637,6 +663,5 @@ func SendPubSubAvatarNotification(component *xmpp.Component, jid string, chatId } func InviteToMUC(chatID int64, jid string, component *xmpp.Component) { - sChatID := strconv.FormatInt(chatID, 10) - SendMUCInvite(jid, sChatID, component, Jid.Full()) + SendMUCInvite(jid, MUCNODE(chatID), component, Jid.Full()) } diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 2f3cb0a..506d9e6 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -128,7 +128,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { return } - toID, ok := toToID(msg.To) + toID, ok, toIsGroup := toToID(msg.To) if ok { toJid, err := stanza.NewJid(msg.To) if err != nil { @@ -138,15 +138,22 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { isGroupchat := msg.Type == "groupchat" - if session.Session.MUC && toJid.Resource != "" { + if session.Session.MUC { chat, _, err := session.GetContactByID(toID, nil) if err == nil && session.IsGroup(chat) { - if isGroupchat { - gateway.SendErrorMessageWithBody(msg.From, msg.To, msg.Body, "", msg.Id, 400, true, component) - } else { - gateway.SendErrorMessage(msg.From, msg.To, "PMing room members is not supported, use the real JID", 406, true, component) + if !toIsGroup { + gateway.SendErrorMessage(msg.From, toJid.Node, "KHVATIT SYUDA ZVONITb", 403, false, component) + return + } + + if toJid.Resource != "" { + if isGroupchat { + gateway.SendErrorMessageWithBody(msg.From, msg.To, msg.Body, "", msg.Id, 400, true, component) + } else { + gateway.SendErrorMessage(msg.From, msg.To, "PMing room members is not supported, use the real JID", 406, true, component) + } + return } - return } } @@ -210,13 +217,21 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { chatId, msgId, err := gateway.IdsDB.GetByXmppId(session.Session.Login, bare, replace.Id) if err == nil { if chatId != toID { - gateway.SendTextMessage(msg.From, strconv.FormatInt(toID, 10), "", component) + if isGroupchat { + gateway.SendErrorMessage(msg.From, gateway.MUCJID(toID), text, 400, isGroupchat, component) + } else { + gateway.SendTextMessage(msg.From, gateway.CHATNODE(toID), "", component, isGroupchat) + } return } replaceId = msgId log.Debugf("replace tg: %#v %#v", chatId, msgId) } else { - gateway.SendTextMessage(msg.From, strconv.FormatInt(toID, 10), "", component) + if isGroupchat { + gateway.SendErrorMessage(msg.From, gateway.MUCJID(toID), text, 400, isGroupchat, component) + } else { + gateway.SendTextMessage(msg.From, gateway.CHATNODE(toID), "", component, isGroupchat) + } return } } @@ -313,7 +328,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { if !ok { return } - toID, ok := toToID(msg.To) + toID, ok, _ := toToID(msg.To) if !ok { return } @@ -385,7 +400,7 @@ func handleSubscription(s xmpp.Sender, p stanza.Presence) { _ = gateway.ResumableSend(component, reply) - toID, ok := toToID(p.To) + toID, ok, _ := toToID(p.To) if !ok { return } @@ -502,8 +517,8 @@ func handleMUCPresence(s xmpp.Sender, p stanza.Presence, mucExt stanza.MucPresen return } - chatId, ok := toToID(toBare) - if !ok { + chatId, ok, toIsGroup := toToID(toBare) + if !ok || !toIsGroup { presenceReplySetError(reply, 404) return } @@ -562,8 +577,8 @@ func tryHandleMUCNicknameChange(s xmpp.Sender, p stanza.Presence) { return } - chatId, ok := toToID(toBare) - if !ok { + chatId, ok, toIsGroup := toToID(toBare) + if !ok || !toIsGroup { return } @@ -663,7 +678,7 @@ func handleGetAvatarDataIq(s xmpp.Sender, iq *stanza.IQ, pubsub *stanza.PubSubGe return } - chatId, ok := toToID(iq.To) + chatId, ok, _ := toToID(iq.To) if !ok { log.Errorf("Invalid chat id in To JID %v", iq.To) return @@ -764,7 +779,7 @@ func handleGetAvatarDataIq(s xmpp.Sender, iq *stanza.IQ, pubsub *stanza.PubSubGe } func getTelegramChatType(from string, to string) (telegram.ChatType, error) { - toId, ok := toToID(to) + toId, ok, _ := toToID(to) if ok { bare, _, ok := gateway.SplitJID(from) if ok { @@ -809,14 +824,14 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoInfo) { defer gateway.ResumableSend(component, answer) disco := answer.DiscoInfo() - toID, toOk := toToID(iq.To) + toID, toOk, toIsGroup := toToID(iq.To) if di.Node == "" { var isMuc bool bare, _, fromOk := gateway.SplitJID(iq.From) if fromOk { session, sessionOk := sessions[bare] - if sessionOk && session.Session.MUC { + if sessionOk && session.Session.MUC && toIsGroup { if toOk { chat, _, err := session.GetContactByID(toID, nil) if err == nil && session.IsGroup(chat) { @@ -907,7 +922,7 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) { log.Debugf("discoItems: %#v", di) - toID, toOk := toToID(iq.To) + toID, toOk, _ := toToID(iq.To) disco := answer.DiscoItems() @@ -959,10 +974,9 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) { // raw access, no need to create a new instance if not connected session, sessionOk := sessions[bare] if sessionOk && session.Session.MUC { - bareJid := gateway.Jid.Bare() - disco.AddItem(bareJid, "", "Telegram group chats") + disco.AddItem(gateway.Jid.Bare(), "", "Telegram group chats") for _, chat := range session.GetGroupChats() { - jid := strconv.FormatInt(chat.Id, 10) + "@" + bareJid + jid := gateway.MUCJID(chat.Id) disco.AddItem(jid, "", chat.Title) } } @@ -1085,7 +1099,7 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command if !ok { return } - toId, toOk := toToID(iq.To) + toId, toOk, _ := toToID(iq.To) var cmdString string var cmdType telegram.CommandType @@ -1603,19 +1617,25 @@ func sendPubSubAvatarNotifications(s xmpp.Sender, jid string, session *telegram. } } -func toToID(to string) (int64, bool) { +func toToID(to string) (int64, bool, bool) { + var isGroup bool toParts := strings.Split(to, "@") if len(toParts) < 2 { - return 0, false + return 0, false, isGroup } - toID, err := strconv.ParseInt(toParts[0], 10, 64) + node := toParts[0] + if strings.HasPrefix(node, "c") { + isGroup = true + node = node[1:] + } + toID, err := strconv.ParseInt(node, 10, 64) if err != nil { log.WithFields(log.Fields{ "to": to, }).Error(errors.Wrap(err, "Invalid to JID!")) - return 0, false + return 0, false, isGroup } - return toID, true + return toID, true, isGroup } func makeVCardPayload(typ byte, id string, info telegram.VCardInfo, session *telegram.Client) stanza.IQPayload {