|
|
@ -44,6 +44,12 @@ var replyRegex = regexp.MustCompile("\\A>>? ?([0-9]+)\\n")
|
|
|
|
const newlineChar string = "\n"
|
|
|
|
const newlineChar string = "\n"
|
|
|
|
const messageHeaderSeparator string = " | "
|
|
|
|
const messageHeaderSeparator string = " | "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
|
|
ChatTypeOther byte = iota
|
|
|
|
|
|
|
|
ChatTypePM
|
|
|
|
|
|
|
|
ChatTypeGroup
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// GetContactByUsername resolves username to user id retrieves user and chat information
|
|
|
|
// GetContactByUsername resolves username to user id retrieves user and chat information
|
|
|
|
func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) {
|
|
|
|
func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) {
|
|
|
|
if !c.Online() {
|
|
|
|
if !c.Online() {
|
|
|
@ -121,10 +127,10 @@ func (c *Client) GetContactByID(id int64, chat *client.Chat) (*client.Chat, *cli
|
|
|
|
return chat, user, nil
|
|
|
|
return chat, user, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsPM checks if a chat is PM
|
|
|
|
// GetChatType checks if a chat is PM or group
|
|
|
|
func (c *Client) IsPM(id int64) (bool, error) {
|
|
|
|
func (c *Client) GetChatType(id int64) (byte, error) {
|
|
|
|
if !c.Online() || id == 0 {
|
|
|
|
if !c.Online() || id == 0 {
|
|
|
|
return false, errOffline
|
|
|
|
return ChatTypeOther, errOffline
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
var err error
|
|
|
@ -135,7 +141,7 @@ func (c *Client) IsPM(id int64) (bool, error) {
|
|
|
|
ChatId: id,
|
|
|
|
ChatId: id,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
return ChatTypeOther, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.cache.SetChat(id, chat)
|
|
|
|
c.cache.SetChat(id, chat)
|
|
|
@ -143,9 +149,12 @@ func (c *Client) IsPM(id int64) (bool, error) {
|
|
|
|
|
|
|
|
|
|
|
|
chatType := chat.Type.ChatTypeType()
|
|
|
|
chatType := chat.Type.ChatTypeType()
|
|
|
|
if chatType == client.TypeChatTypePrivate || chatType == client.TypeChatTypeSecret {
|
|
|
|
if chatType == client.TypeChatTypePrivate || chatType == client.TypeChatTypeSecret {
|
|
|
|
return true, nil
|
|
|
|
return ChatTypePM, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.IsGroup(chat) {
|
|
|
|
|
|
|
|
return ChatTypeGroup, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
return ChatTypeOther, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) userStatusToText(status client.UserStatus, chatID int64) (string, string, string) {
|
|
|
|
func (c *Client) userStatusToText(status client.UserStatus, chatID int64) (string, string, string) {
|
|
|
@ -217,6 +226,10 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if chat != nil && c.Session.MUC && c.IsGroup(chat) {
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var photo string
|
|
|
|
var photo string
|
|
|
|
if chat != nil && chat.Photo != nil {
|
|
|
|
if chat != nil && chat.Photo != nil {
|
|
|
|
file, path, err := c.ForceOpenFile(chat.Photo.Small, 1)
|
|
|
|
file, path, err := c.ForceOpenFile(chat.Photo.Small, 1)
|
|
|
@ -290,6 +303,214 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// JoinMUC saves MUC join fact and sends initialization data
|
|
|
|
|
|
|
|
func (c *Client) JoinMUC(chatId int64, resource string, limit int32) {
|
|
|
|
|
|
|
|
// save the nickname in this MUC, also as a marker of join
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Lock()
|
|
|
|
|
|
|
|
mucState, ok := c.mucCache[chatId]
|
|
|
|
|
|
|
|
if !ok || mucState == nil {
|
|
|
|
|
|
|
|
mucState = NewMUCState()
|
|
|
|
|
|
|
|
c.mucCache[chatId] = mucState
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_, ok = mucState.Resources[resource]
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
// already joined, initializing anyway
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
mucState.Resources[resource] = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.sendMUCStatuses(chatId)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
messages, err := c.getNLastMessages(chatId, limit)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
c.sendMessagesReverse(chatId, messages, false, c.jid+"/"+resource)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.sendMUCSubject(chatId, resource)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) getFullName(user *client.User) string {
|
|
|
|
|
|
|
|
fullName := user.FirstName
|
|
|
|
|
|
|
|
if user.LastName != "" {
|
|
|
|
|
|
|
|
fullName = fullName + " " + user.LastName
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return fullName
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) sendMUCStatuses(chatID int64) {
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Lock()
|
|
|
|
|
|
|
|
defer c.locks.mucCacheLock.Unlock()
|
|
|
|
|
|
|
|
mucState, ok := c.mucCache[chatID]
|
|
|
|
|
|
|
|
if !ok || mucState == nil {
|
|
|
|
|
|
|
|
mucState = NewMUCState()
|
|
|
|
|
|
|
|
c.mucCache[chatID] = mucState
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sChatId := strconv.FormatInt(chatID, 10)
|
|
|
|
|
|
|
|
myNickname := "me"
|
|
|
|
|
|
|
|
if c.me != nil {
|
|
|
|
|
|
|
|
myNickname = c.getFullName(c.me)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
myAffiliation := "member"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
members, err := c.client.SearchChatMembers(&client.SearchChatMembersRequest{
|
|
|
|
|
|
|
|
ChatId: chatID,
|
|
|
|
|
|
|
|
Limit: 200,
|
|
|
|
|
|
|
|
Filter: &client.ChatMembersFilterMembers{},
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
gatewayJidSuffix := "@" + gateway.Jid.Full()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, member := range members.Members {
|
|
|
|
|
|
|
|
var senderId int64
|
|
|
|
|
|
|
|
switch member.MemberId.MessageSenderType() {
|
|
|
|
|
|
|
|
case client.TypeMessageSenderUser:
|
|
|
|
|
|
|
|
memberUser, _ := member.MemberId.(*client.MessageSenderUser)
|
|
|
|
|
|
|
|
senderId = memberUser.UserId
|
|
|
|
|
|
|
|
case client.TypeMessageSenderChat:
|
|
|
|
|
|
|
|
memberChat, _ := member.MemberId.(*client.MessageSenderChat)
|
|
|
|
|
|
|
|
senderId = memberChat.ChatId
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nickname := c.GetMUCNickname(senderId)
|
|
|
|
|
|
|
|
affiliation := c.memberStatusToAffiliation(member.Status)
|
|
|
|
|
|
|
|
mucState.Members[senderId] = &MUCMember{
|
|
|
|
|
|
|
|
Nickname: nickname,
|
|
|
|
|
|
|
|
Affiliation: affiliation,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if c.me != nil && senderId == c.me.Id {
|
|
|
|
|
|
|
|
myNickname = nickname
|
|
|
|
|
|
|
|
myAffiliation = affiliation
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gateway.SendPresence(
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
c.jid,
|
|
|
|
|
|
|
|
gateway.SPFrom(sChatId),
|
|
|
|
|
|
|
|
gateway.SPResource(nickname),
|
|
|
|
|
|
|
|
gateway.SPImmed(true),
|
|
|
|
|
|
|
|
gateway.SPMUCAffiliation(affiliation),
|
|
|
|
|
|
|
|
gateway.SPMUCJid(strconv.FormatInt(senderId, 10) + gatewayJidSuffix),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// according to the spec, own member entry should be sent the last
|
|
|
|
|
|
|
|
gateway.SendPresence(
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
c.jid,
|
|
|
|
|
|
|
|
gateway.SPFrom(sChatId),
|
|
|
|
|
|
|
|
gateway.SPResource(myNickname),
|
|
|
|
|
|
|
|
gateway.SPImmed(true),
|
|
|
|
|
|
|
|
gateway.SPMUCAffiliation(myAffiliation),
|
|
|
|
|
|
|
|
gateway.SPMUCStatusCodes([]uint16{100, 110, 210}),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
toJid := c.jid + "/" + resource
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
gateway.SendSubjectMessage(
|
|
|
|
|
|
|
|
toJid,
|
|
|
|
|
|
|
|
mucJid + "/" + c.GetMUCNickname(c.GetSenderId(pin)),
|
|
|
|
|
|
|
|
c.messageToText(pin, false),
|
|
|
|
|
|
|
|
strconv.FormatInt(pin.Id, 10),
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
int64(pin.Date),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
gateway.SendSubjectMessage(toJid, mucJid, "", "", c.xmpp, 0)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetMUCNickname generates a unique nickname for a MUC member
|
|
|
|
|
|
|
|
func (c *Client) GetMUCNickname(chatID int64) string {
|
|
|
|
|
|
|
|
return c.formatContact(chatID)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) updateMUCsNickname(memberID int64, newNickname string) {
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Lock()
|
|
|
|
|
|
|
|
defer c.locks.mucCacheLock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for mucId, state := range c.mucCache {
|
|
|
|
|
|
|
|
oldMember, ok := state.Members[memberID]
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
state.Members[memberID] = &MUCMember{
|
|
|
|
|
|
|
|
Nickname: newNickname,
|
|
|
|
|
|
|
|
Affiliation: oldMember.Affiliation,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sMucId := strconv.FormatInt(mucId, 10)
|
|
|
|
|
|
|
|
unavailableStatusCodes := []uint16{303, 210}
|
|
|
|
|
|
|
|
availableStatusCodes := []uint16{100, 210}
|
|
|
|
|
|
|
|
if c.me != nil && memberID == c.me.Id {
|
|
|
|
|
|
|
|
unavailableStatusCodes = append(unavailableStatusCodes, 110)
|
|
|
|
|
|
|
|
availableStatusCodes = append(availableStatusCodes, 110)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
gateway.SendPresence(
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
c.jid,
|
|
|
|
|
|
|
|
gateway.SPType("unavailable"),
|
|
|
|
|
|
|
|
gateway.SPFrom(sMucId),
|
|
|
|
|
|
|
|
gateway.SPResource(oldMember.Nickname),
|
|
|
|
|
|
|
|
gateway.SPImmed(true),
|
|
|
|
|
|
|
|
gateway.SPMUCAffiliation(oldMember.Affiliation),
|
|
|
|
|
|
|
|
gateway.SPMUCNick(newNickname),
|
|
|
|
|
|
|
|
gateway.SPMUCStatusCodes(unavailableStatusCodes),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
gateway.SendPresence(
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
c.jid,
|
|
|
|
|
|
|
|
gateway.SPFrom(sMucId),
|
|
|
|
|
|
|
|
gateway.SPResource(newNickname),
|
|
|
|
|
|
|
|
gateway.SPImmed(true),
|
|
|
|
|
|
|
|
gateway.SPMUCAffiliation(oldMember.Affiliation),
|
|
|
|
|
|
|
|
gateway.SPMUCStatusCodes(availableStatusCodes),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MUCHasResource checks if a MUC was joined from a given resource
|
|
|
|
|
|
|
|
func (c *Client) MUCHasResource(chatID int64, resource string) bool {
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Lock()
|
|
|
|
|
|
|
|
defer c.locks.mucCacheLock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mucState, ok := c.mucCache[chatID]
|
|
|
|
|
|
|
|
if !ok || mucState == nil {
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_, ok = mucState.Resources[resource]
|
|
|
|
|
|
|
|
return ok
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetMyMUCNickname obtains this account's nickname in a given MUC
|
|
|
|
|
|
|
|
func (c *Client) GetMyMUCNickname(chatID int64) (string, bool) {
|
|
|
|
|
|
|
|
if c.me == nil {
|
|
|
|
|
|
|
|
return "", false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.locks.mucCacheLock.Lock()
|
|
|
|
|
|
|
|
defer c.locks.mucCacheLock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mucState, ok := c.mucCache[chatID]
|
|
|
|
|
|
|
|
if !ok || mucState == nil {
|
|
|
|
|
|
|
|
return "", false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
member, ok := mucState.Members[c.me.Id]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
|
|
return "", false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return member.Nickname, true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) formatContact(chatID int64) string {
|
|
|
|
func (c *Client) formatContact(chatID int64) string {
|
|
|
|
if chatID == 0 {
|
|
|
|
if chatID == 0 {
|
|
|
|
return ""
|
|
|
|
return ""
|
|
|
@ -322,7 +543,8 @@ func (c *Client) formatContact(chatID int64) string {
|
|
|
|
return str
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) getSenderId(message *client.Message) (senderId int64) {
|
|
|
|
// GetSenderId extracts a sender id from a message
|
|
|
|
|
|
|
|
func (c *Client) GetSenderId(message *client.Message) (senderId int64) {
|
|
|
|
if message.SenderId != nil {
|
|
|
|
if message.SenderId != nil {
|
|
|
|
switch message.SenderId.MessageSenderType() {
|
|
|
|
switch message.SenderId.MessageSenderType() {
|
|
|
|
case client.TypeMessageSenderUser:
|
|
|
|
case client.TypeMessageSenderUser:
|
|
|
@ -338,7 +560,7 @@ func (c *Client) getSenderId(message *client.Message) (senderId int64) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) formatSender(message *client.Message) string {
|
|
|
|
func (c *Client) formatSender(message *client.Message) string {
|
|
|
|
return c.formatContact(c.getSenderId(message))
|
|
|
|
return c.formatContact(c.GetSenderId(message))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) getMessageReply(message *client.Message) (reply *gateway.Reply, replyMsg *client.Message) {
|
|
|
|
func (c *Client) getMessageReply(message *client.Message) (reply *gateway.Reply, replyMsg *client.Message) {
|
|
|
@ -358,7 +580,7 @@ func (c *Client) getMessageReply(message *client.Message) (reply *gateway.Reply,
|
|
|
|
replyId = strconv.FormatInt(message.ReplyToMessageId, 10)
|
|
|
|
replyId = strconv.FormatInt(message.ReplyToMessageId, 10)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reply = &gateway.Reply{
|
|
|
|
reply = &gateway.Reply{
|
|
|
|
Author: fmt.Sprintf("%v@%s", c.getSenderId(replyMsg), gateway.Jid.Full()),
|
|
|
|
Author: fmt.Sprintf("%v@%s", c.GetSenderId(replyMsg), gateway.Jid.Full()),
|
|
|
|
Id: replyId,
|
|
|
|
Id: replyId,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -851,13 +1073,13 @@ func (c *Client) countCharsInLines(lines *[]string) (count int) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string, replyMsg *client.Message) (string, int, int) {
|
|
|
|
func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string, replyMsg *client.Message) (string, int, int) {
|
|
|
|
isPM, err := c.IsPM(message.ChatId)
|
|
|
|
chatType, err := c.GetChatType(message.ChatId)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Could not determine if chat is PM: %v", err)
|
|
|
|
log.Errorf("Could not determine chat type: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isCarbonsEnabled := gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons
|
|
|
|
isCarbonsEnabled := gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons
|
|
|
|
// with carbons, hide for all messages in PM and only for outgoing in group chats
|
|
|
|
// with carbons, hide for all messages in PM and only for outgoing in group chats
|
|
|
|
hideSender := isCarbonsEnabled && (message.IsOutgoing || isPM)
|
|
|
|
hideSender := (isCarbonsEnabled && (message.IsOutgoing || chatType == ChatTypePM)) || (c.Session.MUC && chatType == ChatTypeGroup)
|
|
|
|
|
|
|
|
|
|
|
|
var replyStart, replyEnd int
|
|
|
|
var replyStart, replyEnd int
|
|
|
|
prefix := []string{}
|
|
|
|
prefix := []string{}
|
|
|
@ -878,7 +1100,7 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !isPM || !c.Session.HideIds {
|
|
|
|
if (chatType != ChatTypePM && !c.Session.MUC) || !c.Session.HideIds {
|
|
|
|
prefix = append(prefix, directionChar+strconv.FormatInt(message.Id, 10))
|
|
|
|
prefix = append(prefix, directionChar+strconv.FormatInt(message.Id, 10))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// show sender in group chats
|
|
|
|
// show sender in group chats
|
|
|
@ -931,10 +1153,29 @@ func (c *Client) ensureDownloadFile(file *client.File) *client.File {
|
|
|
|
return file
|
|
|
|
return file
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProcessIncomingMessage transfers a message to XMPP side and marks it as read on Telegram side
|
|
|
|
// ProcessIncomingMessage is a legacy wrapper for SendMessageToGateway aiming only PM messages
|
|
|
|
func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
|
|
|
func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
|
|
|
isCarbon := gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons && message.IsOutgoing
|
|
|
|
c.SendMessageToGateway(chatId, message, "", false, "", []string{})
|
|
|
|
jids := c.getCarbonFullJids(isCarbon, "")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SendMessageToGateway transfers a message to XMPP side and marks it as read on Telegram side
|
|
|
|
|
|
|
|
func (c *Client) SendMessageToGateway(chatId int64, message *client.Message, id string, delay bool, groupChatFrom string, groupChatTos []string) {
|
|
|
|
|
|
|
|
var isCarbon bool
|
|
|
|
|
|
|
|
var jids []string
|
|
|
|
|
|
|
|
var isGroupchat bool
|
|
|
|
|
|
|
|
var originalFrom string
|
|
|
|
|
|
|
|
if len(groupChatTos) == 0 {
|
|
|
|
|
|
|
|
isCarbon = gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons && message.IsOutgoing
|
|
|
|
|
|
|
|
jids = c.getCarbonFullJids(isCarbon, "")
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
isGroupchat = true
|
|
|
|
|
|
|
|
jids = groupChatTos
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
senderId := c.GetSenderId(message)
|
|
|
|
|
|
|
|
if senderId != 0 {
|
|
|
|
|
|
|
|
originalFrom = strconv.FormatInt(senderId, 10) + "@" + gateway.Jid.Full()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var text, oob, auxText string
|
|
|
|
var text, oob, auxText string
|
|
|
|
|
|
|
|
|
|
|
@ -1006,13 +1247,29 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// forward message to XMPP
|
|
|
|
// forward message to XMPP
|
|
|
|
sId := strconv.FormatInt(message.Id, 10)
|
|
|
|
var sId string
|
|
|
|
sChatId := strconv.FormatInt(chatId, 10)
|
|
|
|
if id == "" {
|
|
|
|
|
|
|
|
sId = strconv.FormatInt(message.Id, 10)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sId = id
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var from string
|
|
|
|
|
|
|
|
if groupChatFrom == "" {
|
|
|
|
|
|
|
|
from = strconv.FormatInt(chatId, 10)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
from = groupChatFrom
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var timestamp int64
|
|
|
|
|
|
|
|
if delay {
|
|
|
|
|
|
|
|
timestamp = int64(message.Date)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, jid := range jids {
|
|
|
|
for _, jid := range jids {
|
|
|
|
gateway.SendMessageWithOOB(jid, sChatId, text, sId, c.xmpp, reply, oob, isCarbon)
|
|
|
|
gateway.SendMessageWithOOB(jid, from, text, sId, c.xmpp, reply, timestamp, oob, isCarbon, isGroupchat, originalFrom)
|
|
|
|
if auxText != "" {
|
|
|
|
if auxText != "" {
|
|
|
|
gateway.SendMessage(jid, sChatId, auxText, sId, c.xmpp, reply, isCarbon)
|
|
|
|
gateway.SendMessage(jid, from, auxText, sId, c.xmpp, reply, timestamp, isCarbon, isGroupchat, originalFrom)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1023,21 +1280,21 @@ func (c *Client) PrepareOutgoingMessageContent(text string) client.InputMessageC
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProcessOutgoingMessage executes commands or sends messages to mapped chats, returns message id
|
|
|
|
// ProcessOutgoingMessage executes commands or sends messages to mapped chats, returns message id
|
|
|
|
func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid string, replyId int64, replaceId int64) int64 {
|
|
|
|
func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid string, replyId int64, replaceId int64, isGroupchat bool) *client.Message {
|
|
|
|
if !c.Online() {
|
|
|
|
if !c.Online() {
|
|
|
|
// we're offline
|
|
|
|
// we're offline
|
|
|
|
return 0
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if replaceId == 0 && (strings.HasPrefix(text, "/") || strings.HasPrefix(text, "!")) {
|
|
|
|
if replaceId == 0 && (strings.HasPrefix(text, "/") || strings.HasPrefix(text, "!")) {
|
|
|
|
// try to execute commands
|
|
|
|
// try to execute commands
|
|
|
|
response, isCommand := c.ProcessChatCommand(chatID, text)
|
|
|
|
response, isCommand := c.ProcessChatCommand(chatID, text)
|
|
|
|
if response != "" {
|
|
|
|
if response != "" {
|
|
|
|
c.returnMessage(returnJid, chatID, response)
|
|
|
|
c.returnMessage(returnJid, chatID, response, 0, isGroupchat)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// do not send on success
|
|
|
|
// do not send on success
|
|
|
|
if isCommand {
|
|
|
|
if isCommand {
|
|
|
|
return 0
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1059,27 +1316,31 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
|
|
|
|
if c.content.Upload != "" && strings.HasPrefix(text, c.content.Upload) {
|
|
|
|
if c.content.Upload != "" && strings.HasPrefix(text, c.content.Upload) {
|
|
|
|
response, err := http.Get(text)
|
|
|
|
response, err := http.Get(text)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Failed to fetch the uploaded file", err)
|
|
|
|
c.returnError(returnJid, chatID, "Failed to fetch the uploaded file", err, 500, isGroupchat)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if response != nil && response.Body != nil {
|
|
|
|
if response != nil && response.Body != nil {
|
|
|
|
defer response.Body.Close()
|
|
|
|
defer response.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
if response.StatusCode != 200 {
|
|
|
|
if response.StatusCode != 200 {
|
|
|
|
c.returnMessage(returnJid, chatID, fmt.Sprintf("Received status code %v", response.StatusCode))
|
|
|
|
c.returnMessage(returnJid, chatID, fmt.Sprintf("Received status code %v", response.StatusCode), response.StatusCode, isGroupchat)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tempDir, err := ioutil.TempDir("", "telegabber-*")
|
|
|
|
tempDir, err := ioutil.TempDir("", "telegabber-*")
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Failed to create a temporary directory", err)
|
|
|
|
c.returnError(returnJid, chatID, "Failed to create a temporary directory", err, 500, isGroupchat)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tempFile, err := os.Create(filepath.Join(tempDir, filepath.Base(text)))
|
|
|
|
tempFile, err := os.Create(filepath.Join(tempDir, filepath.Base(text)))
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Failed to create a temporary file", err)
|
|
|
|
c.returnError(returnJid, chatID, "Failed to create a temporary file", err, 500, isGroupchat)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_, err = io.Copy(tempFile, response.Body)
|
|
|
|
_, err = io.Copy(tempFile, response.Body)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Failed to write a temporary file", err)
|
|
|
|
c.returnError(returnJid, chatID, "Failed to write a temporary file", err, 500, isGroupchat)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
file = &client.InputFileLocal{
|
|
|
|
file = &client.InputFileLocal{
|
|
|
@ -1107,10 +1368,10 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
|
|
|
|
InputMessageContent: content,
|
|
|
|
InputMessageContent: content,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Not edited", err)
|
|
|
|
c.returnError(returnJid, chatID, "Not edited", err, 400, isGroupchat)
|
|
|
|
return 0
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return tgMessage.Id
|
|
|
|
return tgMessage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tgMessage, err := c.client.SendMessage(&client.SendMessageRequest{
|
|
|
|
tgMessage, err := c.client.SendMessage(&client.SendMessageRequest{
|
|
|
@ -1119,18 +1380,30 @@ func (c *Client) ProcessOutgoingMessage(chatID int64, text string, returnJid str
|
|
|
|
InputMessageContent: content,
|
|
|
|
InputMessageContent: content,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.returnError(returnJid, chatID, "Not sent", err)
|
|
|
|
c.returnError(returnJid, chatID, "Not sent", err, 400, isGroupchat)
|
|
|
|
return 0
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return tgMessage.Id
|
|
|
|
return tgMessage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) returnMessage(returnJid string, chatID int64, text string) {
|
|
|
|
func (c *Client) returnMessage(returnJid string, chatID int64, text string, code int, isGroupchat bool) {
|
|
|
|
gateway.SendTextMessage(returnJid, strconv.FormatInt(chatID, 10), text, c.xmpp)
|
|
|
|
sChatId := strconv.FormatInt(chatID, 10)
|
|
|
|
|
|
|
|
if isGroupchat {
|
|
|
|
|
|
|
|
gateway.SendErrorMessage(returnJid, sChatId + "@" + gateway.Jid.Bare(), text, code, isGroupchat, c.xmpp)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
gateway.SendTextMessage(returnJid, sChatId, text, c.xmpp)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) returnError(returnJid string, chatID int64, msg string, err error) {
|
|
|
|
func (c *Client) returnError(returnJid string, chatID int64, msg string, err error, code int, isGroupchat bool) {
|
|
|
|
c.returnMessage(returnJid, chatID, fmt.Sprintf("%s: %s", msg, err.Error()))
|
|
|
|
responseError, ok := err.(client.ResponseError)
|
|
|
|
|
|
|
|
log.Debugf("responseError: %#v", responseError)
|
|
|
|
|
|
|
|
if ok && responseError.Err != nil {
|
|
|
|
|
|
|
|
if responseError.Err.Message == "Have no write access to the chat" {
|
|
|
|
|
|
|
|
code = 403
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
c.returnMessage(returnJid, chatID, fmt.Sprintf("%s: %s", msg, err.Error()), code, isGroupchat)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) prepareOutgoingMessageContent(text string, file *client.InputFileLocal) client.InputMessageContent {
|
|
|
|
func (c *Client) prepareOutgoingMessageContent(text string, file *client.InputFileLocal) client.InputMessageContent {
|
|
|
@ -1228,6 +1501,36 @@ func (c *Client) getLastMessages(id int64, query string, from int64, count int32
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) getNLastMessages(chatID int64, limit int32) ([]*client.Message, error) {
|
|
|
|
|
|
|
|
var newMessages *client.Messages
|
|
|
|
|
|
|
|
var messages []*client.Message
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
var fromId int64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _ = range make([]struct{}, limit) { // safety limit
|
|
|
|
|
|
|
|
if len(messages) > 0 {
|
|
|
|
|
|
|
|
fromId = messages[len(messages)-1].Id
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newMessages, err = c.client.GetChatHistory(&client.GetChatHistoryRequest{
|
|
|
|
|
|
|
|
ChatId: chatID,
|
|
|
|
|
|
|
|
FromMessageId: fromId,
|
|
|
|
|
|
|
|
Limit: limit,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
messages = append(messages, newMessages.Messages...)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(newMessages.Messages) == 0 || len(messages) >= int(limit) {
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return messages, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DownloadFile actually obtains a file by id given by TDlib
|
|
|
|
// DownloadFile actually obtains a file by id given by TDlib
|
|
|
|
func (c *Client) DownloadFile(id int32, priority int32, synchronous bool) (*client.File, error) {
|
|
|
|
func (c *Client) DownloadFile(id int32, priority int32, synchronous bool) (*client.File, error) {
|
|
|
|
return c.client.DownloadFile(&client.DownloadFileRequest{
|
|
|
|
return c.client.DownloadFile(&client.DownloadFileRequest{
|
|
|
@ -1285,7 +1588,7 @@ func (c *Client) GetChatDescription(chat *client.Chat) string {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log.Warnf("Coudln't retrieve private chat info: %v", err.Error())
|
|
|
|
log.Warnf("Couldn't retrieve private chat info: %v", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if chatType == client.TypeChatTypeBasicGroup {
|
|
|
|
} else if chatType == client.TypeChatTypeBasicGroup {
|
|
|
|
basicGroupType, _ := chat.Type.(*client.ChatTypeBasicGroup)
|
|
|
|
basicGroupType, _ := chat.Type.(*client.ChatTypeBasicGroup)
|
|
|
@ -1295,7 +1598,7 @@ func (c *Client) GetChatDescription(chat *client.Chat) string {
|
|
|
|
if err == nil {
|
|
|
|
if err == nil {
|
|
|
|
return fullInfo.Description
|
|
|
|
return fullInfo.Description
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log.Warnf("Coudln't retrieve basic group info: %v", err.Error())
|
|
|
|
log.Warnf("Couldn't retrieve basic group info: %v", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if chatType == client.TypeChatTypeSupergroup {
|
|
|
|
} else if chatType == client.TypeChatTypeSupergroup {
|
|
|
|
supergroupType, _ := chat.Type.(*client.ChatTypeSupergroup)
|
|
|
|
supergroupType, _ := chat.Type.(*client.ChatTypeSupergroup)
|
|
|
@ -1305,12 +1608,68 @@ func (c *Client) GetChatDescription(chat *client.Chat) string {
|
|
|
|
if err == nil {
|
|
|
|
if err == nil {
|
|
|
|
return fullInfo.Description
|
|
|
|
return fullInfo.Description
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log.Warnf("Coudln't retrieve supergroup info: %v", err.Error())
|
|
|
|
log.Warnf("Couldn't retrieve supergroup info: %v", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetChatMemberCount obtains the member count depending on the chat type
|
|
|
|
|
|
|
|
func (c *Client) GetChatMemberCount(chat *client.Chat) int32 {
|
|
|
|
|
|
|
|
chatType := chat.Type.ChatTypeType()
|
|
|
|
|
|
|
|
if chatType == client.TypeChatTypePrivate {
|
|
|
|
|
|
|
|
return 2
|
|
|
|
|
|
|
|
} else if chatType == client.TypeChatTypeBasicGroup {
|
|
|
|
|
|
|
|
basicGroupType, _ := chat.Type.(*client.ChatTypeBasicGroup)
|
|
|
|
|
|
|
|
basicGroup, err := c.client.GetBasicGroup(&client.GetBasicGroupRequest{
|
|
|
|
|
|
|
|
BasicGroupId: basicGroupType.BasicGroupId,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
return basicGroup.MemberCount
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Warnf("Couldn't retrieve basic group: %v", err.Error())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if chatType == client.TypeChatTypeSupergroup {
|
|
|
|
|
|
|
|
supergroupType, _ := chat.Type.(*client.ChatTypeSupergroup)
|
|
|
|
|
|
|
|
supergroup, err := c.client.GetSupergroup(&client.GetSupergroupRequest{
|
|
|
|
|
|
|
|
SupergroupId: supergroupType.SupergroupId,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
return supergroup.MemberCount
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Warnf("Couldn't retrieve supergroup: %v", err.Error())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetGroupChats obtains all group chats
|
|
|
|
|
|
|
|
func (c *Client) GetGroupChats() []*client.Chat {
|
|
|
|
|
|
|
|
var groupChats []*client.Chat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chats, err := c.client.GetChats(&client.GetChatsRequest{
|
|
|
|
|
|
|
|
Limit: chatsLimit,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
for _, id := range chats.ChatIds {
|
|
|
|
|
|
|
|
chat, _, _ := c.GetContactByID(id, nil)
|
|
|
|
|
|
|
|
if chat != nil && c.IsGroup(chat) {
|
|
|
|
|
|
|
|
groupChats = append(groupChats, chat)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Errorf("Could not retrieve chats: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return groupChats
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// IsGroup determines if a chat is eligible to be represented as MUC
|
|
|
|
|
|
|
|
func (c *Client) IsGroup(chat *client.Chat) bool {
|
|
|
|
|
|
|
|
typ := chat.Type.ChatTypeType()
|
|
|
|
|
|
|
|
return typ == client.TypeChatTypeBasicGroup
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// subscribe to a Telegram ID
|
|
|
|
// subscribe to a Telegram ID
|
|
|
|
func (c *Client) subscribeToID(id int64, chat *client.Chat) {
|
|
|
|
func (c *Client) subscribeToID(id int64, chat *client.Chat) {
|
|
|
|
var args []args.V
|
|
|
|
var args []args.V
|
|
|
@ -1321,6 +1680,10 @@ func (c *Client) subscribeToID(id int64, chat *client.Chat) {
|
|
|
|
chat, _, _ = c.GetContactByID(id, nil)
|
|
|
|
chat, _, _ = c.GetContactByID(id, nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if chat != nil {
|
|
|
|
if chat != nil {
|
|
|
|
|
|
|
|
if c.Session.MUC && c.IsGroup(chat) {
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
args = append(args, gateway.SPNickname(chat.Title))
|
|
|
|
args = append(args, gateway.SPNickname(chat.Title))
|
|
|
|
|
|
|
|
|
|
|
|
gateway.SetNickname(c.jid, strconv.FormatInt(id, 10), chat.Title, c.xmpp)
|
|
|
|
gateway.SetNickname(c.jid, strconv.FormatInt(id, 10), chat.Title, c.xmpp)
|
|
|
@ -1378,6 +1741,10 @@ func (c *Client) UpdateChatNicknames() {
|
|
|
|
for _, id := range c.cache.ChatsKeys() {
|
|
|
|
for _, id := range c.cache.ChatsKeys() {
|
|
|
|
chat, ok := c.cache.GetChat(id)
|
|
|
|
chat, ok := c.cache.GetChat(id)
|
|
|
|
if ok {
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
if c.Session.MUC && c.IsGroup(chat) {
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
newArgs := []args.V{
|
|
|
|
newArgs := []args.V{
|
|
|
|
gateway.SPFrom(strconv.FormatInt(id, 10)),
|
|
|
|
gateway.SPFrom(strconv.FormatInt(id, 10)),
|
|
|
|
gateway.SPNickname(chat.Title),
|
|
|
|
gateway.SPNickname(chat.Title),
|
|
|
@ -1504,3 +1871,59 @@ func (c *Client) usernamesToString(usernames []string) string {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(atUsernames, ", ")
|
|
|
|
return strings.Join(atUsernames, ", ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) memberStatusToAffiliation(memberStatus client.ChatMemberStatus) string {
|
|
|
|
|
|
|
|
switch memberStatus.ChatMemberStatusType() {
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusCreator:
|
|
|
|
|
|
|
|
return "owner"
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusAdministrator:
|
|
|
|
|
|
|
|
return "admin"
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusMember:
|
|
|
|
|
|
|
|
return "member"
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusRestricted:
|
|
|
|
|
|
|
|
return "outcast"
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusLeft:
|
|
|
|
|
|
|
|
return "none"
|
|
|
|
|
|
|
|
case client.TypeChatMemberStatusBanned:
|
|
|
|
|
|
|
|
return "outcast"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return "member"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message, plain bool, toJid string) {
|
|
|
|
|
|
|
|
sChatId := strconv.FormatInt(chatID, 10)
|
|
|
|
|
|
|
|
var mucJid string
|
|
|
|
|
|
|
|
if toJid != "" {
|
|
|
|
|
|
|
|
mucJid = sChatId + "@" + gateway.Jid.Bare()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i := len(messages) - 1; i >= 0; i-- {
|
|
|
|
|
|
|
|
message := messages[i]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if plain {
|
|
|
|
|
|
|
|
reply, _ := c.getMessageReply(message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gateway.SendMessage(
|
|
|
|
|
|
|
|
c.jid,
|
|
|
|
|
|
|
|
sChatId,
|
|
|
|
|
|
|
|
c.formatMessage(0, 0, false, message),
|
|
|
|
|
|
|
|
strconv.FormatInt(message.Id, 10),
|
|
|
|
|
|
|
|
c.xmpp,
|
|
|
|
|
|
|
|
reply,
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
"",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
c.SendMessageToGateway(
|
|
|
|
|
|
|
|
chatID,
|
|
|
|
|
|
|
|
message,
|
|
|
|
|
|
|
|
"",
|
|
|
|
|
|
|
|
true,
|
|
|
|
|
|
|
|
mucJid + "/" + c.GetMUCNickname(c.GetSenderId(message)),
|
|
|
|
|
|
|
|
[]string{toJid},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|