2016-02-22 22:07:02 +01:00
|
|
|
// Copyright 2016 Martin Hebnes Pedersen (LA5NTA). All rights reserved.
|
2015-05-22 20:01:56 +02:00
|
|
|
// Use of this source code is governed by the MIT-license that can be
|
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
2025-06-14 07:50:42 +02:00
|
|
|
package cli
|
2015-05-22 20:01:56 +02:00
|
|
|
|
|
|
|
|
import (
|
2022-02-16 20:58:10 +01:00
|
|
|
"context"
|
2015-05-22 20:01:56 +02:00
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
2024-12-15 12:11:02 +01:00
|
|
|
"path/filepath"
|
2015-05-22 20:01:56 +02:00
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/bndr/gotabulate"
|
|
|
|
|
|
2025-06-14 07:50:42 +02:00
|
|
|
"github.com/la5nta/pat/app"
|
2015-11-23 21:47:50 +01:00
|
|
|
"github.com/la5nta/wl2k-go/fbb"
|
2015-05-22 20:01:56 +02:00
|
|
|
"github.com/la5nta/wl2k-go/mailbox"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var mailboxes = []string{"in", "out", "sent", "archive"}
|
|
|
|
|
|
2025-06-14 07:50:42 +02:00
|
|
|
func ReadHandle(ctx context.Context, app *app.App, _ []string) {
|
2025-07-06 10:07:52 +02:00
|
|
|
cancel := exitOnContextCancellation(ctx)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
2015-05-22 20:01:56 +02:00
|
|
|
w := os.Stdout
|
|
|
|
|
|
|
|
|
|
for {
|
2016-05-14 22:42:18 +02:00
|
|
|
// Query user for mailbox to list
|
|
|
|
|
printMailboxes(w)
|
|
|
|
|
fmt.Fprintf(w, "\nChoose mailbox [n]: ")
|
2025-07-06 10:07:52 +02:00
|
|
|
mailboxIdx, ok := readInt()
|
2016-05-14 22:42:18 +02:00
|
|
|
if !ok {
|
2015-05-22 20:01:56 +02:00
|
|
|
break
|
2016-05-14 22:42:18 +02:00
|
|
|
} else if mailboxIdx+1 > len(mailboxes) {
|
|
|
|
|
fmt.Fprintln(w, "Invalid mailbox number")
|
|
|
|
|
continue
|
2015-05-22 20:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-14 22:42:18 +02:00
|
|
|
for {
|
|
|
|
|
// Fetch messages
|
2025-06-14 07:50:42 +02:00
|
|
|
msgs, err := mailbox.LoadMessageDir(filepath.Join(app.Mailbox().MBoxPath, mailboxes[mailboxIdx]))
|
2016-05-14 22:42:18 +02:00
|
|
|
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)
|
2015-05-22 20:01:56 +02:00
|
|
|
|
2016-05-14 22:42:18 +02:00
|
|
|
// Query user for message to print
|
|
|
|
|
fmt.Fprintf(w, "Choose message [n]: ")
|
2025-07-06 10:07:52 +02:00
|
|
|
msgIdx, ok := readInt()
|
2016-05-14 22:42:18 +02:00
|
|
|
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)
|
|
|
|
|
}
|
2015-10-01 20:20:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-15 12:11:02 +01:00
|
|
|
L:
|
|
|
|
|
for {
|
2025-07-09 09:26:49 +02:00
|
|
|
fmt.Fprintf(w, "Action [C,r,ra,f,e,d,q,?]: ")
|
2025-05-23 11:32:19 +02:00
|
|
|
switch ans := readLine(); ans {
|
2024-12-15 12:11:02 +01:00
|
|
|
case "C", "c", "":
|
|
|
|
|
break L
|
2025-07-07 21:22:10 +02:00
|
|
|
case "d":
|
|
|
|
|
fmt.Fprint(w, "Delete message? [y/N]: ")
|
|
|
|
|
if ans := readLine(); strings.EqualFold(ans, "y") {
|
|
|
|
|
msg := msgs[msgIdx]
|
|
|
|
|
mbox := mailboxes[mailboxIdx]
|
|
|
|
|
path := filepath.Join(app.Mailbox().MBoxPath, mbox, msg.MID()+mailbox.Ext)
|
|
|
|
|
if err := os.Remove(path); err != nil {
|
|
|
|
|
log.Printf("Failed to delete message %s from %s: %v", msg.MID(), mbox, err)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintln(w, "Message deleted.")
|
|
|
|
|
}
|
|
|
|
|
break L
|
|
|
|
|
}
|
2025-07-09 09:26:49 +02:00
|
|
|
case "r":
|
2025-07-15 19:35:46 +02:00
|
|
|
composeMessage(app, composerFlags{from: app.Options().MyCall, inReplyTo: msgs[msgIdx].MID()}, true)
|
2025-07-09 09:26:49 +02:00
|
|
|
case "ra":
|
2025-07-15 19:35:46 +02:00
|
|
|
composeMessage(app, composerFlags{from: app.Options().MyCall, inReplyTo: msgs[msgIdx].MID(), replyAll: true}, true)
|
2025-07-09 09:26:49 +02:00
|
|
|
case "f":
|
2025-07-15 19:35:46 +02:00
|
|
|
composeMessage(app, composerFlags{from: app.Options().MyCall, forward: msgs[msgIdx].MID()}, true)
|
2024-12-15 12:11:02 +01:00
|
|
|
case "e":
|
2025-06-14 07:50:42 +02:00
|
|
|
ExtractMessageHandle(ctx, app, []string{msgs[msgIdx].MID()})
|
2024-12-15 12:11:02 +01:00
|
|
|
case "q":
|
|
|
|
|
return
|
|
|
|
|
case "?":
|
|
|
|
|
fallthrough
|
|
|
|
|
default:
|
2025-05-23 11:32:19 +02:00
|
|
|
fmt.Fprintln(w, "c - continue")
|
|
|
|
|
fmt.Fprintln(w, "r - reply")
|
|
|
|
|
fmt.Fprintln(w, "ra - reply all")
|
2025-07-09 09:26:49 +02:00
|
|
|
fmt.Fprintln(w, "f - forward")
|
2025-05-23 11:32:19 +02:00
|
|
|
fmt.Fprintln(w, "e - extract (attachments)")
|
2025-07-07 21:22:10 +02:00
|
|
|
fmt.Fprintln(w, "d - delete")
|
2025-05-23 11:32:19 +02:00
|
|
|
fmt.Fprintln(w, "q - quit")
|
2024-12-15 12:11:02 +01:00
|
|
|
}
|
2016-05-14 22:42:18 +02:00
|
|
|
}
|
2015-05-22 20:01:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-06 10:07:52 +02:00
|
|
|
func readInt() (int, bool) {
|
|
|
|
|
str := readLine()
|
|
|
|
|
if str == "" {
|
2016-05-14 22:42:18 +02:00
|
|
|
return 0, false
|
|
|
|
|
}
|
2025-07-06 10:07:52 +02:00
|
|
|
i, _ := strconv.Atoi(str)
|
|
|
|
|
return i, true
|
2015-05-22 20:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-23 21:47:50 +01:00
|
|
|
func printMsg(w io.Writer, msg *fbb.Message) {
|
2015-05-22 20:01:56 +02:00
|
|
|
fmt.Fprintf(w, "========================================\n")
|
|
|
|
|
fmt.Fprintln(w, msg)
|
|
|
|
|
fmt.Fprintf(w, "========================================\n\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func printMailboxes(w io.Writer) {
|
2021-08-16 22:40:36 -06:00
|
|
|
for i, mbox := range mailboxes {
|
|
|
|
|
fmt.Fprintf(w, "%d:%s\t", i, mbox)
|
2015-05-22 20:01:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 21:47:50 +01:00
|
|
|
func printMessages(w io.Writer, msgs []*fbb.Message) {
|
2015-05-22 20:01:56 +02:00
|
|
|
rows := make([][]string, len(msgs))
|
|
|
|
|
for i, msg := range msgs {
|
2017-08-08 23:36:18 +02:00
|
|
|
var to string
|
|
|
|
|
if len(msg.To()) > 0 {
|
|
|
|
|
to = msg.To()[0].Addr
|
|
|
|
|
}
|
2015-07-30 19:05:17 +02:00
|
|
|
if len(msg.To()) > 1 {
|
2021-08-16 22:40:36 -06:00
|
|
|
to += ", ..."
|
2015-05-22 20:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-01 20:20:55 +02:00
|
|
|
var flags string
|
|
|
|
|
if mailbox.IsUnread(msg) {
|
|
|
|
|
flags += "N" // New
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-22 20:01:56 +02:00
|
|
|
rows[i] = []string{
|
|
|
|
|
fmt.Sprintf("%2d", i),
|
2015-10-01 20:20:55 +02:00
|
|
|
flags,
|
2015-07-30 19:05:17 +02:00
|
|
|
msg.Subject(),
|
|
|
|
|
msg.From().Addr,
|
|
|
|
|
msg.Date().String(),
|
2015-05-22 20:01:56 +02:00
|
|
|
to,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
t := gotabulate.Create(rows)
|
2015-10-01 20:20:55 +02:00
|
|
|
t.SetHeaders([]string{"i", "Flags", "Subject", "From", "Date", "To"})
|
2015-05-22 20:01:56 +02:00
|
|
|
t.SetAlign("left")
|
|
|
|
|
t.SetWrapStrings(true)
|
|
|
|
|
t.SetMaxCellSize(60)
|
|
|
|
|
fmt.Fprintln(w, t.Render("simple"))
|
|
|
|
|
}
|