Form support for transport Ad-Hoc commands with arguments

This commit is contained in:
Bohdan Horbeshko 2024-02-03 04:24:22 -05:00
parent e3a5191905
commit 21dc5fa6c6
4 changed files with 95 additions and 29 deletions

View file

@ -2,7 +2,7 @@
COMMIT := $(shell git rev-parse --short HEAD) COMMIT := $(shell git rev-parse --short HEAD)
TD_COMMIT := "5bbfc1cf5dab94f82e02f3430ded7241d4653551" TD_COMMIT := "5bbfc1cf5dab94f82e02f3430ded7241d4653551"
VERSION := "v1.9.1" VERSION := "v1.10.0-dev"
MAKEOPTS := "-j4" MAKEOPTS := "-j4"
all: all:

View file

@ -16,7 +16,7 @@ import (
goxmpp "gosrc.io/xmpp" goxmpp "gosrc.io/xmpp"
) )
var version string = "1.9.1" var version string = "1.10.0-dev"
var commit string var commit string
var sm *goxmpp.StreamManager var sm *goxmpp.StreamManager

View file

@ -107,9 +107,9 @@ var transportConfigurationOptions = map[string]configurationOption{
} }
type command struct { type command struct {
requiredArgs int RequiredArgs int
arguments []string Arguments []string
description string Description string
} }
type configurationOption struct { type configurationOption struct {
arguments string arguments string
@ -138,14 +138,21 @@ func GetCommands(typ CommandType) map[string]command {
return commandMap return commandMap
} }
// GetCommand obtains one command
func GetCommand(typ CommandType, cmd string) (command, bool) {
commands := GetCommands(typ)
command, ok := commands[cmd]
return command, ok
}
// CommandToHelpString builds a text description of a command // CommandToHelpString builds a text description of a command
func CommandToHelpString(name string, cmd command) string { func CommandToHelpString(name string, cmd command) string {
var str strings.Builder var str strings.Builder
str.WriteString("/") str.WriteString("/")
str.WriteString(name) str.WriteString(name)
for i, arg := range cmd.arguments { for i, arg := range cmd.Arguments {
optional := i >= cmd.requiredArgs optional := i >= cmd.RequiredArgs
str.WriteString(" ") str.WriteString(" ")
if optional { if optional {
str.WriteString("[") str.WriteString("[")
@ -156,7 +163,7 @@ func CommandToHelpString(name string, cmd command) string {
} }
} }
str.WriteString(" — ") str.WriteString(" — ")
str.WriteString(cmd.description) str.WriteString(cmd.Description)
return str.String() return str.String()
} }
@ -267,7 +274,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
if !ok { if !ok {
return "Unknown command" return "Unknown command"
} }
if len(args) < command.requiredArgs { if len(args) < command.RequiredArgs {
return notEnoughArguments return notEnoughArguments
} }

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"io" "io"
"sort"
"strconv" "strconv"
"strings" "strings"
@ -701,31 +702,89 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
log.Debugf("command: %#v", command) log.Debugf("command: %#v", command)
bare, resource, ok := gateway.SplitJID(iq.From)
if !ok {
return
}
var cmdString string
if command.Action == "" || command.Action == stanza.CommandActionExecute { if command.Action == "" || command.Action == stanza.CommandActionExecute {
_, ok := toToID(iq.To) _, ok := toToID(iq.To)
if !ok { if !ok {
bare, resource, ok := gateway.SplitJID(iq.From) cmd, ok := telegram.GetCommand(telegram.CommandTypeTransport, command.Node)
if !ok { if ok && cmd.RequiredArgs > 0 {
return var fields []*stanza.Field
for i, arg := range cmd.Arguments {
fields = append(fields, &stanza.Field{
Var: strconv.FormatInt(int64(i), 10),
Label: arg,
})
}
answer.Payload = &stanza.Command{
SessionId: command.Node,
Node: command.Node,
Status: stanza.CommandStatusExecuting,
CommandElement: &stanza.Form{
Title: command.Node,
Instructions: []string{cmd.Description},
Fields: fields,
},
}
} else {
cmdString = "/" + command.Node
} }
session, ok := sessions[bare]
if !ok {
return
}
response := session.ProcessTransportCommand("/" + command.Node, resource)
answer.Payload = &stanza.Command{
Node: command.Node,
Status: stanza.CommandStatusCompleted,
CommandElement: &stanza.Note{
Text: response,
Type: stanza.CommandNoteTypeInfo,
},
}
log.Debugf("command response: %#v", answer.Payload)
} }
} else if command.Action == stanza.CommandActionComplete {
_, ok := toToID(iq.To)
if !ok {
form, ok := command.CommandElement.(*stanza.Form)
if ok {
// just for the case the client messed the order somehow
sort.Slice(form.Fields, func(i int, j int) bool {
iField := form.Fields[i]
jField := form.Fields[j]
if iField != nil && jField != nil {
ii, iErr := strconv.ParseInt(iField.Var, 10, 64)
ji, jErr := strconv.ParseInt(jField.Var, 10, 64)
return iErr == nil && jErr == nil && ii < ji
}
return false
})
var cmd strings.Builder
cmd.WriteString("/")
cmd.WriteString(command.Node)
for _, field := range form.Fields {
cmd.WriteString(" ")
if len(field.ValuesList) > 0 {
cmd.WriteString(field.ValuesList[0])
}
}
cmdString = cmd.String()
}
}
}
if cmdString != "" {
session, ok := sessions[bare]
if !ok {
return
}
response := session.ProcessTransportCommand(cmdString, resource)
answer.Payload = &stanza.Command{
SessionId: command.Node,
Node: command.Node,
Status: stanza.CommandStatusCompleted,
CommandElement: &stanza.Note{
Text: response,
Type: stanza.CommandNoteTypeInfo,
},
}
log.Debugf("command response: %#v", answer.Payload)
} }
} }