From f029cbfbb4d89d55aee01fc89f08b0388c45575e Mon Sep 17 00:00:00 2001
From: Kevin Lyda <kevin@lyda.ie>
Date: Tue, 6 May 2025 21:55:41 +0100
Subject: [PATCH] Remove NEWS related things
Remove NEWS related commands, flags and help text.
---
accounts/accounts.go | 10 +-
dclish/dclish.go | 17 +++-
go.mod | 1 +
go.sum | 2 +
repl/command.go | 236 +++++++++----------------------------------
repl/folders.go | 29 ++++++
repl/help.go | 60 ++++++++++-
7 files changed, 159 insertions(+), 196 deletions(-)
create mode 100644 repl/folders.go
diff --git a/accounts/accounts.go b/accounts/accounts.go
index acd5b25..def5a4b 100644
--- a/accounts/accounts.go
+++ b/accounts/accounts.go
@@ -16,10 +16,12 @@ import (
// UserData is the type for holding user data. Things like preferences,
// unread message counts, signatures, etc.
type UserData struct {
- Account string
- FullName string
- pref *sql.DB
- bull *sql.DB
+ Account string
+ FullName string
+ pref *sql.DB
+ bull *sql.DB
+ CurrentFolder string
+ CurrentMessage int
}
// User is the user for this process. It is loaded by the `Verify` function.
diff --git a/dclish/dclish.go b/dclish/dclish.go
index 94ebb59..19c93fe 100644
--- a/dclish/dclish.go
+++ b/dclish/dclish.go
@@ -54,7 +54,8 @@ func (c Commands) ParseAndRun(line string) error {
case 1:
cmd = c[possibles[0]]
default:
- fmt.Printf("ERROR: Ambiguous command '%s' (matches %s)\n", words[0], possibles)
+ fmt.Printf("ERROR: Ambiguous command '%s' (matches %s)\n",
+ words[0], strings.Join(possibles, ", "))
return nil
}
}
@@ -78,7 +79,8 @@ func (c Commands) ParseAndRun(line string) error {
wordup := strings.ToUpper(flag)
flg, ok := cmd.Flags[wordup]
if !ok {
- fmt.Printf("ERROR: Flag '%s' not recognised.", args[i])
+ fmt.Printf("ERROR: Flag '%s' not recognised.\n", args[i])
+ return nil
}
flg.Value = val
} else {
@@ -90,13 +92,22 @@ func (c Commands) ParseAndRun(line string) error {
}
flg, ok := cmd.Flags[wordup]
if !ok {
- fmt.Printf("ERROR: Flag '%s' not recognised.", args[i])
+ fmt.Printf("ERROR: Flag '%s' not recognised.\n", args[i])
+ return nil
}
flg.Value = value
}
} else {
+ if len(cmd.Args) == cmd.MaxArgs {
+ fmt.Printf("ERROR: Too many args at '%s'\n", args[i])
+ return nil
+ }
cmd.Args = append(cmd.Args, args[i])
}
}
+ if len(cmd.Args) < cmd.MinArgs {
+ fmt.Println("ERROR: Not enough args.")
+ return nil
+ }
return cmd.Action(cmd)
}
diff --git a/go.mod b/go.mod
index f7faa44..cba97c6 100644
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
diff --git a/go.sum b/go.sum
index cd2ef07..a9657c7 100644
--- a/go.sum
+++ b/go.sum
@@ -10,6 +10,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
diff --git a/repl/command.go b/repl/command.go
index ad080b4..a963b64 100644
--- a/repl/command.go
+++ b/repl/command.go
@@ -163,9 +163,7 @@ useful for scanning a long message.`,
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 for non-
-NEWS folders, /NOHEADER for NEWS folders. If the SET STRIP command
-is set for the folder, it will change the default to be /HEADER.`,
+further reads in the selected folder. The default is /HEADER.`,
},
},
},
@@ -275,12 +273,6 @@ in place of an actual number, i.e. CURRENT-LAST, 1-CURRENT, etc.`,
"/ALL": {
Description: `Specifies to copy all the messages in the old folder.`,
},
- "/GROUPS": {
- Description: `/GROUPS=(newsgroup,[...])
-
-Valid only if a NEWS group is selected. Specifies to send the message to
-the specified NEWS group(s) in addition to the selected NEWS group.`,
- },
"/HEADER": {
Description: `/[NO]HEADER
@@ -464,9 +456,7 @@ useful for scanning a long message.`,
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 for non-
-NEWS folders, /NOHEADER for NEWS folders. If the SET STRIP command
-is set for the folder, it will change the default to be /HEADER.`,
+further reads in the selected folder. The default is /HEADER.`,
},
},
},
@@ -544,6 +534,7 @@ newest message. If there are no new messages, listing will start at the
first message, or if a message has already been read, it will start at
that message.`,
MaxArgs: 1,
+ Action: ActionDirectory,
Flags: dclish.Flags{
"/ALL": {
Description: `Lists all messages. Used if the qualifiers /MARKED, /UNMARKED, /SEEN,
@@ -564,8 +555,7 @@ Indicates the last message number you want to display.`,
"/FOLDERS": {
Description: `Lists the available message folders. Shows last message date and number
of messages in folder. An asterisk (*) next to foldername indicates
-that there are unread messages in that folder. This will not show
-newsgroups. To see newsgroups, use the NEWS command or DIR/NEWS.`,
+that there are unread messages in that folder.`,
},
"/MARKED": {
Description: `Lists messages that have been marked (indicated by an asterisk).
@@ -595,10 +585,6 @@ read. To see all messages, use either /ALL, or reselect the folder.`,
"/NEW": {
Description: `Specifies to start the listing of messages with the first unread
message.`,
- },
- "/NEWS": {
- Description: `Lists the available news groups. This does the same thing as the NEWS
-command. See that command for qualifiers which apply.`,
},
"/PRINT": {
Description: `Specifies that the text of the messages which are found by the
@@ -692,7 +678,8 @@ file exists, the file would be appended to that file.`,
Description: `To obtain help on any topic, type:
HELP topic`,
- Action: ActionHelp,
+ MaxArgs: 1,
+ Action: ActionHelp,
},
"INDEX": {
Description: `Gives directory listing of all folders in alphabetical order. If the
@@ -703,6 +690,7 @@ off after one has read a message.
Format:
INDEX`,
+ Action: ActionIndex,
Flags: dclish.Flags{
"/MARKED": {
Description: `Lists messages that have been marked (marked messages are indicated by
@@ -779,9 +767,7 @@ useful for scanning a long message.`,
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 for non-
-NEWS folders, /NOHEADER for NEWS folders. If the SET STRIP command
-is set for the folder, it will change the default to be /HEADER.`,
+further reads in the selected folder. The default is /HEADER.`,
},
},
},
@@ -834,11 +820,27 @@ as unmarked.
MARK [message-number or numbers]
UNMARK [message-number or numbers]
-NOTE: The list of marked messages for non-NEWS folders are stored in a
-file username.BULLMARK, and NEWS folders are stored in
-username.NEWSMARK. The files are created in the directory pointed to by
-the logical name BULL_MARK. If BULL_MARK is not defined, SYS$LOGIN
-will be used.`,
+NOTE: The list of marked messages are stored in a file username.BULLMARK.
+The files are created in the directory pointed to by the logical name
+BULL_MARK. If BULL_MARK is not defined, SYS$LOGIN will be used.`,
+ MaxArgs: 1,
+ },
+ "UNMARK": {
+ Description: `Sets the current or message-id message as marked. Marked messages are
+displayed with an asterisk in the left hand column of the directory
+listing. A marked message can serve as a reminder of important
+information. The UNMARK command sets the current or message-id message
+as unmarked.
+
+ Format:
+
+ MARK [message-number or numbers]
+ UNMARK [message-number or numbers]
+
+NOTE: The list of marked messages are stored in a file username.BULLMARK.
+The files are created in the directory pointed to by the logical name
+BULL_MARK. If BULL_MARK is not defined, SYS$LOGIN will be used.`,
+ MaxArgs: 1,
},
"MODIFY": {
Description: `Modifies the database information for the current folder. Only the
@@ -906,19 +908,6 @@ in place of an actual number, i.e. CURRENT-LAST, 1-CURRENT, etc.`,
Description: `Specifies to move all the messages from the old folder. Note: If the
old folder is remote, they will be copied but not deleted, as only one
message can be deleted from a remote folder at a time.`,
- },
- "/GROUPS": {
- Description: `/GROUPS=(newsgroup,[...])
-
-Valid only if a NEWS group is selected. Specifies to send the message to
-the specified NEWS group(s) in addition to the selected NEWS group.`,
- },
- "/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 moved messages are
@@ -946,82 +935,7 @@ useful for scanning a long message.`,
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 for non-
-NEWS folders, /NOHEADER for NEWS folders. If the SET STRIP command
-is set for the folder, it will change the default to be /HEADER.`,
- },
- },
- },
- "POST": {
- Description: `If a NEWS group is selected, posts a message to that group. If a normal
-folder is selected, sends a message via MAIL to the network mailing list
-which is associated with the selected folder. The address of the
-mailing list must be stored using either CREATE/DESCRIPTION or
-MODIFY/DESCRIPTION. See help on those commands for more information.
-
- Format:
- POST [file-name]`,
- MaxArgs: 1,
- Flags: dclish.Flags{
- "/CC": {
- Description: `/CC=user[s]
-Specifies additional users that should receive the mail message.`,
- },
- "/EDIT": {
- Description: `Specifies that the editor is to be used for creating the mail message.`,
- },
- "/EXTRACT": {
- Description: `Specifies that the text of the message that is being read should be
-included in the mail message. This qualifier is valid only when used
-with /EDIT. The text of the message is indented with > at the
-beginning of each line. This can be suppressed with /NOINDENT.`,
- },
- "/GROUPS": {
- Description: `/GROUPS=(newsgroup,[...])
-
-Valid only if a NEWS group is selected. Specifies to send the message to
-the specified NEWS group(s) in addition to the selected NEWS group.`,
- },
- "/NOINDENT": {
- Description: `See /EXTRACT for information on this qualifier.`,
- },
- "/NOSIGNATURE": {
- Description: `Specifies to suppress the automatically appended signature, if one exists.
-Signatures are appended for postings to mailing lists and to responds.
-See the help topic POST Signature_file for signature information.`,
- },
- "/SUBJECT": {
- Description: `/SUBJECT=text
-
-Specifies the subject of the mail message. If the text consists of more
-than one word, enclose the text in quotation marks (").
-
-If you omit this qualifier, you will prompted for the subject.`,
- },
- "Signature_file": {
- Description: `It is possibly to have the contents of a file be automatically appended
-to the end of a message added with the POST and/or the RESPOND command.
-This file is known as a signature file, and it typically contains one's
-name, address, or perhaps a favorite quote. The name of the file should
-be SYS$LOGIN:BULL_SIGNATURE.TXT, and it should be a simple text file. In
-order to specify a different file to use, define the logical name
-BULL_SIGNATURE to point to the desired file.
-
-It is possible to specify that portions or all of the signature file are
-to be included only for specific folders or news groups. Simply surround
-the exclusive text starting with the line "START <folder-name>" and ending
-with the line "END", i.e.
-
-START INFOVAX
-This line will only appear in the INFOVAX folder.
-END
-START MISC.TEST
-This line will only appear in the news folder MISC.TEST.
-END
-This line will appear in all postings.
-
-Note that an empty line is automatically created to separate the text of
-the message and the contents of the signature file.`,
+further reads in the selected folder. The default is /HEADER.`,
},
},
},
@@ -1127,9 +1041,7 @@ useful for scanning a long message.`,
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 for non-
-NEWS folders, /NOHEADER for NEWS folders. If the SET STRIP command
-is set for the folder, it will change the default to be /HEADER.`,
+further reads in the selected folder. The default is /HEADER.`,
},
"/MARKED": {
Description: `Specifies to read only messages that have been marked (marked messages
@@ -1233,13 +1145,6 @@ message.`,
mail message. This qualifier is valid only when used with /EDIT. The
text of the message is indented with > at the beginning of each line.
This can be suppressed with /NOINDENT.`,
- },
- "/GROUPS": {
- Description: `/GROUPS=(newsgroup,[...])
-
-Valid only if a NEWS group is selected and /LIST is present. Specifies
-to send the message to the specified NEWS group(s) in addition to the
-selected NEWS group.`,
},
"/LIST": {
Description: `Specifies that the reply should also be sent to the network mailing list
@@ -1333,18 +1238,14 @@ command sets the current or message-id message as unseen.
SEEN [message-number or numbers]
UNSEEN [message-number or numbers]
-Keeping track of seen messages requires very little overhead for NEWS
-folders. However, there is a moderate overhead for regular non-NEWS
-folders. If you have used the SEEN command and wish to disable the
-automatic marking of messages in regular folders as SEEN when they are
-read, type the command SEEN/NOREAD. To reenable, simply use the SEEN
-command again.
-
-NOTE: The list of SEEN messages for non-NEWS folders are stored in a
-file username.BULLMARK, and NEWS folders are stored in
-username.NEWSMARK. The files are created in the directory pointed to by
-the logical name BULL_MARK. If BULL_MARK is not defined, SYS$LOGIN
-will be used.`,
+If you have used the SEEN command and wish to disable the automatic
+marking of messages in regular folders as SEEN when they are read, type
+the command SEEN/NOREAD. To reenable, simply use the SEEN command again.
+
+NOTE: The list of SEEN messages are stored in a
+file username.BULLMARK. NEWSMARK. The files are created in the directory
+pointed to by the logical name BULL_MARK. If BULL_MARK is not defined,
+SYS$LOGIN will be used.`,
MinArgs: 1,
MaxArgs: 1,
},
@@ -1361,18 +1262,14 @@ command sets the current or message-id message as unseen.
SEEN [message-number or numbers]
UNSEEN [message-number or numbers]
-Keeping track of seen messages requires very little overhead for NEWS
-folders. However, there is a moderate overhead for regular non-NEWS
-folders. If you have used the SEEN command and wish to disable the
-automatic marking of messages in regular folders as SEEN when they are
-read, type the command SEEN/NOREAD. To reenable, simply use the SEEN
-command again.
-
-NOTE: The list of SEEN messages for non-NEWS folders are stored in a
-file username.BULLMARK, and NEWS folders are stored in
-username.NEWSMARK. The files are created in the directory pointed to by
-the logical name BULL_MARK. If BULL_MARK is not defined, SYS$LOGIN
-will be used.`,
+If you have used the SEEN command and wish to disable the automatic
+marking of messages in regular folders as SEEN when they are read, type
+the command SEEN/NOREAD. To reenable, simply use the SEEN command again.
+
+NOTE: The list of SEEN messages are stored in a
+file username.BULLMARK. NEWSMARK. The files are created in the directory
+pointed to by the logical name BULL_MARK. If BULL_MARK is not defined,
+SYS$LOGIN will be used.`,
MinArgs: 1,
MaxArgs: 1,
},
@@ -1397,14 +1294,7 @@ BULLCP process running (invoked by BULLETIN/STARTUP command.)
After selecting a folder, the user will notified of the number of unread
messages, and the message pointer will be placed at the first unread
-message.
-
-BULLETIN automatically determines if the selcted name is a NEWS group by
-detecting if a period is present in the name being specified, as most
-NEWS groups contain a period, whereas a real folder cannot. A few
-special NEWS groups, i.e. JUNK and CONTROL, do not contain a period. If
-desired, you can select these groups by enclosing them in double quotes
-("), and typing the name in lower case.`,
+message.`,
Flags: dclish.Flags{
"/MARKED": {
Description: `Selects only messages that have been marked (indicated by an asterisk).
@@ -1524,8 +1414,8 @@ users must be at least 2.
SET BBOARD [username]
-BBOARD cannot be set for remote folders. See also the commands SET
-STRIP and SET DIGEST for options on formatting BBOARD messages.
+BBOARD cannot be set for remote folders. See also the command SET
+DIGEST for options on formatting BBOARD messages.
If BULLCP is running, BBOARD is updated every 15 minutes. If you want
to length this period, define BULL_BBOARD_UPDATE to be the number of
@@ -1980,19 +1870,6 @@ specified, the selected folder is modified. Valid only with NOSHOWNEW.
Specifies that SHOWNEW is a permanent flag and cannot be changed by the
individual, except if changing to READNEW. This is a privileged qualifier.
-`,
- },
- "STRIP": {
- Description: `Affect only messages which are added via either the BBOARD option, or
-written directly from a network mailing program (i.e. PMDF). If
-STRIP is set, the header of the mail message will be stripped off
-before it is stored as a BULLETIN message.
-
- Format:
-
- SET [NO]STRIP
-
-The command SHOW FOLDER/FULL will show if STRIP has been set.
`,
},
"SYSTEM": {
@@ -2118,13 +1995,6 @@ linked.
},
},
},
- "SUBSCRIBE": {
- Description: `Used only for NEWS folders. Specifies that BULLETIN will keep track of
-the newest message that has been read for that NEWS folder. When the
-NEWS folder is selected, the message pointer will automatically point to
-the next newest message that has not been read.
-`,
- },
"UNDELETE": {
Description: `Undeletes he specified message if the message was deleted using the
DELETE command. Deleted messages are not actually deleted but have
@@ -2135,12 +2005,6 @@ string (DELETED) when either reading or doing a directory listing.
Format:
UNDELETE [message-number]
-`,
- },
- "UNSUBSCRIBE": {
- Description: `Used only for NEWS folders. Specifies that BULLETIN will no longer keep
-track of the newest message that has been read for that NEWS folder. See the
-SUBSCRIBE command for further info.
`,
},
}
diff --git a/repl/folders.go b/repl/folders.go
new file mode 100644
index 0000000..3e0db73
--- /dev/null
+++ b/repl/folders.go
@@ -0,0 +1,29 @@
+// Package repl implements the main event loop.
+package repl
+
+import (
+ "fmt"
+ "strings"
+
+ "git.lyda.ie/kevin/bulletin/accounts"
+ "git.lyda.ie/kevin/bulletin/dclish"
+)
+
+// ActionDirectory handles the `DIRECTORY` command. This lists all the
+// messages in the current folder.
+func ActionDirectory(cmd *dclish.Command) error {
+ // TODO: flag parsing.
+ if len(cmd.Args) == 1 {
+ folder := strings.ToUpper(cmd.Args[0])
+ // TODO: Check folder is valid.
+ accounts.User.CurrentFolder = folder
+ }
+ fmt.Println("TODO: List messages in folder")
+ return nil
+}
+
+// ActionIndex handles the `INDEX` command. This lists all the folders.
+func ActionIndex(cmd *dclish.Command) error {
+ fmt.Printf("TODO: implement INDEX:\n%s\n\n", cmd.Description)
+ return nil
+}
diff --git a/repl/help.go b/repl/help.go
index 007dfe0..d3dc916 100644
--- a/repl/help.go
+++ b/repl/help.go
@@ -3,6 +3,7 @@ package repl
import (
"fmt"
+ "sort"
"strings"
"git.lyda.ie/kevin/bulletin/dclish"
@@ -64,9 +65,61 @@ in a state such that they would be inaccessible by other users.)
}
func init() {
+ // Add all command help.
+ buf := &strings.Builder{}
for c := range commands {
- helpmap[c] = commands[c].Description
+ fmt.Fprint(buf, commands[c].Description)
+ if len(commands[c].Flags) > 0 {
+ flgs := make([]string, len(commands[c].Flags))
+ i := 0
+ for flg := range commands[c].Flags {
+ flgs[i] = flg
+ i++
+ }
+ sort.Strings(flgs)
+ for i := range flgs {
+ fmt.Fprintf(buf, "\n%s %s", flgs[i], commands[c].Flags[flgs[i]].Description)
+ }
+ }
+ helpmap[c] = buf.String()
+ buf.Reset()
+ }
+
+ // Add a list of topics.
+ topics := make([]string, len(helpmap))
+ i := 0
+ maxlen := 0
+ for topic := range helpmap {
+ maxlen = max(len(topic), maxlen)
+ topics[i] = topic
+ i++
+ }
+ maxlen = maxlen + 2
+ sort.Strings(topics)
+
+ buf.Reset()
+ linelen := 2
+ fmt.Fprint(buf, `The following command and topics are available for more help
+
+ `)
+ for i := range topics {
+ linelen += maxlen
+ if linelen > 78 {
+ fmt.Fprint(buf, "\n ")
+ linelen = maxlen + 2
+ }
+ // TODO: Kludge - move helpmap to map[string]TopicType which has a
+ // description and a display name.
+ switch topics[i] {
+ case "FOLDERS":
+ fmt.Fprintf(buf, "%-*s", maxlen, "Folders")
+ case "CTRL-C":
+ fmt.Fprintf(buf, "%-*s", maxlen, "Ctrl-C")
+ default:
+ fmt.Fprintf(buf, "%-*s", maxlen, topics[i])
+ }
}
+ helpmap["TOPICS"] = buf.String()
}
// ActionHelp handles the `HELP` command.
@@ -91,11 +144,12 @@ func ActionHelp(cmd *dclish.Command) error {
case 1:
helptext = helpmap[possibles[0]]
default:
- fmt.Printf("ERROR: Ambiguous topic '%s' (matches %s)\n", cmd.Args[0], possibles)
+ fmt.Printf("ERROR: Ambiguous topic '%s' (matches %s)\n",
+ cmd.Args[0], strings.Join(possibles, ", "))
return nil
}
}
- fmt.Printf("%s\n\n", helptext)
+ fmt.Printf("\n%s\n\n", helptext)
return nil
}
--
GitLab