Commit dbee0389 authored by Kevin Lyda's avatar Kevin Lyda
Browse files

Address missing commands

But not the mail commands yet.
parent 754f9d30
Loading
Loading
Loading
Loading
+43 −2
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@ import (
	"git.lyda.ie/pp/bulletin/this"
)

// CreateMessage creates a new folder.
func CreateMessage(author, subject, message, folder string, permanent, shutdown int, expiration *time.Time) error {
// CreateMessage creates a new message.
func CreateMessage(author, subject, message, folder string, permanent, system, shutdown int, expiration *time.Time) error {
	ctx := storage.Context()
	if expiration == nil {
		days, err := this.Q.GetFolderExpire(ctx, folder)
@@ -34,12 +34,53 @@ func CreateMessage(author, subject, message, folder string, permanent, shutdown
		Subject:    subject,
		Message:    message,
		Permanent:  int64(permanent),
		System:     int64(system),
		Shutdown:   int64(shutdown),
		Expiration: *expiration,
	})
	return err
}

// CopyMessage copies a message from one folder to another.
func CopyMessage(srcFolder, destFolder string, msgid int64) error {
	ctx := storage.Context()
	return this.Q.CopyMessage(ctx, destFolder, srcFolder, msgid)
}

// CopyMessages copies multiple messages from one folder to another.
func CopyMessages(srcFolder, destFolder string, msgids []int64) error {
	for _, msgid := range msgids {
		if err := CopyMessage(srcFolder, destFolder, msgid); err != nil {
			return err
		}
	}
	return nil
}

// ListMessagesSeen lists messages seen by a user in a folder.
func ListMessagesSeen(login, folder string) ([]storage.Message, error) {
	ctx := storage.Context()
	return this.Q.ListMessagesSeen(ctx, folder, login)
}

// ListMessagesUnseen lists messages not seen by a user in a folder.
func ListMessagesUnseen(login, folder string) ([]storage.Message, error) {
	ctx := storage.Context()
	return this.Q.ListMessagesUnseen(ctx, folder, login)
}

// ListMessagesMarked lists messages marked by a user in a folder.
func ListMessagesMarked(login, folder string) ([]storage.Message, error) {
	ctx := storage.Context()
	return this.Q.ListMessagesMarked(ctx, folder, login)
}

// ListMessagesUnmarked lists messages not marked by a user in a folder.
func ListMessagesUnmarked(login, folder string) ([]storage.Message, error) {
	ctx := storage.Context()
	return this.Q.ListMessagesUnmarked(ctx, folder, login)
}

// GetMessage reads a message for a user.
func GetMessage(login, folder string, msgid int64) (*storage.Message, error) {
	ctx := storage.Context()
+36 −15
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import (
	"git.lyda.ie/pp/bulletin/ask"
	"git.lyda.ie/pp/bulletin/dclish"
	"git.lyda.ie/pp/bulletin/folders"
	"git.lyda.ie/pp/bulletin/pager"
	"git.lyda.ie/pp/bulletin/storage"
	"git.lyda.ie/pp/bulletin/this"
)
@@ -17,24 +18,44 @@ import (
//
// This originally existed as the subroutine FULL_DIR in bulletin9.for.
func ActionIndex(cmd *dclish.Command) error {
	if cmd.Flags["/RESTART"].Set {
		this.ReadFirstCall = true
	}

	// Check for filter flags - these filter messages in the current folder.
	var msgs []storage.Message
	var filterErr error
	filtered := false

	if cmd.Flags["/MARKED"].Set {
		return errors.New("not implemented yet")
	}
	if cmd.Flags["/NEW"].Set {
		return errors.New("not implemented yet")
		msgs, filterErr = folders.ListMessagesMarked(this.User.Login, this.Folder.Name)
		filtered = true
	} else if cmd.Flags["/UNMARKED"].Set {
		msgs, filterErr = folders.ListMessagesUnmarked(this.User.Login, this.Folder.Name)
		filtered = true
	} else if cmd.Flags["/SEEN"].Set {
		msgs, filterErr = folders.ListMessagesSeen(this.User.Login, this.Folder.Name)
		filtered = true
	} else if cmd.Flags["/NEW"].Set || cmd.Flags["/UNSEEN"].Set {
		msgs, filterErr = folders.ListMessagesUnseen(this.User.Login, this.Folder.Name)
		filtered = true
	}
	if cmd.Flags["/RESTART"].Set {
		return errors.New("not implemented yet")

	if filtered {
		if filterErr != nil {
			return filterErr
		}
	if cmd.Flags["/SEEN"].Set {
		return errors.New("not implemented yet")
		if len(msgs) == 0 {
			fmt.Println("There are no messages matching the filter.")
			return nil
		}
	if cmd.Flags["/UNMARKED"].Set {
		return errors.New("not implemented yet")
		buf := strings.Builder{}
		buf.WriteString(fmt.Sprintf("%4s %-43s %-12s %-10s\n", "#", "Subject", "From", "Date"))
		for _, msg := range msgs {
			buf.WriteString(fmt.Sprint(msg.OneLine(false)))
		}
	if cmd.Flags["/UNSEEN"].Set {
		return errors.New("not implemented yet")
		pager.Pager(buf.String())
		return nil
	}

	rows, err := folders.ListFolder()
+46 −21
Original line number Diff line number Diff line
@@ -89,15 +89,9 @@ func ActionAdd(cmd *dclish.Command) error {
	if cmd.Flags["/BELL"].Value == "true" {
		optBell = 1
	}
	if cmd.Flags["/BELL"].Set {
		fmt.Printf("/BELL is not yet implemented - you set it to %d\n", optBell)
	}
	if cmd.Flags["/BROADCAST"].Value == "true" {
		optBroadcast = 1
	}
	if cmd.Flags["/BROADCAST"].Set {
		fmt.Printf("/BROADCAST is not yet implemented - you set it to %d\n", optBroadcast)
	}
	if cmd.Flags["/EXPIRATION"].Value != "" {
		// dd-mmm-yyyy, or delta time: dddd
		exp, err := time.Parse("2006-01-02", cmd.Flags["/EXPIRATION"].Value)
@@ -115,18 +109,12 @@ func ActionAdd(cmd *dclish.Command) error {
	if cmd.Flags["/EXTRACT"].Value == "true" {
		optExtract = 1
	}
	if cmd.Flags["/EXTRACT"].Set {
		fmt.Printf("/EXTRACT is not yet implemented - you set it to %d\n", optExtract)
	}
	if cmd.Flags["/FOLDER"].Value != "" {
		optFolder = strings.Split(cmd.Flags["/FOLDER"].Value, ",")
	}
	if cmd.Flags["/INDENT"].Value == "true" {
		optIndent = 1
	}
	if cmd.Flags["/INDENT"].Set {
		fmt.Printf("/INDENT is not yet implemented - you set it to %d\n", optIndent)
	}
	if cmd.Flags["/PERMANENT"].Value == "true" {
		optPermanent = 1
	}
@@ -136,18 +124,12 @@ func ActionAdd(cmd *dclish.Command) error {
	if cmd.Flags["/SIGNATURE"].Value == "true" {
		optSignature = 1
	}
	if cmd.Flags["/SIGNATURE"].Set {
		fmt.Printf("/SIGNATURE is not yet implemented - you set it to %d\n", optSignature)
	}
	if cmd.Flags["/SUBJECT"].Value != "" {
		optSubject = cmd.Flags["/SUBJECT"].Value
	}
	if cmd.Flags["/SYSTEM"].Value == "true" {
		optSystem = 1
	}
	if cmd.Flags["/SYSTEM"].Set {
		fmt.Printf("/SYSTEM is not yet implemented - you set it to %d\n", optSystem)
	}

	if len(optFolder) == 0 {
		optFolder = []string{this.Folder.Name}
@@ -171,21 +153,64 @@ func ActionAdd(cmd *dclish.Command) error {
	if optShutdown == 1 && this.User.Admin == 0 {
		return errors.New("must be an admin to set shutdown")
	}
	if optSystem == 1 {
		if this.User.Admin == 0 {
			return errors.New("must be an admin to set /SYSTEM")
		}
		if this.Folder.Name != "GENERAL" {
			return errors.New("/SYSTEM can only be used in the GENERAL folder")
		}
	}
	if optBroadcast == 1 && this.User.Admin == 0 {
		return errors.New("must be an admin to use /BROADCAST")
	}

	// Handle /EXTRACT and /INDENT: prepend current message text.
	origMsg := ""
	if optExtract == 1 && this.MsgID > 0 {
		original, err := folders.GetMessage(this.User.Login, this.Folder.Name, this.MsgID)
		if err != nil {
			return err
		}
		if optIndent == 1 {
			origMsg = "> " + strings.Join(strings.Split(original.Message, "\n"), "\n> ")
		} else {
			origMsg = original.Message
		}
	}

	message, err := editor.Editor(
		fmt.Sprintf("Enter message for '%s'...", optSubject),
		"Edit message",
		"")
		origMsg)
	if err != nil {
		return err
	}

	// Handle /SIGNATURE: append user's signature.
	if optSignature == 1 {
		sig, ok := this.User.Signature.(string)
		if ok && sig != "" {
			message = message + "\n--\n" + sig
		}
	}

	for i := range optFolder {
		err = folders.CreateMessage(this.User.Login, optSubject, message,
			optFolder[i], optPermanent, optShutdown, optExpiration)
			optFolder[i], optPermanent, optSystem, optShutdown, optExpiration)
		if err != nil {
			return err
		}
	}

	// Handle /BROADCAST and /BELL: create broadcast message.
	if optBroadcast == 1 {
		err = this.Q.CreateBroadcast(ctx, this.User.Login, int64(optBell), message)
		if err != nil {
			return err
		}
	}

	return nil
}

@@ -591,7 +616,7 @@ func ActionReply(cmd *dclish.Command) error {
		return nil
	}
	err = folders.CreateMessage(this.User.Login, subject,
		message, this.Folder.Name, 0, 0, nil)
		message, this.Folder.Name, 0, 0, 0, nil)
	if err != nil {
		fmt.Printf("ERROR: CreateMessage failure (%s).\n", err)
		return nil
+32 −14
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package repl
import (
	"fmt"
	"strings"
	"time"

	"github.com/carlmjohnson/versioninfo"

@@ -148,22 +149,21 @@ func ActionShowUser(cmd *dclish.Command) error {
			}
		}
	}
	/*
		TODO: need to add this.
	var since time.Time
		var err error
	hasSince := false
	if cmd.Flags["/SINCE"].Value != "" {
		if cmd.Flags["/LOGIN"].Set || cmd.Flags["/FOLDER"].Set {
				fmt.Println("ERROR: Must set /[NO]LOGIN or /FOLDER.")
			fmt.Println("ERROR: Can't use /SINCE with /LOGIN or /FOLDER.")
			return nil
		}
		var err error
		since, err = ParseDate(cmd.Flags["/SINCE"].Value)
		if err != nil {
			fmt.Println("ERROR: Invalid date specified.")
			return nil
		}
		hasSince = true
	}
	*/

	// Actually do the thing.
	ctx := storage.Context()
@@ -205,6 +205,16 @@ func ActionShowUser(cmd *dclish.Command) error {
		for _, r := range rows {
			fmt.Printf("%-12s  %s\n", r.Login, r.LastLogin.Format("2006-01-02 15:04:05"))
		}
	} else if cmd.Flags["/ALL"].Set && hasSince {
		rows, err := this.Q.GetLastLoginSince(ctx, since)
		if err != nil {
			fmt.Printf("ERROR: Failed to get list (%s).\n", err)
			return nil
		}
		fmt.Println("User          Last Login")
		for _, r := range rows {
			fmt.Printf("%-12s  %s\n", r.Login, r.LastLogin.Format("2006-01-02 15:04:05"))
		}
	} else if cmd.Flags["/ALL"].Set {
		rows, err := this.Q.GetLastLogin(ctx)
		if err != nil {
@@ -215,6 +225,14 @@ func ActionShowUser(cmd *dclish.Command) error {
		for _, r := range rows {
			fmt.Printf("%-12s  %s\n", r.Login, r.LastLogin.Format("2006-01-02 15:04:05"))
		}
	} else if hasSince {
		r, err := this.Q.GetLastLoginByLoginSince(ctx, login, since)
		if err != nil {
			fmt.Printf("ERROR: Failed to get list (%s).\n", err)
			return nil
		}
		fmt.Println("User          Last Login")
		fmt.Printf("%-12s  %s\n", r.Login, r.LastLogin.Format("2006-01-02 15:04:05"))
	} else {
		r, err := this.Q.GetLastLoginByLogin(ctx, login)
		if err != nil {
+86 −16
Original line number Diff line number Diff line
package repl

import (
	"errors"
	"fmt"

	"git.lyda.ie/pp/bulletin/dclish"
	"git.lyda.ie/pp/bulletin/folders"
	"git.lyda.ie/pp/bulletin/storage"
	"git.lyda.ie/pp/bulletin/this"
)

// ActionCopy handles the `COPY` command.
func ActionCopy(cmd *dclish.Command) error {
	ctx := storage.Context()
	folder := cmd.Args[0]

	destFolder, err := folders.FindFolder(folder)
	if err != nil || destFolder.Name == "" {
		return errors.New("destination folder does not exist")
	}
	writable, err := folders.IsFolderWriteable(destFolder.Name, this.User.Login)
	if err != nil {
		return err
	}
	if !writable {
		return errors.New("no write access to destination folder")
	}

	if cmd.Flags["/MERGE"].Set {
		fmt.Println("Warning: /MERGE is not yet implemented, messages will be appended.")
	}
	if cmd.Flags["/ORIGINAL"].Set {
		fmt.Println("Warning: /ORIGINAL is not yet implemented, messages will be owned by the copier.")
	}

	msgids := []int64{this.MsgID}
	if cmd.Flags["/ALL"].Value == "true" {
		if len(cmd.Args) == 2 {
		var err error
			return errors.New("can't provide a message list and /ALL")
		}
		msgids, err = this.Q.ListMessageIDs(ctx, this.Folder.Name)
		if err != nil {
			return err
		}
	} else if len(cmd.Args) == 2 {
		msgids, err = ParseNumberList(cmd.Args[1])
		if err != nil {
			return err
		}
	}
	fmt.Printf("copy %+v to %s is not implemented\n", msgids, folder)
	/*
		msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)

	err = folders.CopyMessages(this.Folder.Name, destFolder.Name, msgids)
	if err != nil {
		return err
	}
	*/
	fmt.Printf("%d message(s) copied to %s.\n", len(msgids), destFolder.Name)
	return nil
}

// ActionMove handles the `MOVE` command.
func ActionMove(cmd *dclish.Command) error {
	ctx := storage.Context()
	folder := cmd.Args[0]

	destFolder, err := folders.FindFolder(folder)
	if err != nil || destFolder.Name == "" {
		return errors.New("destination folder does not exist")
	}
	writable, err := folders.IsFolderWriteable(destFolder.Name, this.User.Login)
	if err != nil {
		return err
	}
	if !writable {
		return errors.New("no write access to destination folder")
	}

	// Check write access on source folder for deletion.
	srcWritable, err := folders.IsFolderWriteable(this.Folder.Name, this.User.Login)
	if err != nil {
		return err
	}
	if !srcWritable {
		return errors.New("no write access to source folder")
	}

	if cmd.Flags["/MERGE"].Set {
		fmt.Println("Warning: /MERGE is not yet implemented, messages will be appended.")
	}
	if cmd.Flags["/ORIGINAL"].Set {
		fmt.Println("Warning: /ORIGINAL is not yet implemented, messages will be owned by the mover.")
	}

	msgids := []int64{this.MsgID}
	if cmd.Flags["/ALL"].Value == "true" {
		if len(cmd.Args) == 2 {
		var err error
			return errors.New("can't provide a message list and /ALL")
		}
		msgids, err = this.Q.ListMessageIDs(ctx, this.Folder.Name)
		if err != nil {
			return err
		}
	} else if len(cmd.Args) == 2 {
		msgids, err = ParseNumberList(cmd.Args[1])
		if err != nil {
			return err
		}
	}
	fmt.Printf("move %+v to %s is not implemented\n", msgids, folder)
	/*
		msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)

	err = folders.CopyMessages(this.Folder.Name, destFolder.Name, msgids)
	if err != nil {
		return err
	}
	err = folders.DeleteMessages(msgids)
	if err != nil {
		return err
	}
	*/
	fmt.Printf("%d message(s) moved to %s.\n", len(msgids), destFolder.Name)
	return nil
}
Loading