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