aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--telegram/commands.go26
-rw-r--r--telegram/utils.go129
-rw-r--r--telegram/utils_test.go6
-rw-r--r--xmpp/handlers.go55
4 files changed, 165 insertions, 51 deletions
diff --git a/telegram/commands.go b/telegram/commands.go
index a01a80e..3c899ed 100644
--- a/telegram/commands.go
+++ b/telegram/commands.go
@@ -70,6 +70,7 @@ var transportCommands = map[string]command{
var notForGroups = []ChatType{ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
var notForPM = []ChatType{ChatTypePrivate, ChatTypeSecret}
+var notForPMAndBasic = []ChatType{ChatTypePrivate, ChatTypeSecret, ChatTypeBasicGroup}
var onlyForSecret = []ChatType{ChatTypePrivate, ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
var chatCommands = map[string]command{
@@ -93,8 +94,8 @@ var chatCommands = map[string]command{
"invite": command{1, []string{"id or @username"}, "add user to current chat", &notForPM},
"link": command{0, []string{}, "get invite link for current chat", &notForPM},
"kick": command{1, []string{"id or @username"}, "remove user from current chat", &notForPM},
- "mute": command{1, []string{"id or @username", "hours"}, "mute user in current chat", &notForPM},
- "unmute": command{1, []string{"id or @username"}, "unrestrict user from current chat", &notForPM},
+ "mute": command{1, []string{"id or @username", "hours"}, "mute user in current chat", &notForPMAndBasic},
+ "unmute": command{1, []string{"id or @username"}, "unrestrict user from current chat", &notForPMAndBasic},
"ban": command{1, []string{"id or @username", "hours"}, "restrict @username from current chat for [hours] or forever", &notForPM},
"unban": command{1, []string{"id or @username"}, "unbans @username in current chat (and devotes from admins)", &notForPM},
"promote": command{1, []string{"id or @username", "title"}, "promote user to admin in current chat", &notForPM},
@@ -1100,30 +1101,17 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
query = args[0]
}
- members, err := c.client.SearchChatMembers(&client.SearchChatMembersRequest{
- ChatId: chatID,
- Limit: 9999,
- Query: query,
- Filter: &client.ChatMembersFilterMembers{},
- })
+ members, err := c.GetChatMembers(chatID, false, query, MembersListMembers)
if err != nil {
return err.Error(), true
}
var entries []string
- 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
- }
+ for _, member := range members {
+ senderId := c.GetSenderId(member.MemberId)
entries = append(entries, fmt.Sprintf(
"%v | role: %v",
- c.formatContact(senderId),
+ c.FormatContact(senderId),
member.Status.ChatMemberStatusType(),
))
}
diff --git a/telegram/utils.go b/telegram/utils.go
index 2c8b00d..e7d16d6 100644
--- a/telegram/utils.go
+++ b/telegram/utils.go
@@ -46,6 +46,7 @@ type messageStub struct {
}
var errOffline = errors.New("TDlib instance is offline")
+var errOverLimit = errors.New("Over limit")
var spaceRegex = regexp.MustCompile(`\s+`)
var replyRegex = regexp.MustCompile("\\A>>? ?([0-9]+)\\n")
@@ -65,6 +66,16 @@ const (
ChatTypeChannel
)
+// MembersList is an enum of member list filters
+type MembersList int
+
+const (
+ MembersListMembers MembersList = iota
+ MembersListRestricted
+ MembersListBanned
+ MembersListBannedAndAdministrators
+)
+
// GetContactByUsername resolves username to user id retrieves user and chat information
func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.User, error) {
if !c.Online() {
@@ -330,7 +341,8 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o
return c.sendPresence(newArgs...)
}
-func (c *Client) formatContact(chatID int64) string {
+// FormatContact retrieves a complete "full name (@usernames)" string for display
+func (c *Client) FormatContact(chatID int64) string {
if chatID == 0 {
return ""
}
@@ -362,23 +374,27 @@ func (c *Client) formatContact(chatID int64) string {
return str
}
-func (c *Client) getSenderId(message *client.Message) (senderId int64) {
- if message.SenderId != nil {
- switch message.SenderId.MessageSenderType() {
- case client.TypeMessageSenderUser:
- senderUser, _ := message.SenderId.(*client.MessageSenderUser)
- senderId = senderUser.UserId
- case client.TypeMessageSenderChat:
- senderChat, _ := message.SenderId.(*client.MessageSenderChat)
- senderId = senderChat.ChatId
- }
+func (c *Client) GetSenderId(sender client.MessageSender) (senderId int64) {
+ switch sender.MessageSenderType() {
+ case client.TypeMessageSenderUser:
+ senderUser, _ := sender.(*client.MessageSenderUser)
+ senderId = senderUser.UserId
+ case client.TypeMessageSenderChat:
+ senderChat, _ := sender.(*client.MessageSenderChat)
+ senderId = senderChat.ChatId
}
+ return
+}
+func (c *Client) getMessageSenderId(message *client.Message) (senderId int64) {
+ if message.SenderId != nil {
+ senderId = c.GetSenderId(message.SenderId)
+ }
return
}
func (c *Client) formatSender(message *client.Message) string {
- return c.formatContact(c.getSenderId(message))
+ return c.FormatContact(c.getMessageSenderId(message))
}
func (c *Client) messageToStub(message *client.Message, preview bool, text string) *messageStub {
@@ -428,7 +444,7 @@ func (c *Client) getMessageReply(message *client.Message, preview bool, noConten
}
gatewayReply = &gateway.Reply{
- Author: fmt.Sprintf("%v@%s", c.getSenderId(replyMsg), gateway.Jid.Full()),
+ Author: fmt.Sprintf("%v@%s", c.getMessageSenderId(replyMsg), gateway.Jid.Full()),
Id: replyId,
}
} else if !noContent {
@@ -445,7 +461,7 @@ func (c *Client) getMessageReply(message *client.Message, preview bool, noConten
}
tgReply = &messageStub{
- Sender: c.formatOrigin(replyTo.Origin) + " @ " + c.formatContact(replyTo.ChatId),
+ Sender: c.formatOrigin(replyTo.Origin) + " @ " + c.FormatContact(replyTo.ChatId),
Date: replyTo.OriginSendDate,
Text: text,
}
@@ -515,14 +531,14 @@ func (c *Client) formatOrigin(origin client.MessageOrigin) string {
switch origin.MessageOriginType() {
case client.TypeMessageOriginUser:
originUser := origin.(*client.MessageOriginUser)
- return c.formatContact(originUser.SenderUserId)
+ return c.FormatContact(originUser.SenderUserId)
case client.TypeMessageOriginChat:
originChat := origin.(*client.MessageOriginChat)
var signature string
if originChat.AuthorSignature != "" {
signature = fmt.Sprintf(" (%s)", originChat.AuthorSignature)
}
- return c.formatContact(originChat.SenderChatId) + signature
+ return c.FormatContact(originChat.SenderChatId) + signature
case client.TypeMessageOriginHiddenUser:
originUser := origin.(*client.MessageOriginHiddenUser)
return originUser.SenderName
@@ -532,7 +548,7 @@ func (c *Client) formatOrigin(origin client.MessageOrigin) string {
if channel.AuthorSignature != "" {
signature = fmt.Sprintf(" (%s)", channel.AuthorSignature)
}
- return c.formatContact(channel.ChatId) + signature
+ return c.FormatContact(channel.ChatId) + signature
}
return "Unknown origin type"
}
@@ -701,13 +717,13 @@ func (c *Client) messageContentToText(content client.MessageContent, chatId int6
text := "invited "
if len(addMembers.MemberUserIds) > 0 {
- text += c.formatContact(addMembers.MemberUserIds[0])
+ text += c.FormatContact(addMembers.MemberUserIds[0])
}
return text
case client.TypeMessageChatDeleteMember:
deleteMember, _ := content.(*client.MessageChatDeleteMember)
- return "kicked " + c.formatContact(deleteMember.UserId)
+ return "kicked " + c.FormatContact(deleteMember.UserId)
case client.TypeMessagePinMessage:
pinMessage, _ := content.(*client.MessagePinMessage)
return "pinned message: " + c.formatMessage(chatId, pinMessage.MessageId, preview, nil)
@@ -857,7 +873,7 @@ func (c *Client) messageContentToText(content client.MessageContent, chatId int6
}
case client.TypeMessageChatSetMessageAutoDeleteTime:
ttl, _ := content.(*client.MessageChatSetMessageAutoDeleteTime)
- name := c.formatContact(ttl.FromUserId)
+ name := c.FormatContact(ttl.FromUserId)
if name == "" {
if ttl.MessageAutoDeleteTime == 0 {
return "The self-destruct timer was disabled"
@@ -1654,3 +1670,76 @@ func (c *Client) usernamesToString(usernames []string) string {
}
return strings.Join(atUsernames, ", ")
}
+
+// GetChatMembers retrieves a list of chat members. "Limited" mode works only if there are no more than 20 members at all
+func (c *Client) GetChatMembers(chatID int64, limited bool, query string, membersList MembersList) ([]*client.ChatMember, error) {
+ var filters []client.ChatMembersFilter
+ switch membersList {
+ case MembersListMembers:
+ filters = []client.ChatMembersFilter{&client.ChatMembersFilterMembers{}}
+ case MembersListRestricted:
+ filters = []client.ChatMembersFilter{&client.ChatMembersFilterRestricted{}}
+ case MembersListBanned:
+ filters = []client.ChatMembersFilter{&client.ChatMembersFilterBanned{}}
+ case MembersListBannedAndAdministrators:
+ filters = []client.ChatMembersFilter{&client.ChatMembersFilterBanned{}, &client.ChatMembersFilterAdministrators{}}
+ }
+
+ limit := int32(9999)
+ if limited {
+ limit = 20
+
+ chat, _, err := c.GetContactByID(chatID, nil)
+ if err != nil {
+ return nil, err
+ } else if chat == nil {
+ return nil, errors.New("Chat not found")
+ }
+
+ chatType := chat.Type.ChatTypeType()
+ if chatType == client.TypeChatTypeBasicGroup {
+ basicGroupType, _ := chat.Type.(*client.ChatTypeBasicGroup)
+ fullInfo, err := c.client.GetBasicGroupFullInfo(&client.GetBasicGroupFullInfoRequest{
+ BasicGroupId: basicGroupType.BasicGroupId,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ if len(fullInfo.Members) > int(limit) {
+ return nil, errOverLimit
+ }
+
+ return fullInfo.Members, nil
+ } else if chatType == client.TypeChatTypeSupergroup {
+ supergroupType, _ := chat.Type.(*client.ChatTypeSupergroup)
+ fullInfo, err := c.client.GetSupergroupFullInfo(&client.GetSupergroupFullInfoRequest{
+ SupergroupId: supergroupType.SupergroupId,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ if fullInfo.MemberCount > limit {
+ return nil, errOverLimit
+ }
+ } else {
+ return nil, errors.New("Inapplicable chat type")
+ }
+ }
+
+ var members []*client.ChatMember
+ for _, filter := range filters {
+ chatMembers, err := c.client.SearchChatMembers(&client.SearchChatMembersRequest{
+ ChatId: chatID,
+ Limit: limit,
+ Query: query,
+ Filter: filter,
+ })
+ if err != nil {
+ return nil, err
+ }
+ members = append(members, chatMembers.Members...)
+ }
+ return members, nil
+}
diff --git a/telegram/utils_test.go b/telegram/utils_test.go
index fa9c107..a0939cd 100644
--- a/telegram/utils_test.go
+++ b/telegram/utils_test.go
@@ -567,7 +567,7 @@ func TestMessageToPrefix7(t *testing.T) {
func GetSenderIdEmpty(t *testing.T) {
message := client.Message{}
- senderId := (&Client{}).getSenderId(&message)
+ senderId := (&Client{}).getMessageSenderId(&message)
if senderId != 0 {
t.Errorf("Wrong sender id: %v", senderId)
}
@@ -579,7 +579,7 @@ func GetSenderIdUser(t *testing.T) {
UserId: 42,
},
}
- senderId := (&Client{}).getSenderId(&message)
+ senderId := (&Client{}).getMessageSenderId(&message)
if senderId != 42 {
t.Errorf("Wrong sender id: %v", senderId)
}
@@ -591,7 +591,7 @@ func GetSenderIdChat(t *testing.T) {
ChatId: -42,
},
}
- senderId := (&Client{}).getSenderId(&message)
+ senderId := (&Client{}).getMessageSenderId(&message)
if senderId != -42 {
t.Errorf("Wrong sender id: %v", senderId)
}
diff --git a/xmpp/handlers.go b/xmpp/handlers.go
index 3554394..945f119 100644
--- a/xmpp/handlers.go
+++ b/xmpp/handlers.go
@@ -790,23 +790,59 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
dummyString := ""
required = &dummyString
}
- fields = append(fields, &stanza.Field{
+
+ var fieldType string
+ var options []stanza.Option
+ if toOk && i == 0 {
+ switch command.Node {
+ case "mute", "kick", "ban", "promote", "unmute", "unban":
+ session, ok := sessions[bare]
+ if ok {
+ var membersList telegram.MembersList
+ switch command.Node {
+ case "unmute":
+ membersList = telegram.MembersListRestricted
+ case "unban":
+ membersList = telegram.MembersListBannedAndAdministrators
+ }
+ members, err := session.GetChatMembers(toId, true, "", membersList)
+ if err == nil {
+ fieldType = stanza.FieldTypeListSingle
+ for _, member := range members {
+ senderId := session.GetSenderId(member.MemberId)
+ options = append(options, stanza.Option{
+ Label: session.FormatContact(senderId),
+ ValuesList: []string{strconv.FormatInt(senderId, 10)},
+ })
+ }
+ }
+ }
+ }
+ }
+
+ field := stanza.Field{
Var: strconv.FormatInt(int64(i), 10),
Label: arg,
Required: required,
- })
+ Type: fieldType,
+ Options: options,
+ }
+ fields = append(fields, &field)
+ log.Debugf("field: %#v", field)
+ }
+ form := stanza.Form{
+ Type: stanza.FormTypeForm,
+ Title: command.Node,
+ Instructions: []string{cmd.Description},
+ Fields: fields,
}
answer.Payload = &stanza.Command{
SessionId: command.Node,
Node: command.Node,
Status: stanza.CommandStatusExecuting,
- CommandElement: &stanza.Form{
- Type: stanza.FormTypeForm,
- Title: command.Node,
- Instructions: []string{cmd.Description},
- Fields: fields,
- },
+ CommandElement: &form,
}
+ log.Debugf("form: %#v", form)
} else {
cmdString = "/" + command.Node
}
@@ -842,8 +878,9 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
},
}
- log.Debugf("command response: %#v", answer.Payload)
}
+
+ log.Debugf("command response: %#v", answer.Payload)
}
func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code int) {