mirror of
https://dev.narayana.im/narayana/telegabber.git
synced 2026-08-05 04:07:07 +00:00
Bot Menu via Ad-Hoc
This commit is contained in:
parent
3cac57e0f3
commit
4414c147d8
5 changed files with 162 additions and 16 deletions
|
|
@ -58,6 +58,8 @@ type Client struct {
|
|||
lastMsgIds map[int64]string
|
||||
msgHashSeed maphash.Seed
|
||||
|
||||
LastBotCmdString string
|
||||
|
||||
XmppClientFeatures map[string]*[]string
|
||||
XmppClientFeaturesLock sync.Mutex
|
||||
|
||||
|
|
|
|||
|
|
@ -247,10 +247,23 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
|
|||
|
||||
c.updateLastMessageHash(update.Message.ChatId, update.Message.Id, update.Message.Content)
|
||||
|
||||
var forceCmd bool
|
||||
if c.LastBotCmdString != "" && update.Message.IsOutgoing {
|
||||
if update.Message.Content.MessageContentType() == client.TypeMessageText {
|
||||
textMessage, _ := update.Message.Content.(*client.MessageText)
|
||||
|
||||
if textMessage.Text != nil && textMessage.Text.Text == c.LastBotCmdString {
|
||||
forceCmd = true
|
||||
c.LastBotCmdString = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ignore self outgoing messages
|
||||
if update.Message.IsOutgoing &&
|
||||
update.Message.SendingState != nil &&
|
||||
update.Message.SendingState.MessageSendingStateType() == client.TypeMessageSendingStatePending {
|
||||
update.Message.SendingState.MessageSendingStateType() == client.TypeMessageSendingStatePending &&
|
||||
!forceCmd {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ type messageStub struct {
|
|||
Text string
|
||||
}
|
||||
|
||||
type BotCommand struct {
|
||||
Command string
|
||||
Description string
|
||||
}
|
||||
|
||||
type BotLink struct {
|
||||
Description string
|
||||
Link string
|
||||
}
|
||||
|
||||
const (
|
||||
typeFileDataSha1 byte = iota
|
||||
typeFileDataBase64
|
||||
|
|
@ -211,6 +221,40 @@ func (c *Client) IsPM(id int64) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// IsBot checks if a chat is a bot
|
||||
func (c *Client) IsBot(id int64) (bool, error) {
|
||||
_, user, err := c.GetContactByID(id, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if user == nil || user.Type == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return user.Type.UserTypeType() == client.TypeUserTypeBot, nil
|
||||
}
|
||||
|
||||
// GetBotMenu retrieves the bot's attachment menu
|
||||
func (c *Client) GetBotMenu(id int64) (*BotLink, []*BotCommand, error) {
|
||||
fullInfo, err := c.client.GetUserFullInfo(&client.GetUserFullInfoRequest{
|
||||
UserId: id,
|
||||
})
|
||||
if err == nil && fullInfo.BotInfo != nil {
|
||||
if fullInfo.BotInfo.MenuButton != nil {
|
||||
menuButton := fullInfo.BotInfo.MenuButton
|
||||
return &BotLink{menuButton.Text, menuButton.Url}, nil, nil
|
||||
} else {
|
||||
var commands []*BotCommand
|
||||
for _, command := range fullInfo.BotInfo.Commands {
|
||||
commands = append(commands, &BotCommand{command.Command, command.Description})
|
||||
}
|
||||
return nil, commands, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func (c *Client) userStatusToText(status client.UserStatus, chatID int64) (string, string, string) {
|
||||
var show, textStatus, presenceType string
|
||||
|
||||
|
|
@ -1275,13 +1319,13 @@ func (c *Client) PrepareOutgoingMessageContent(text string) client.InputMessageC
|
|||
}
|
||||
|
||||
// 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, raw bool) int64 {
|
||||
if !c.Online() {
|
||||
// we're offline
|
||||
return 0
|
||||
}
|
||||
|
||||
if replaceId == 0 && (strings.HasPrefix(text, "/") || strings.HasPrefix(text, "!")) {
|
||||
if replaceId == 0 && !raw && (strings.HasPrefix(text, "/") || strings.HasPrefix(text, "!")) {
|
||||
// try to execute commands
|
||||
response, isCommand, _ := c.ProcessChatCommand(chatID, text)
|
||||
if response != "" {
|
||||
|
|
|
|||
104
xmpp/handlers.go
104
xmpp/handlers.go
|
|
@ -204,7 +204,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) {
|
|||
|
||||
session.SendMessageLock.Lock()
|
||||
defer session.SendMessageLock.Unlock()
|
||||
tgMessageId := session.ProcessOutgoingMessage(toID, text, msg.From, replyId, replaceId)
|
||||
tgMessageId := session.ProcessOutgoingMessage(toID, text, msg.From, replyId, replaceId, false)
|
||||
if tgMessageId != 0 {
|
||||
if replaceId != 0 {
|
||||
// not needed (is it persistent among clients though?)
|
||||
|
|
@ -679,7 +679,7 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) {
|
|||
|
||||
log.Debugf("discoItems: %#v", di)
|
||||
|
||||
_, toOk := toToID(iq.To)
|
||||
toID, toOk := toToID(iq.To)
|
||||
if di.Node == gateway.NSCommand {
|
||||
answer.Payload = di
|
||||
|
||||
|
|
@ -698,6 +698,13 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) {
|
|||
session, ok := sessions[bare]
|
||||
if ok {
|
||||
isOnline = session.Online()
|
||||
|
||||
if toOk {
|
||||
isBot, err := session.IsBot(toID)
|
||||
if err == nil && isBot {
|
||||
di.AddItem(iq.To, "botmenu", "Bot Menu")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -966,7 +973,7 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
|||
CommandElements: elements,
|
||||
}
|
||||
}
|
||||
} else if command.Node == "loginwizard" {
|
||||
} else if !toOk && command.Node == "loginwizard" {
|
||||
var session *telegram.Client
|
||||
answer.Payload, cancelSend, session = loginWizardPayload(bare, form, resource)
|
||||
|
||||
|
|
@ -974,6 +981,31 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
|||
if cancelSend {
|
||||
go sendLoginWizardResponse(component, answer, session)
|
||||
}
|
||||
} else if toOk && command.Node == "botmenu" {
|
||||
payload := &stanza.Command{
|
||||
SessionId: command.Node,
|
||||
Node: command.Node,
|
||||
}
|
||||
answer.Payload = payload
|
||||
|
||||
if len(form.Fields) == 1 && form.Fields[0] != nil &&
|
||||
form.Fields[0].Var == "command" && len(form.Fields[0].ValuesList) == 1 {
|
||||
session, ok := sessions[bare]
|
||||
if ok {
|
||||
msgText := "/"+form.Fields[0].ValuesList[0]
|
||||
session.LastBotCmdString = msgText
|
||||
tgMessageId := session.ProcessOutgoingMessage(toId, msgText, iq.From, 0, 0, true)
|
||||
if tgMessageId != 0 {
|
||||
payload.Status = stanza.CommandStatusCompleted
|
||||
} else {
|
||||
setCommandPayloadError(payload, "Failed to send a bot command")
|
||||
}
|
||||
} else {
|
||||
setCommandPayloadError(payload, "Session is lost")
|
||||
}
|
||||
} else {
|
||||
setCommandPayloadError(payload, "Broken form")
|
||||
}
|
||||
} else {
|
||||
// just for the case the client messed the order somehow
|
||||
sort.Slice(form.Fields, func(i int, j int) bool {
|
||||
|
|
@ -1102,7 +1134,7 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
|||
CommandElements: []stanza.CommandElement{&form},
|
||||
}
|
||||
log.Debugf("form: %#v", form)
|
||||
} else if command.Node == "loginwizard" {
|
||||
} else if !toOk && command.Node == "loginwizard" {
|
||||
var session *telegram.Client
|
||||
answer.Payload, cancelSend, session = loginWizardPayload(bare, nil, resource)
|
||||
|
||||
|
|
@ -1110,6 +1142,61 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
|||
if cancelSend {
|
||||
go sendLoginWizardResponse(component, answer, session)
|
||||
}
|
||||
} else if toOk && command.Node == "botmenu" {
|
||||
session, ok := sessions[bare]
|
||||
|
||||
var link *telegram.BotLink
|
||||
var commands []*telegram.BotCommand
|
||||
var err error
|
||||
if ok {
|
||||
link, commands, err = session.GetBotMenu(toId)
|
||||
}
|
||||
|
||||
payload := &stanza.Command{
|
||||
SessionId: command.Node,
|
||||
Node: command.Node,
|
||||
}
|
||||
answer.Payload = payload
|
||||
|
||||
if !ok || err != nil {
|
||||
setCommandPayloadError(payload, "Cannot retrieve commands")
|
||||
} else {
|
||||
if link != nil {
|
||||
payload.Status = stanza.CommandStatusCompleted
|
||||
payload.CommandElements = []stanza.CommandElement{
|
||||
&stanza.Note{
|
||||
Text: fmt.Sprintf("%v: %v", link.Description, link.Link),
|
||||
Type: stanza.CommandNoteTypeInfo,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
var options []stanza.Option
|
||||
for _, cmd := range commands {
|
||||
options = append(options, stanza.Option{
|
||||
Label: fmt.Sprintf("/%v — %v", cmd.Command, cmd.Description),
|
||||
ValuesList: []string{cmd.Command},
|
||||
})
|
||||
}
|
||||
|
||||
dummyString := ""
|
||||
field := stanza.Field{
|
||||
Var: "command",
|
||||
Type: stanza.FieldTypeListSingle,
|
||||
Required: &dummyString,
|
||||
Options: options,
|
||||
}
|
||||
log.Debugf("field: %#v", field)
|
||||
|
||||
form := stanza.Form{
|
||||
Type: stanza.FormTypeForm,
|
||||
Fields: []*stanza.Field{&field},
|
||||
}
|
||||
log.Debugf("form: %#v", form)
|
||||
|
||||
payload.Status = stanza.CommandStatusExecuting
|
||||
payload.CommandElements = []stanza.CommandElement{&form}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmdString = "/" + command.Node
|
||||
}
|
||||
|
|
@ -1206,6 +1293,15 @@ func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code
|
|||
}
|
||||
}
|
||||
|
||||
func setCommandPayloadError(payload *stanza.Command, err string) {
|
||||
note := stanza.Note{
|
||||
Text: err,
|
||||
Type: stanza.CommandNoteTypeErr,
|
||||
}
|
||||
payload.Status = stanza.CommandStatusCompleted
|
||||
payload.CommandElements = append(payload.CommandElements, ¬e)
|
||||
}
|
||||
|
||||
func probeClientFeatures(jid string, component *xmpp.Component) {
|
||||
id, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -11,15 +11,6 @@ import (
|
|||
"gosrc.io/xmpp/stanza"
|
||||
)
|
||||
|
||||
func setCommandPayloadError(payload *stanza.Command, err string) {
|
||||
note := stanza.Note{
|
||||
Text: err,
|
||||
Type: stanza.CommandNoteTypeErr,
|
||||
}
|
||||
payload.Status = stanza.CommandStatusCompleted
|
||||
payload.CommandElements = append(payload.CommandElements, ¬e)
|
||||
}
|
||||
|
||||
func loginWizardPayload(bare string, requestForm *stanza.Form, resource string) (payload *stanza.Command, cancelSend bool, returnSession *telegram.Client) {
|
||||
payload = &stanza.Command{
|
||||
SessionId: "loginwizard",
|
||||
|
|
|
|||
Loading…
Reference in a new issue