mirror of
https://dev.narayana.im/narayana/telegabber.git
synced 2026-08-05 04:07:07 +00:00
Ad-Hoc config editor
This commit is contained in:
parent
7ebcdb0826
commit
0368b8cad8
5 changed files with 206 additions and 74 deletions
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
COMMIT := $(shell git rev-parse --short HEAD)
|
||||
TD_COMMIT := "5bbfc1cf5dab94f82e02f3430ded7241d4653551"
|
||||
VERSION := "v1.10.1"
|
||||
VERSION := "v1.10.2"
|
||||
MAKEOPTS := "-j4"
|
||||
|
||||
all:
|
||||
|
|
|
|||
|
|
@ -51,7 +51,13 @@ type Session struct {
|
|||
IgnoreGroupDeletions bool `yaml:":ignoregroupdeletions"`
|
||||
}
|
||||
|
||||
var configKeys = []string{
|
||||
const (
|
||||
PropertyTypeUnknown byte = iota
|
||||
PropertyTypeString
|
||||
PropertyTypeBool
|
||||
)
|
||||
|
||||
var ConfigKeys = []string{
|
||||
"timezone",
|
||||
"keeponline",
|
||||
"rawmessages",
|
||||
|
|
@ -181,7 +187,7 @@ func (s *Session) ToMap() map[string]string {
|
|||
defer sessionsLock.Unlock()
|
||||
|
||||
m := make(map[string]string)
|
||||
for _, configKey := range configKeys {
|
||||
for _, configKey := range ConfigKeys {
|
||||
value, _ := s.get(configKey)
|
||||
m[configKey] = value
|
||||
}
|
||||
|
|
@ -266,6 +272,18 @@ func (s *Session) Set(key string, value string) (string, error) {
|
|||
return "", errors.New("Unknown session property")
|
||||
}
|
||||
|
||||
// PropertyType determines the property type
|
||||
func PropertyType(key string) byte {
|
||||
switch key {
|
||||
case "timezone":
|
||||
return PropertyTypeString
|
||||
case "keeponline", "rawmessages", "asciiarrows", "oobmode", "carbons", "hideids",
|
||||
"receipts", "nativeedits", "ignoregroupdeletions":
|
||||
return PropertyTypeBool
|
||||
}
|
||||
return PropertyTypeUnknown
|
||||
}
|
||||
|
||||
// TimezoneToLocation tries to convert config timezone to location
|
||||
func (s *Session) TimezoneToLocation() *time.Location {
|
||||
time, err := time.Parse("-07:00", s.Timezone)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
goxmpp "gosrc.io/xmpp"
|
||||
)
|
||||
|
||||
var version string = "1.10.1"
|
||||
var version string = "1.10.2"
|
||||
var commit string
|
||||
|
||||
var sm *goxmpp.StreamManager
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
"unicode"
|
||||
|
||||
"dev.narayana.im/narayana/telegabber/persistence"
|
||||
"dev.narayana.im/narayana/telegabber/xmpp/gateway"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
|
@ -108,9 +109,16 @@ var chatCommands = map[string]command{
|
|||
}
|
||||
|
||||
var transportConfigurationOptions = map[string]configurationOption{
|
||||
"timezone": configurationOption{"<timezone>", "adjust timezone for Telegram user statuses (example: +02:00)"},
|
||||
"keeponline": configurationOption{"<bool>", "always keep telegram session online and rely on jabber offline messages (example: true)"},
|
||||
"rawmessages": configurationOption{"<bool>", "do not add additional info (message id, origin etc.) to incoming messages (example: true)"},
|
||||
"timezone": configurationOption{"<timezone>", "adjust timezone for Telegram user statuses (example: +02:00)"},
|
||||
"keeponline": configurationOption{"<bool>", "always keep telegram session online and rely on jabber offline messages (true/false)"},
|
||||
"rawmessages": configurationOption{"<bool>", "do not add additional info (message id, origin etc.) to incoming messages (true/false)"},
|
||||
"asciiarrows": configurationOption{"<bool>", "replace some Unicode symbols with ASCII alternatives for better compatibility (true/false)"},
|
||||
"oobmode": configurationOption{"<bool>", "use XEP-0066 (OOB); pros: some modern clients won't show images without it, cons: very restricted, Tkabber would flood with popups (true/false)"},
|
||||
"carbons": configurationOption{"<bool>", "send carbons to your another clients, will turn on only if supported by the server (true/false)"},
|
||||
"hideids": configurationOption{"<bool>", "hide message IDs from message info (true/false)"},
|
||||
"receipts": configurationOption{"<bool>", "if enabled, XMPP read receipts are synced to Telegram, otherwise, messages are marked as read automatically (true/false)"},
|
||||
"nativeedits": configurationOption{"<bool>", "if possible, edit XMPP messages instead of showing Telegram edits as separate messages (true/false)"},
|
||||
"ignoregroupdeletions": configurationOption{"<bool>", "suppress message deletion messages in group chats (true/false)"},
|
||||
}
|
||||
|
||||
type command struct {
|
||||
|
|
@ -222,7 +230,8 @@ func (c *Client) helpString(typ CommandType, chatId int64) string {
|
|||
|
||||
if typ == CommandTypeTransport {
|
||||
str.WriteString("Configuration options\n")
|
||||
for name, option := range transportConfigurationOptions {
|
||||
for _, name := range persistence.ConfigKeys {
|
||||
option := transportConfigurationOptions[name]
|
||||
str.WriteString(name)
|
||||
str.WriteString(" ")
|
||||
str.WriteString(option.arguments)
|
||||
|
|
@ -461,7 +470,6 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) (strin
|
|||
}
|
||||
case "config":
|
||||
if len(args) > 1 {
|
||||
var msg string
|
||||
if gateway.MessageOutgoingPermissionVersion == 0 && args[0] == "carbons" && args[1] == "true" {
|
||||
return "The server did not allow to enable carbons", false
|
||||
}
|
||||
|
|
@ -472,7 +480,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) (strin
|
|||
}
|
||||
gateway.DirtySessions = true
|
||||
|
||||
return fmt.Sprintf("%s%s set to %s", msg, args[0], value), true
|
||||
return fmt.Sprintf("%s set to %s", args[0], value), true
|
||||
} else if len(args) > 0 {
|
||||
value, err := c.Session.Get(args[0])
|
||||
if err != nil {
|
||||
|
|
@ -483,7 +491,12 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) (strin
|
|||
}
|
||||
|
||||
var entries []string
|
||||
for key, value := range c.Session.ToMap() {
|
||||
for _, key := range persistence.ConfigKeys {
|
||||
value, err := c.Session.Get(key)
|
||||
if err != nil {
|
||||
log.Errorf("Achtung! Programming error in sessions with key %v", key)
|
||||
continue
|
||||
}
|
||||
entries = append(entries, fmt.Sprintf("%s is set to %s", key, value))
|
||||
}
|
||||
|
||||
|
|
|
|||
227
xmpp/handlers.go
227
xmpp/handlers.go
|
|
@ -877,86 +877,187 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
|||
cmdType = telegram.CommandTypeTransport
|
||||
}
|
||||
if form != nil {
|
||||
// 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
|
||||
})
|
||||
if command.Node == "config" {
|
||||
session, ok := sessions[bare]
|
||||
if ok {
|
||||
var infoStrings []string
|
||||
var warnString, errString string
|
||||
for _, field := range form.Fields {
|
||||
if len(field.ValuesList) > 0 {
|
||||
fieldValue := field.ValuesList[0]
|
||||
|
||||
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])
|
||||
if gateway.MessageOutgoingPermissionVersion == 0 && field.Var == "carbons" && fieldValue == "true" {
|
||||
warnString = "The server did not allow to enable carbons"
|
||||
continue
|
||||
}
|
||||
|
||||
// 10. In accordance with Section 3.2.2.1 of XML Schema Part 2: Datatypes, the allowable
|
||||
// lexical representations for the xs:boolean datatype are the strings "0" and "false"
|
||||
// for the concept 'false' and the strings "1" and "true" for the concept 'true';
|
||||
// implementations MUST support both styles of lexical representation.
|
||||
if persistence.PropertyType(field.Var) == persistence.PropertyTypeBool {
|
||||
if fieldValue == "0" {
|
||||
fieldValue = "false"
|
||||
}
|
||||
if fieldValue == "1" {
|
||||
fieldValue = "true"
|
||||
}
|
||||
}
|
||||
|
||||
oldValue, err := session.Session.Get(field.Var)
|
||||
if err != nil || oldValue != fieldValue {
|
||||
value, err := session.Session.Set(field.Var, fieldValue)
|
||||
if err != nil {
|
||||
errString = fmt.Sprintf("Error for field %v: %v, aborting", field.Var, err.Error())
|
||||
break
|
||||
}
|
||||
infoStrings = append(infoStrings, fmt.Sprintf("%s set to %s", field.Var, value))
|
||||
gateway.DirtySessions = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var elements []stanza.CommandElement
|
||||
if errString != "" {
|
||||
elements = append(elements, &stanza.Note{
|
||||
Text: errString,
|
||||
Type: stanza.CommandNoteTypeErr,
|
||||
})
|
||||
}
|
||||
if warnString != "" {
|
||||
elements = append(elements, &stanza.Note{
|
||||
Text: warnString,
|
||||
Type: stanza.CommandNoteTypeWarn,
|
||||
})
|
||||
}
|
||||
for _, infoString := range infoStrings {
|
||||
elements = append(elements, &stanza.Note{
|
||||
Text: infoString,
|
||||
Type: stanza.CommandNoteTypeInfo,
|
||||
})
|
||||
}
|
||||
|
||||
answer.Payload = &stanza.Command{
|
||||
SessionId: command.Node,
|
||||
Node: command.Node,
|
||||
Status: stanza.CommandStatusCompleted,
|
||||
CommandElements: elements,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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()
|
||||
}
|
||||
|
||||
cmdString = cmd.String()
|
||||
} else {
|
||||
if command.Action == "" || command.Action == stanza.CommandActionExecute {
|
||||
cmd, ok := telegram.GetCommand(cmdType, command.Node)
|
||||
if ok && len(cmd.Arguments) > 0 {
|
||||
var fields []*stanza.Field
|
||||
for i, arg := range cmd.Arguments {
|
||||
var required *string
|
||||
if i < cmd.RequiredArgs {
|
||||
dummyString := ""
|
||||
required = &dummyString
|
||||
}
|
||||
if command.Node == "config" {
|
||||
session, ok := sessions[bare]
|
||||
if ok {
|
||||
for _, key := range persistence.ConfigKeys {
|
||||
// no reason to display the item if carbons won't work
|
||||
if key == "carbons" && gateway.MessageOutgoingPermissionVersion == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
value, err := session.Session.Get(key)
|
||||
if err != nil {
|
||||
log.Errorf("Achtung! Programming error in sessions with key %v", key)
|
||||
continue
|
||||
}
|
||||
|
||||
var fieldType string
|
||||
if persistence.PropertyType(key) == persistence.PropertyTypeBool {
|
||||
fieldType = stanza.FieldTypeBool
|
||||
}
|
||||
|
||||
field := stanza.Field{
|
||||
Var: key,
|
||||
Label: key,
|
||||
Type: fieldType,
|
||||
ValuesList: []string{value},
|
||||
}
|
||||
fields = append(fields, &field)
|
||||
log.Debugf("field: %#v", field)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i, arg := range cmd.Arguments {
|
||||
var required *string
|
||||
if i < cmd.RequiredArgs {
|
||||
dummyString := ""
|
||||
required = &dummyString
|
||||
}
|
||||
|
||||
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 {
|
||||
// allow empty form
|
||||
case "mute", "unmute":
|
||||
options = append(options, stanza.Option{
|
||||
ValuesList: []string{""},
|
||||
})
|
||||
case "unmute":
|
||||
membersList = telegram.MembersListRestricted
|
||||
case "unban":
|
||||
membersList = telegram.MembersListBannedAndAdministrators
|
||||
}
|
||||
for _, member := range members {
|
||||
senderId := session.GetSenderId(member.MemberId)
|
||||
options = append(options, stanza.Option{
|
||||
Label: session.FormatContact(senderId),
|
||||
ValuesList: []string{strconv.FormatInt(senderId, 10)},
|
||||
})
|
||||
members, err := session.GetChatMembers(toId, true, "", membersList)
|
||||
if err == nil {
|
||||
fieldType = stanza.FieldTypeListSingle
|
||||
switch command.Node {
|
||||
// allow empty form
|
||||
case "mute", "unmute":
|
||||
options = append(options, stanza.Option{
|
||||
ValuesList: []string{""},
|
||||
})
|
||||
}
|
||||
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,
|
||||
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)
|
||||
}
|
||||
fields = append(fields, &field)
|
||||
log.Debugf("field: %#v", field)
|
||||
}
|
||||
form := stanza.Form{
|
||||
Type: stanza.FormTypeForm,
|
||||
|
|
|
|||
Loading…
Reference in a new issue