After commit c018f5fd29 Fenrir is being switched over to go. If you do not want to be part of the testing process, please switch to master.
This commit is contained in:
1 parent
c018f5fd29
commit
0e50de4c76
1047 files changed
+58364
-63747
No files matched your search
@@ -0,0 +1,195 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.stormux.org/storm/fenrir/internal/config"
|
||||
"git.stormux.org/storm/fenrir/internal/control"
|
||||
)
|
||||
|
||||
// These operations run only after the shared credential and settings gates.
|
||||
// A save keeps its reply pending until the worker reports the actual disk result.
|
||||
func (a *application) remote_settings_request(text string, request control.Request) (string, bool) {
|
||||
verb, parameter, _ := strings.Cut(text, " ")
|
||||
verb, parameter = strings.ToUpper(verb), strings.TrimSpace(parameter)
|
||||
if a.speechPending {
|
||||
return "Settings are busy; try again after the current operation", false
|
||||
}
|
||||
if verb == "SET" {
|
||||
updated, err := remote_settings(a.effective_settings(), text)
|
||||
if err != nil {
|
||||
return err.Error(), false
|
||||
}
|
||||
if !same_speech_selection(updated.Presentation.Speech, a.settings.live.Presentation.Speech) {
|
||||
if a.saver.busy || a.ui.active {
|
||||
return "Settings are busy; try again after the current operation", false
|
||||
}
|
||||
a.change_speech(updated.Presentation.Speech, func(err error) {
|
||||
response := ""
|
||||
if err != nil {
|
||||
response = err.Error()
|
||||
} else {
|
||||
response = a.apply_remote_settings(resolved_remote_selection(text, updated))
|
||||
}
|
||||
remote_reply(request.Reply, response)
|
||||
})
|
||||
return "", true
|
||||
}
|
||||
}
|
||||
switch verb {
|
||||
case "SAVE", "SAVEAS", "RESET":
|
||||
if a.saver.busy || a.ui.active {
|
||||
return "Settings are busy; try again after the current operation", false
|
||||
}
|
||||
default:
|
||||
return a.apply_remote_settings(text), false
|
||||
}
|
||||
if verb != "SAVEAS" && parameter != "" {
|
||||
return verb + " does not accept parameters", false
|
||||
}
|
||||
if verb == "RESET" {
|
||||
updated, _, err := a.remote_reset_state()
|
||||
if err != nil {
|
||||
return err.Error(), false
|
||||
}
|
||||
if !same_speech_selection(updated.Presentation.Speech, a.settings.live.Presentation.Speech) {
|
||||
a.change_speech(updated.Presentation.Speech, func(err error) {
|
||||
response := ""
|
||||
if err != nil {
|
||||
response = err.Error()
|
||||
} else {
|
||||
response = a.reset_remote_settings()
|
||||
}
|
||||
remote_reply(request.Reply, response)
|
||||
})
|
||||
return "", true
|
||||
}
|
||||
return a.reset_remote_settings(), false
|
||||
}
|
||||
path := a.options.ConfigPath
|
||||
if verb == "SAVEAS" {
|
||||
// A root TTY reader also admits its active console user for ordinary
|
||||
// commands. That must not grant arbitrary root-owned file writes.
|
||||
if request.UID != 0 && request.UID != os.Geteuid() {
|
||||
return "SAVEAS requires the reader owner or root", false
|
||||
}
|
||||
path = parameter
|
||||
}
|
||||
if path == "" || strings.ContainsAny(path, "\x00\r\n") {
|
||||
return "A valid settings destination is required", false
|
||||
}
|
||||
if !a.saver.save(a.ctx, path, a.settings_to_save()) {
|
||||
return "Settings are busy; try again after the current operation", false
|
||||
}
|
||||
a.saver.revision = a.settings.remoteRevision
|
||||
a.saver.reply = request.Reply
|
||||
return "", true
|
||||
}
|
||||
|
||||
func (a *application) settings_save_result(err error) {
|
||||
if !a.saver.busy {
|
||||
return
|
||||
}
|
||||
if settings_committed(err) {
|
||||
a.settings.resetBase = a.saver.snapshot
|
||||
for path, revision := range a.settings.remoteFields {
|
||||
if revision <= a.saver.revision {
|
||||
delete(a.settings.remoteFields, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
if done := a.saver.menuDone; done != nil {
|
||||
a.saver.busy, a.saver.menuDone = false, nil
|
||||
done(err)
|
||||
} else if reply := a.saver.reply; reply != nil {
|
||||
a.saver.busy, a.saver.reply = false, nil
|
||||
response := ""
|
||||
if err != nil {
|
||||
response = "Could not save settings: " + err.Error()
|
||||
}
|
||||
remote_reply(reply, response)
|
||||
} else {
|
||||
a.saver.result(err, a.voice)
|
||||
}
|
||||
}
|
||||
|
||||
// RESET clears temporary quick/remote overrides, as in Python's
|
||||
// reset_setting_arg_dict. It never reloads a file or installs factory defaults.
|
||||
func (a *application) remote_reset_state() (config.Settings, config.Settings, error) {
|
||||
updated, persisted := a.effective_settings(), a.settings.saveDraft
|
||||
for _, target := range []*config.Settings{&updated, &persisted} {
|
||||
copy_quick_settings(target, a.settings.resetBase)
|
||||
if a.quick.selectionChanged {
|
||||
copy_speech_selection(&target.Presentation.Speech, a.settings.resetBase.Presentation.Speech)
|
||||
}
|
||||
copy_remote_settings(target, a.settings.resetBase, a.settings.remoteFields)
|
||||
if err := target.Validate(); err != nil {
|
||||
return updated, persisted, err
|
||||
}
|
||||
}
|
||||
if updated.Presentation.Speech.Enabled && !a.settings.speechAvailable {
|
||||
return updated, persisted, fmt.Errorf("Speech was disabled at startup; enable it in settings and relaunch")
|
||||
}
|
||||
return updated, persisted, nil
|
||||
}
|
||||
|
||||
func (a *application) reset_remote_settings() string {
|
||||
updated, persisted, err := a.remote_reset_state()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
a.settings.saveDraft = persisted
|
||||
_, speechOverridden := a.settings.remoteFields["speech#enabled"]
|
||||
a.apply_remote_state(updated, speechOverridden)
|
||||
clear(a.settings.remoteFields)
|
||||
a.quick.changed = false
|
||||
a.quick.selectionChanged = false
|
||||
return ""
|
||||
}
|
||||
|
||||
// Copy only remotely overridden fields; unrelated session mute/AutoRead,
|
||||
// next-launch menu choices, reading regions and keyboard routing survive.
|
||||
func copy_remote_settings(target *config.Settings, source config.Settings, fields map[string]uint64) {
|
||||
for path := range fields {
|
||||
switch path {
|
||||
case "reading#mode", "focus#cursor", "focus#highlight":
|
||||
target.Reading.Mode = source.Reading.Mode
|
||||
case "speech#enabled":
|
||||
target.Presentation.Speech.Enabled = source.Presentation.Speech.Enabled
|
||||
case "speech#module", "speech#language", "speech#voice":
|
||||
copy_speech_selection(&target.Presentation.Speech, source.Presentation.Speech)
|
||||
case "speech#rate":
|
||||
target.Presentation.Speech.Rate = source.Presentation.Speech.Rate
|
||||
case "speech#pitch":
|
||||
target.Presentation.Speech.Pitch = source.Presentation.Speech.Pitch
|
||||
case "speech#volume":
|
||||
target.Presentation.Speech.Volume = source.Presentation.Speech.Volume
|
||||
case "sound#enabled":
|
||||
target.Presentation.Sound.Enabled = source.Presentation.Sound.Enabled
|
||||
case "sound#volume":
|
||||
target.Presentation.Sound.Volume = source.Presentation.Sound.Volume
|
||||
case "sound#progress_monitoring":
|
||||
target.Presentation.Progress.Enabled = source.Presentation.Progress.Enabled
|
||||
case "general#punctuation_level":
|
||||
target.Reading.PunctuationLevel = source.Reading.PunctuationLevel
|
||||
case "speech#auto_read_incoming", "reading#automatic":
|
||||
target.Reading.Automatic = source.Reading.Automatic
|
||||
case "reading#cursor_echo":
|
||||
target.Reading.CursorEcho = source.Reading.CursorEcho
|
||||
case "keyboard#char_echo_mode":
|
||||
target.Keyboard.CharacterEcho = source.Keyboard.CharacterEcho
|
||||
target.Keyboard.EchoOnCapsLock = source.Keyboard.EchoOnCapsLock
|
||||
case "keyboard#word_echo":
|
||||
target.Keyboard.WordEcho = source.Keyboard.WordEcho
|
||||
case "keyboard#echo_on_capslock":
|
||||
target.Keyboard.EchoOnCapsLock = source.Keyboard.EchoOnCapsLock
|
||||
case "screen#ignore_screen":
|
||||
target.Screen.IgnoredVTs = append([]int{}, source.Screen.IgnoredVTs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user