pat/read.go
Martin Hebnes Pedersen 441fda35c4 Graceful shutdown through context cancellation
By doing graceful shutdown, we're able to properly close all of the open
resources such as modem connections and ongoing sessions.

This will allow transport drivers controlling stateful TNCs (e.g.
ptc-go) to recover the initial TNC state before termination.

Resolves #314
2022-02-20 14:48:29 +01:00

157 lines
3.2 KiB
Go

// Copyright 2016 Martin Hebnes Pedersen (LA5NTA). All rights reserved.
// Use of this source code is governed by the MIT-license that can be
// found in the LICENSE file.
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"os"
"path"
"sort"
"strconv"
"strings"
"github.com/bndr/gotabulate"
"github.com/la5nta/wl2k-go/fbb"
"github.com/la5nta/wl2k-go/mailbox"
)
var mailboxes = []string{"in", "out", "sent", "archive"}
func readMail(ctx context.Context) {
w := os.Stdout
for {
// Query user for mailbox to list
printMailboxes(w)
fmt.Fprintf(w, "\nChoose mailbox [n]: ")
mailboxIdx, ok := readInt(ctx)
if !ok {
break
} else if mailboxIdx+1 > len(mailboxes) {
fmt.Fprintln(w, "Invalid mailbox number")
continue
}
for {
// Fetch messages
msgs, err := mailbox.LoadMessageDir(path.Join(mailbox.UserPath(fOptions.MailboxPath, fOptions.MyCall), mailboxes[mailboxIdx]))
if err != nil {
log.Fatal(err)
} else if len(msgs) == 0 {
fmt.Fprintf(w, "(empty)\n")
break
}
// Print messages (sorted by date)
sort.Sort(fbb.ByDate(msgs))
printMessages(w, msgs)
// Query user for message to print
fmt.Fprintf(w, "Choose message [n]: ")
msgIdx, ok := readInt(ctx)
if !ok {
break
} else if msgIdx+1 > len(msgs) {
fmt.Fprintf(w, "invalid message number\n")
continue
}
printMsg(w, msgs[msgIdx])
// Mark as read?
if mailbox.IsUnread(msgs[msgIdx]) {
fmt.Fprintf(w, "Mark as read? [Y/n]: ")
ans := readLine()
if ans == "" || strings.EqualFold(ans, "y") {
mailbox.SetUnread(msgs[msgIdx], false)
}
}
// Reply?
fmt.Fprintf(w, "Reply (ctrl+c to quit) [y/N]: ")
ans := readLine()
if strings.EqualFold(ans, "y") {
composeReplyMessage(msgs[msgIdx])
}
}
}
}
func readInt(ctx context.Context) (int, bool) {
cs := make(chan string, 1)
go func() { cs <- readLine() }()
select {
case <-ctx.Done():
return 0, false
case str := <-cs:
if str == "" {
return 0, false
}
i, _ := strconv.Atoi(str)
return i, true
}
}
type PrettyAddrSlice []fbb.Address
func (addrs PrettyAddrSlice) String() string {
var buf bytes.Buffer
for i, addr := range addrs {
fmt.Fprintf(&buf, "%s", addr.Addr)
if i < len(addrs)-1 {
fmt.Fprintf(&buf, ", ")
}
}
return buf.String()
}
func printMsg(w io.Writer, msg *fbb.Message) {
fmt.Fprintf(w, "========================================\n")
fmt.Fprintln(w, msg)
fmt.Fprintf(w, "========================================\n\n")
}
func printMailboxes(w io.Writer) {
for i, mbox := range mailboxes {
fmt.Fprintf(w, "%d:%s\t", i, mbox)
}
}
func printMessages(w io.Writer, msgs []*fbb.Message) {
rows := make([][]string, len(msgs))
for i, msg := range msgs {
var to string
if len(msg.To()) > 0 {
to = msg.To()[0].Addr
}
if len(msg.To()) > 1 {
to += ", ..."
}
var flags string
if mailbox.IsUnread(msg) {
flags += "N" // New
}
rows[i] = []string{
fmt.Sprintf("%2d", i),
flags,
msg.Subject(),
msg.From().Addr,
msg.Date().String(),
to,
}
}
t := gotabulate.Create(rows)
t.SetHeaders([]string{"i", "Flags", "Subject", "From", "Date", "To"})
t.SetAlign("left")
t.SetWrapStrings(true)
t.SetMaxCellSize(60)
fmt.Fprintln(w, t.Render("simple"))
}