Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions cmd/modemmenu/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,11 @@ func (u *setupUI) run() error {
if err := d.Show(scr); err != nil {
return err
}
k, alt, err := d.Key(-1)
wait := time.Duration(-1) // no idle limit: the sysop's setup waits
if u.size != nil {
wait = time.Minute // the size looked at again
}
k, alt, err := d.Key(wait)
if errors.Is(err, term.ErrTimeout) && u.size != nil {
continue // at the console: no one to hang up on
}
Expand Down Expand Up @@ -913,7 +917,7 @@ func runSetupLocal(path string) int {
return 1
}
u.size = size
d.Idle = time.Minute // the size looked at again
d.Idle = -1 // the setup never times out
u.who = "on the console"
if err := u.run(); err != nil {
fmt.Fprintln(os.Stderr, "modemmenu:", err)
Expand Down Expand Up @@ -968,15 +972,13 @@ func setupItem(t *term.Term, cfg *settings, it *menuItem, s *session, deadline t
}
u.who = "user=" + s.User
logf("setup: %s by user=%s", cfg.path, s.User)
if !deadline.IsZero() && time.Until(deadline) < d.Idle {
d.Idle = max(time.Until(deadline), time.Second)
}
// no idle limit for the sysop's setup: only the session's time limit
// (time_limit) ends it, or a hangup
d.Idle = -1
d.Deadline = deadline
err = u.run()
if errors.Is(err, term.ErrTimeout) {
if !deadline.IsZero() && !time.Now().Before(deadline) {
return errTimeLimit
}
return t.Write("\r\nIdle too long: the setup ended (what was not saved is not).\r\n")
return errTimeLimit
}
return err
}
Expand Down
6 changes: 4 additions & 2 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ groups = sysops

It must have `users` or `groups` (modemmenu refuses one without), and is
never a guest's. It needs an ANSI terminal of 40x14 at least (80x24 is
better); others are told so. The idle timeout and the call's time limit
hold in it; what was not saved when the call ends is lost. The file is
better); others are told so. The idle timeout does not hold in it: the
setup waits for the sysop however long they take. The call's time limit
(`time_limit`) still does, and what was not saved when the call ends is
lost. The file is
written as the user modemmenu runs as, which must be able to write it.

## Terminals
Expand Down
4 changes: 3 additions & 1 deletion internal/tui/desk.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ type Desk struct {
Shade bool
Menus []Menu // the menu bar's pull-downs; none: a bar with Name
// how long a key may take where the screens wait without a limit of
// their own (0: a day); ErrTimeout after
// their own (0: a day, < 0: no limit); ErrTimeout after
Idle time.Duration
// a time no wait goes past (zero: none); ErrTimeout at it
Deadline time.Time

on *Screen // what the terminal shows (nil: not known)
last *Screen // what was shown last
Expand Down
26 changes: 22 additions & 4 deletions internal/tui/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,32 @@ func (d *Desk) next(wait time.Duration) (byte, error) {
}
if wait < 0 {
wait = d.Idle
if wait <= 0 {
if wait == 0 {
wait = 24 * time.Hour
}
}
if wait == 0 {
return 0, ErrTimeout
forever := wait < 0 // Idle < 0: until a key, a hangup or the Deadline
for {
w := wait
if forever {
w = 24 * time.Hour
}
if !d.Deadline.IsZero() {
left := time.Until(d.Deadline)
if left <= 0 {
return 0, ErrTimeout
}
w = min(w, left)
}
if w == 0 {
return 0, ErrTimeout
}
b, err := d.Line.ReadOne(w)
if forever && errors.Is(err, ErrTimeout) {
continue
}
return b, err
}
return d.Line.ReadOne(wait)
}

func (d *Desk) unread(b byte) { d.pending = append([]byte{b}, d.pending...) }
39 changes: 39 additions & 0 deletions internal/tui/tui_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,42 @@ func TestPullDown(t *testing.T) {
t.Errorf("menu keys")
}
}

// slowLine: times out a few times before its one key
type slowLine struct {
quiet int
waits []time.Duration
}

func (l *slowLine) ReadOne(d time.Duration) (byte, error) {
l.waits = append(l.waits, d)
if l.quiet > 0 {
l.quiet--
return 0, ErrTimeout
}
return 'x', nil
}

func (l *slowLine) WriteRaw(string) error { return nil }

// TestNoIdle: Idle < 0 waits through the line's timeouts for a key;
// a Deadline still ends the wait
func TestNoIdle(t *testing.T) {
l := &slowLine{quiet: 3}
d := &Desk{Line: l, Idle: -1}
if k, _, err := d.Key(-1); err != nil || k != 'x' {
t.Fatalf("Key = %q, %v; want 'x'", k, err)
}
if len(l.waits) != 4 {
t.Fatalf("%d reads, want 4", len(l.waits))
}
l = &slowLine{quiet: 1 << 30}
d = &Desk{Line: l, Idle: -1, Deadline: time.Now().Add(-time.Second)}
if _, _, err := d.Key(-1); err != ErrTimeout {
t.Fatalf("past the deadline: %v, want ErrTimeout", err)
}
d = &Desk{Line: &slowLine{quiet: 1}, Idle: time.Minute}
if _, _, err := d.Key(-1); err != ErrTimeout {
t.Fatalf("Idle a minute: %v, want ErrTimeout", err)
}
}
Loading