Select Git revision
messages.go
messages.go 8.05 KiB
// Package repl implements the main event loop.
package repl
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"git.lyda.ie/kevin/bulletin/ask"
"git.lyda.ie/kevin/bulletin/dclish"
"git.lyda.ie/kevin/bulletin/editor"
"git.lyda.ie/kevin/bulletin/folders"
"git.lyda.ie/kevin/bulletin/pager"
"git.lyda.ie/kevin/bulletin/this"
)
// ActionDirectory handles the `DIRECTORY` command. This lists all the
// messages in the current folder.
func ActionDirectory(cmd *dclish.Command) error {
// TODO: flag parsing.
showExpiration := false
if cmd.Flags["/EXPIRATION"].Value == "true" {
showExpiration = true
}
if len(cmd.Args) == 1 {
folder, err := folders.ValidFolder(cmd.Args[0])
if err != nil {
return err
}
this.Folder = folder
}
msgs, err := folders.ListMessages(this.Folder.Name)
if err != nil {
return err
}
if len(msgs) == 0 {
fmt.Println("There are no messages present.")
return nil
}
fmt.Printf("%4s %-43s %-12s %-10s\n", "#", "Subject", "From", "Date")
for _, msg := range msgs {
fmt.Printf("%s\n", msg.OneLine(showExpiration))
}
return nil
}
// ActionAdd handles the `ADD` command. This adds a message to a folder.
func ActionAdd(cmd *dclish.Command) error {
optAll := 0
optBell := 0
optBroadcast := 0
optEdit := 0
optExpiration := &time.Time{}
optExtract := 0
optFolder := []string{}
optIndent := 0
optPermanent := 0
optShutdown := 0
optSignature := 0
optSubject := ""
optSystem := 0
if cmd.Flags["/ALL"].Value == "true" {
optAll = 1
}
if cmd.Flags["/BELL"].Value == "true" {
optBell = 1
}
if cmd.Flags["/BROADCAST"].Value == "true" {
optBroadcast = 1
}
if cmd.Flags["/EDIT"].Value == "true" {
optEdit = 1
}
if cmd.Flags["/EXPIRATION"].Value != "" {
// dd-mmm-yyyy, or delta time: dddd
exp, err := time.Parse("2006-01-02", cmd.Flags["/EXPIRATION"].Value)
if err != nil {
days, err := strconv.Atoi(cmd.Flags["/EXPIRATION"].Value)
if err != nil {
optExpiration = nil
}
exp := time.Now().AddDate(0, 0, days)
optExpiration = &exp
} else {
optExpiration = &exp
}
}
if cmd.Flags["/EXTRACT"].Value == "true" {
optExtract = 1
}
if cmd.Flags["/FOLDER"].Value != "" {
fmt.Printf("/FOLDER = %s\n", cmd.Flags["/FOLDER"].Value)
optFolder = strings.Split(cmd.Flags["/FOLDER"].Value, ",")
}
if cmd.Flags["/INDENT"].Value == "true" {
optIndent = 1
}
if cmd.Flags["/PERMANENT"].Value == "true" {
optPermanent = 1
}
if cmd.Flags["/SHUTDOWN"].Value == "true" {
optShutdown = 1
}
if cmd.Flags["/SIGNATURE"].Value == "true" {
optSignature = 1
}
if cmd.Flags["/SUBJECT"].Value != "" {
optSubject = cmd.Flags["/SUBJECT"].Value
}
if cmd.Flags["/SYSTEM"].Value == "true" {
optSystem = 1
}
fmt.Printf("TODO: optAll is not yet implemented - you set it to %d\n", optAll)
fmt.Printf("TODO: optBell is not yet implemented - you set it to %d\n", optBell)
fmt.Printf("TODO: optBroadcast is not yet implemented - you set it to %d\n", optBroadcast)
fmt.Printf("TODO: optEdit is not yet implemented - you set it to %d\n", optEdit)
fmt.Printf("TODO: optExtract is not yet implemented - you set it to %d\n", optExtract)
fmt.Printf("TODO: optIndent is not yet implemented - you set it to %d\n", optIndent)
fmt.Printf("TODO: optSignature is not yet implemented - you set it to %d\n", optSignature)
fmt.Printf("TODO: optSystem is not yet implemented - you set it to %d\n", optSystem)
if len(optFolder) == 0 {
optFolder = []string{this.Folder.Name}
}
// TODO: check if folders exist.
if optSubject == "" {
optSubject, _ = ask.GetLine("Enter subject of message: ")
if optSubject == "" {
return errors.New("Must enter a subject")
}
}
// TODO: check we have permission for shutdown and permanent
message, err := editor.Editor(fmt.Sprintf("Enter message for '%s'...", optSubject), "Edit message")
if err != nil {
return err
}
for i := range optFolder {
err = folders.CreateMessage(this.User.Login, optSubject, message,
optFolder[i], optPermanent, optShutdown, optExpiration)
}
return nil
}
// ActionCurrent handles the `CURRENT` command.
func ActionCurrent(_ *dclish.Command) error {
// TODO: handle flags.
msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, this.MsgID)
if err != nil {
return err
}
lines := strings.Split(msg.String(), "\n")
if len(lines) > 10 {
lines = lines[:10]
}
fmt.Printf("%s\n", strings.Join(lines, "\n"))
return nil
}
// ActionBack handles the `BACK` command.
func ActionBack(_ *dclish.Command) error {
// TODO: handle flags.
msgid := folders.PrevMsgid(this.User.Login, this.Folder.Name, this.MsgID)
if msgid == 0 {
fmt.Println("No previous messages")
return nil
}
msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)
if err != nil {
return err
}
// TODO: pager needs to report if the whole message was read
// and only increment if not.
pager.Pager(msg.String())
this.MsgID = msgid
return nil
}
// ActionChange handles the `CHANGE` command.
func ActionChange(cmd *dclish.Command) error {
fmt.Printf("TODO: unimplemented...\n%s\n", cmd.Description)
return nil
}
// ActionFirst handles the `FIRST` command.
func ActionFirst(_ *dclish.Command) error {
msgid := folders.FirstMessage(this.Folder.Name)
if msgid == 0 {
fmt.Println("No messages in folder")
return nil
}
this.MsgID = msgid
return nil
}
// ActionNext handles the `NEXT` command.
func ActionNext(_ *dclish.Command) error {
// TODO: handle flags.
msgid := folders.NextMsgid(this.User.Login, this.Folder.Name, this.MsgID)
if msgid == 0 {
fmt.Println("No next messages")
return nil
}
msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)
if err != nil {
return err
}
// TODO: pager needs to report if the whole message was read
// and only increment if not.
pager.Pager(msg.String())
this.MsgID = msgid
return nil
}
// ActionRead handles the `READ` command.
func ActionRead(cmd *dclish.Command) error {
// TODO: handle flags.
msgid := this.MsgID
if len(cmd.Args) == 1 {
var err error
msgid, err = strconv.ParseInt(cmd.Args[0], 10, 64)
if err != nil {
return err
}
}
msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)
if err != nil {
return err
}
// TODO: pager needs to report if the whole message was read
// and only increment if not.
pager.Pager(msg.String())
msgid = folders.NextMsgid(this.User.Login, this.Folder.Name, msgid)
this.MsgID = max(this.MsgID, msgid)
return nil
}
// ActionReply handles the `REPLY` command.
func ActionReply(cmd *dclish.Command) error {
fmt.Printf("TODO: unimplemented...\n%s\n", cmd.Description)
return nil
}
// ActionForward handles the `FORWARD` command.
func ActionForward(cmd *dclish.Command) error {
fmt.Printf("TODO: unimplemented...\n%s\n", cmd.Description)
return nil
}
// ActionSeen handles the `SEEN` command.
func ActionSeen(cmd *dclish.Command) error {
var err error
msgids := []int64{this.MsgID}
if len(cmd.Args) == 1 {
msgids, err = ParseNumberList(cmd.Args[0])
if err != nil {
return err
}
}
err = folders.MarkSeen(msgids)
if err != nil {
fmt.Printf("ERROR: %s.\n", err)
}
return nil
}
// ActionUnseen handles the `UNSEEN` command.
func ActionUnseen(cmd *dclish.Command) error {
var err error
msgids := []int64{this.MsgID}
if len(cmd.Args) == 1 {
msgids, err = ParseNumberList(cmd.Args[0])
if err != nil {
return err
}
}
err = folders.MarkUnseen(msgids)
if err != nil {
fmt.Printf("ERROR: %s.\n", err)
}
return nil
}
// ActionDelete handles the `DELETE` command.
func ActionDelete(cmd *dclish.Command) error {
// TODO: Follow permissions.
var err error
all := false
if cmd.Flags["/ALL"].Value == "true" {
all = true
}
if all {
if len(cmd.Args) == 1 {
fmt.Println("ERROR: Can't specify both message numbers and /ALL flag.")
return nil
}
err := folders.DeleteAllMessages()
if err != nil {
fmt.Printf("ERROR: %s.\n", err)
}
return nil
}
msgids := []int64{this.MsgID}
if len(cmd.Args) == 1 {
msgids, err = ParseNumberList(cmd.Args[0])
if err != nil {
fmt.Printf("ERROR: %s.\n", err)
return nil
}
}
err = folders.DeleteMessages(msgids)
if err != nil {
fmt.Printf("ERROR: %s.\n", err)
}
return nil
}