Unverified Commit 46e10831 authored by Kevin Lyda's avatar Kevin Lyda
Browse files

Implement a number of SET commands

parent 62cfedea
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package folders

import (
	"errors"
	"fmt"
	"time"

	"git.lyda.ie/kevin/bulletin/storage"
@@ -40,6 +41,7 @@ func CreateMessage(author, subject, message, folder string, permanent, shutdown
// ReadMessage reads a message for a user.
func ReadMessage(login, folder string, msgid int64) (*storage.Message, error) {
	ctx := storage.Context()
	fmt.Printf("TODO: Make sure %s can read this message.\n", login)
	msg, err := this.Q.ReadMessage(ctx, storage.ReadMessageParams{
		Folder: folder,
		ID:     msgid,
@@ -51,11 +53,6 @@ func ReadMessage(login, folder string, msgid int64) (*storage.Message, error) {
	if msg.ID != int64(msgid) || msgid == 0 {
		return nil, errors.New("Specified message was not found")
	}
	err = this.Q.SetMessageSeen(ctx, storage.SetMessageSeenParams{
		Login:  login,
		Folder: folder,
		Msgid:  int64(msgid),
	})

	return &msg, nil
}
@@ -130,6 +127,16 @@ func FirstMessage(folder string) int64 {
	return first
}

// LastMessage gets the last message in a folder.
func LastMessage(folder string) int64 {
	ctx := storage.Context()
	last, err := this.Q.LastMsgidIgnoringSeen(ctx, folder)
	if err != nil {
		return 0
	}
	return last
}

// ListMessages lists messages.
func ListMessages(folder string) ([]storage.Message, error) {
	ctx := storage.Context()
+22 −76
Original line number Diff line number Diff line
@@ -127,13 +127,6 @@ topic of the message.
  Specifies that the editor is to be used to read the message.  This is
  useful for scanning a long message.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Specifies that if a message header exists, the header will be shown.
  If /HEADER or /NOHEADER is specified, the setting will apply for all
  further reads in the selected folder.  The default is /HEADER.`,
			},
		},
	},
	"CHANGE": {
@@ -176,10 +169,6 @@ This can be suppressed by the qualifier /NEW.
			"/GENERAL": {
				Description: `  Specifies that the message is to be converted from a SYSTEM message to
  a GENERAL message.  This only applies to the GENERAL folder.`,
			},
			"/HEADER": {
				Description: `  Specifies  that the  message header  is to  be replaced.  You will  be
  prompted for the new message description.`,
			},
			"/NEW": {
				Description: `  If the editor is to be used for replacing the text of the message, NEW
@@ -236,17 +225,11 @@ The key words CURRENT and LAST can also be specified in the range in,
place of an actual number, i.e. CURRENT-LAST, 1-CURRENT, etc.`,
		MinArgs: 1,
		MaxArgs: 2,
		Action:  ActionCopy,
		Flags: dclish.Flags{
			"/ALL": {
				Description: `  Specifies to copy all the messages in the old folder.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Valid  only if  destination folder  is  a news  group. Specifies  that
  header of  message is to  be included with the  text when the  text is
  copied. The default is /NOHEADER.`,
			},
			"/MERGE": {
				Description: `  Specifies that the  original date and time of the  copied messages are
  saved and that the messages  are placed in correct chronological order
@@ -382,13 +365,6 @@ of the message again, you can enter the CURRENT command.
				Description: `  Specifies that the editor  is to be used to read  the message. This is
  useful for scanning a long message.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Specifies that if a message header exists, the header will be shown.
  If /HEADER or /NOHEADER is specified, the setting will apply for all
  further reads in the selected folder.  The default is /HEADER.`,
			},
		},
	},
	"DELETE": {
@@ -560,13 +536,6 @@ place of an actual number, i.e. CURRENT-LAST, 1-CURRENT, etc.`,
			"/FF": {
				Description: `  Specifies that a form feed is placed between messages in the file.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Controls whether a  header containing the owner, subject,  and date of
  the  message is  written in  the  file. The  default is  to write  the
  header.`,
			},
			"/NEW": {
				Description: `  Specifies  that  a new  file  is  to  be  created. Otherwise,  if  the
  specified file exists, the file would be appended to that file.`,
@@ -631,10 +600,6 @@ where one left off after one has read a message.
				Description: `  If specified,  causes the listing  to be reinitialized and  start from
  the first folder.`,
			},
			"/SUBSCRIBE": {
				Description: `  If  specified,  lists  only  those   news  folders  which  have  been
  subscribed to.`,
			},
		},
	},
	"LAST": {
@@ -642,18 +607,12 @@ where one left off after one has read a message.

  Format:
    LAST`,
		Action: ActionLast,
		Flags: dclish.Flags{
			"/EDIT": {
				Description: `  Specifies that the editor  is to be used to read  the message. This is
  useful for scanning a long message.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Specifies that if  a message header exists, the header  will be shown.
  If /HEADER or  /NOHEADER is specified, the setting will  apply for all
  further reads in the selected folder. The default is /HEADER.`,
			},
		},
	},
	"MAIL": {
@@ -674,13 +633,6 @@ specified as xxx%"""address""".`,
			"/EDIT": {
				Description: `  Specifies that  the editor is  to be used  to edit the  message before
  mailing it.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Controls whether a  header containing the owner, subject,  and date of
  the  message is  written in  the  mail. The  default is  to write  the
  header.`,
			},
			"/SUBJECT": {
				Description: `/SUBJECT=text
@@ -768,6 +720,7 @@ The key words CURRENT and LAST can also be specified in the range in,
place of an actual number, i.e. CURRENT-LAST, 1-CURRENT, etc.`,
		MinArgs: 1,
		MaxArgs: 2,
		Action:  ActionMove,
		Flags: dclish.Flags{
			"/ALL": {
				Description: `  Specifies to move  all the messages from the old  folder. Note: If the
@@ -797,13 +750,6 @@ you would like to skip over.`,
				Description: `  Specifies that the editor  is to be used to read  the message. This is
  useful for scanning a long message.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Specifies that if  a message header exists, the header  will be shown.
  If /HEADER or  /NOHEADER is specified, the setting will  apply for all
  further reads in the selected folder. The default is /HEADER.`,
			},
		},
	},
	"PRINT": {
@@ -844,12 +790,6 @@ it's subject line, DIRECTORY/PRINT/SUBJ would allow you do it.`,
  to have  your job  print, the  system manager  should stop  the queue,
  physically change  the paper stock  on the output device,  and restart
  the queue specifying the new form type as the mounted form.)`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Controls whether a header containing the owner, subject, and date of the
  message is printed at the beginning. The default is to write the header.`,
			},
			"/NOTIFY": {
				Description: `/[NO]NOTIFY
@@ -904,13 +844,6 @@ the help on the SEEN command.`,
			"/EDIT": {
				Description: `  Specifies that the editor  is to be used to read  the message. This is
  useful for scanning a long message.`,
			},
			"/HEADER": {
				Description: `/[NO]HEADER

  Specifies that if  a message header exists, the header  will be shown.
  If /HEADER or  /NOHEADER is specified, the setting will  apply for all
  further reads in the selected folder. The default is /HEADER.`,
			},
			"/MARKED": {
				Description: `  Specifies to read only messages that have been marked (marked messages
@@ -1263,12 +1196,14 @@ sure they are read.

  Format:
    SET ALWAYS`,
				Action: ActionSetAlways,
			},
			"NOALWAYS": {
				Description: `Removes ALWAYS attribute from the selected folder.

  Format:
    SET NOALWAYS`,
				Action: ActionSetAlways,
			},
			"BRIEF": {
				Description: `Controls whether you will be alerted upon logging  that  there  are  new
@@ -1281,6 +1216,7 @@ READNEW setting (and visa versa).

  Format:
    SET BRIEF`,
				Action: ActionSetBrief,
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the  SET BRIEF option is the default  for all users for
@@ -1306,6 +1242,7 @@ privileged qualifier.`,

  Format:
    SET NOBRIEF`,
				Action: ActionSetBrief,
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the SET NOBRIEF option is the default for all users for
@@ -1385,6 +1322,7 @@ In a cluster, if the logical name MAIL$SYSTEM_FLAGS is defined so that
bit 1 is set, users will be notified no matter which node they are logged
in to.  If you wish to disable this, you should define BULL_SYSTEM_FLAGS
so that bit 1 is cleared.`,
				Action: ActionSetNotify,
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the SET NOTIFY option  is the default for all users for
@@ -1410,6 +1348,7 @@ so that bit 1 is cleared.`,

  Format:
    SET NONOTIFY [folder-name]`,
				Action:  ActionSetNonotify,
				MaxArgs: 1,
			},
			"PRIVILEGES": {
@@ -1560,14 +1499,21 @@ is allowed to have SYSTEM and SHUTDOWN messages added to it. This is a
privileged command.

  Format:
    SET [NO]SYSTEM
    SET SYSTEM

By default, the GENERAL folder is a SYSTEM folder, and the setting for
that folder cannot be removed.
that folder cannot be removed.`,
				Action: ActionSetSystem,
			},
			"NOSYSTEM": {
				Description: `Specifies that the selected folder is not a SYSTEM folder.

If the selected folder is remote, /SYSTEM cannot be specified unless the
folder at the other node is also a SYSTEM folder.
`,
  Format:
    SET NOSYSTEM

By default, the GENERAL folder is a SYSTEM folder, and the setting for
that folder cannot be removed.`,
				Action: ActionSetNosystem,
			},
		},
	},
@@ -1654,7 +1600,7 @@ have done this.`,
  Specifies to display  only those users whose latest  read message date
  is the  same date  or later  than the  specified date.  If no  date is
  specified, the  date of the  current message  is used. Only  valid for
  folders or with /LOGIN. Use /START for newsgroups.`,
  folders or with /LOGIN.`,
					},
				},
			},
+41 −5
Original line number Diff line number Diff line
@@ -200,6 +200,17 @@ func ActionFirst(_ *dclish.Command) error {
	return nil
}

// ActionLast handles the `LAST` command.
func ActionLast(_ *dclish.Command) error {
	msgid := folders.LastMessage(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.
@@ -219,6 +230,31 @@ func ActionNext(_ *dclish.Command) error {
	return nil
}

// ActionPrint handles the `PRINT` command.
func ActionPrint(cmd *dclish.Command) error {
	// TODO: handle flags.
	msgids := []int64{this.MsgID}
	if len(cmd.Args) == 1 {
		var err error
		msgids, err = ParseNumberList(cmd.Args[0])
		if err != nil {
			return err
		}
	}
	print("\033[5i")
	for _, msgid := range msgids {
		msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid)
		if err != nil {
			fmt.Printf("Message %d not found.\n")
		} else {
			fmt.Print(msg.String())
		}
		print("\n\v")
	}
	print("\033[4i")
	return nil
}

// ActionRead handles the `READ` command.
func ActionRead(cmd *dclish.Command) error {
	// TODO: handle flags.
@@ -234,11 +270,11 @@ func ActionRead(cmd *dclish.Command) error {
	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())
	if pager.Pager(msg.String()) {
		folders.MarkSeen([]int64{msgid})
		msgid = folders.NextMsgid(this.User.Login, this.Folder.Name, msgid)
		this.MsgID = max(this.MsgID, msgid)
	}
	return nil
}

repl/msg-text.go

0 → 100644
+8 −0
Original line number Diff line number Diff line
package repl

import "strings"

func quote(content string) string {
	lines := strings.Split(content, "\n")
	return "> " + strings.Join(lines, "\n> ")
}
+4 −1
Original line number Diff line number Diff line
@@ -34,8 +34,10 @@ func Loop() error {
	// TODO: Remove once commands are implemented.
	unimplemented := 0
	total := len(commands)
	fmt.Print("Missing")
	for c := range commands {
		if commands[c].Action == nil {
			fmt.Printf(" [%s]", c)
			unimplemented++
		}
		if len(commands[c].Commands) > 0 {
@@ -43,13 +45,14 @@ func Loop() error {
			unimplemented--
			for subc := range commands[c].Commands {
				if commands[c].Commands[subc].Action == nil {
					fmt.Printf(" [%s %s]", c, subc)
					unimplemented++
				}
			}
			total += len(commands[c].Commands)
		}
	}
	fmt.Printf("TODO: %d out of %d commands still to be implemented.\n",
	fmt.Printf("\nTODO: %d out of %d commands still to be implemented.\n",
		unimplemented, total)
	// TODO: END

Loading