Loading dclish/dclish.go +25 −3 Original line number Diff line number Diff line Loading @@ -106,11 +106,35 @@ func split(line string) []string { return words } // PrefixMatch searches for a command in a list of possible commands. func PrefixMatch(command string, commands []string) (string, error) { cmd := strings.ToUpper(command) possibles := []string{} for i := range commands { if strings.HasPrefix(cmd, commands[i]) { possibles = append(possibles, commands[i]) } } switch len(possibles) { case 0: return "", fmt.Errorf("Unknown command '%s'", command) case 1: return possibles[0], nil default: return "", fmt.Errorf("Ambiguous command '%s' (matches %s)", command, strings.Join(possibles, ", ")) } } // ParseAndRun parses a command line and runs the command. func (c Commands) ParseAndRun(line string) error { // Split into words. words := split(line) return c.run(words) } func (c Commands) run(words []string) error { // Find the command. wordup := strings.ToUpper(words[0]) cmd, ok := c[wordup] Loading Loading @@ -141,9 +165,7 @@ func (c Commands) ParseAndRun(line string) error { fmt.Printf("ERROR: missing subcommand for %s.\n", wordup) return nil } // TODO: quoting is probably an issue here - break ParseAndRun into ParseAndRun + Run. newline := strings.Join(words[1:], " ") return cmd.Commands.ParseAndRun(newline) return cmd.Commands.run(words[1:]) } if cmd.Action == nil { Loading folders/sql/1_create_table.up.sql +30 −23 Original line number Diff line number Diff line CREATE TABLE users ( login VARCHAR(12) NOT NULL PRIMARY KEY, name VARCHAR(53) NOT NULL, admin INT DEFAULT 0, disabled INT DEFAULT 0, admin INT DEFAULT 0 NOT NULL, moderator INT DEFAULT 0 NOT NULL, disabled INT DEFAULT 0 NOT NULL, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL Loading Loading @@ -34,16 +35,15 @@ END; CREATE TABLE folders ( name VARCHAR(25) NOT NULL PRIMARY KEY, always INT DEFAULT 0, brief INT DEFAULT 0, description VARCHAR(53) NOT NULL, notify INT DEFAULT 0, owner VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, readnew INT DEFAULT 0, shownew INT DEFAULT 0, system INT DEFAULT 0, expire INT DEFAULT 14, visibility TEXT DEFAULT 'public', always INT DEFAULT 0 NOT NULL, brief INT DEFAULT 0 NOT NULL, description VARCHAR(53) DEFAULT 0 NOT NULL, notify INT DEFAULT 0 NOT NULL, readnew INT DEFAULT 0 NOT NULL, shownew INT DEFAULT 0 NOT NULL, system INT DEFAULT 0 NOT NULL, expire INT DEFAULT 14 NOT NULL, visibility TEXT DEFAULT 'public' NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL ) WITHOUT ROWID; Loading Loading @@ -87,7 +87,7 @@ END; INSERT INTO folders (name, description, system, shownew, owner) VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1, 'SYSTEM'); CREATE TABLE co_owners ( CREATE TABLE owners ( folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, owner VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, Loading @@ -95,11 +95,11 @@ CREATE TABLE co_owners ( PRIMARY KEY (folder, owner) ) WITHOUT ROWID; CREATE TRIGGER co_owners_after_update_update_at AFTER UPDATE ON co_owners FOR EACH ROW CREATE TRIGGER owners_after_update_update_at AFTER UPDATE ON owners FOR EACH ROW WHEN NEW.update_at = OLD.update_at --- avoid infinite loop BEGIN UPDATE co_owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner; UPDATE owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner; END; CREATE TABLE messages ( Loading @@ -108,8 +108,8 @@ CREATE TABLE messages ( author VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, subject VARCHAR(53) NOT NULL, message TEXT NOT NULL, permanent INT DEFAULT 0, shutdown INT DEFAULT 0, permanent INT DEFAULT 0 NOT NULL, shutdown INT DEFAULT 0 NOT NULL, expiration TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, Loading @@ -118,7 +118,7 @@ CREATE TABLE messages ( CREATE INDEX messages_idx_shutdown ON messages(shutdown); CREATE INDEX messages_idx_expiration ON messages(expiration); CREATE TABLE read ( CREATE TABLE seen ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, msgid INT, Loading @@ -142,13 +142,20 @@ CREATE TABLE mark ( ON UPDATE CASCADE ) WITHOUT ROWID; CREATE TABLE access ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (login, folder), ) WITHOUT ROWID; --- TODO: The following is incomplete: --- User configs. CREATE TABLE config ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, always INT NOT NULL, always INT NOT NULL DEFAULT 0, alert INT NOT NULL DEFAULT 0, --- 0=no, 1=brief, 2=readnew always INT NOT NULL ) WITHOUT ROWID; --- System configs. Loading repl/command.go +22 −60 Original line number Diff line number Diff line Loading @@ -1439,16 +1439,22 @@ to see what is presently set. This is a privileged command. The parameters are one or more privileges separated by commas. To remove a privilege, specify the privilege preceeded by "NO". If /ID is specified, the parameters are rights identifiers.`, Flags: dclish.Flags{ "/ID": { Description: `/[NO]ID specified, the parameters are rights identifiers. If specified, then the rights identifier which is specified as the parameter will allow users holding that rights identifier to execute privileged commands. If /NOID is specified, the identifier is removed.`, }, }, For the reimplementation this is used to manage users. The following parameters are available. Format: SET PRIVILEGES CREATE login SET PRIVILEGES DELETE login SET PRIVILEGES SSH [login] SET PRIVILEGES [NO]ADMIN login SET PRIVILEGES [NO]MOD login [folder] SET PRIVILEGES ENABLE login SET PRIVILEGES DISABLE login`, MinArgs: 1, MaxArgs: 3, Action: ActionSetPrivileges, }, "PROMPT_EXPIRE": { Description: `Specifies that a user will be prompted for an expiration date when Loading Loading @@ -1492,17 +1498,8 @@ the EXIT command will cause you to skip to those folders. (See HELP SET SYSTEM for a description of a SYSTEM folder).`, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET [NO]READNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the [NO]READNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, Description: ` Specifies that the SET READNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, }, "/PERMANENT": { Description: `/[NO]PERMANENT Loading @@ -1515,30 +1512,11 @@ SYSTEM for a description of a SYSTEM folder).`, "NOREADNEW": { Description: `Turns off READNEW. Format: SET NOREADNEW NOTE: If you have several folders with READNEW enabled, each folder's messages will be displayed separately. However, if you EXIT the READNEW mode before all the folders have been displayed, you will not be alerted of the new messages in the undisplayed folders the next time you login. However, if you enter BULLETIN, you will be told that new messages are present in those other folders. Also, it is not possible to EXIT the READNEW mode if there are SYSTEM folders which have new messages. Typing the EXIT command will cause you to skip to those folders. (See HELP SET SYSTEM for a description of a SYSTEM folder).`, SET NOREADNEW`, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET [NO]READNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the [NO]READNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, Description: ` Specifies that the SET NOREADNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, }, "/FOLDER": { Description: `/FOLDER=foldername Loading @@ -1564,15 +1542,8 @@ In order to apply this to a specific folder, first select the folder Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET SHOWNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, the specified folder. This is a privileged qualifier.`, }, "/DEFAULT": { Description: ` Specifies that the SHOWNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`}, "/PERMANENT": { Description: `/[NO]PERMANENT Loading @@ -1590,16 +1561,7 @@ In order to apply this to a specific folder, first select the folder Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET NOSHOWNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the NOSHOWNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, for the specified folder. This is a privileged qualifier.`, }, "/FOLDER": { Description: `/FOLDER=foldername Loading repl/set.go +32 −2 Original line number Diff line number Diff line Loading @@ -89,8 +89,38 @@ func ActionSetNonotify(_ *dclish.Command) error { } // ActionSetPrivileges handles the `SET PRIVILEGES` command. func ActionSetPrivileges(_ *dclish.Command) error { fmt.Println("TODO: implement ActionSetPrivileges.") func ActionSetPrivileges(cmd *dclish.Command) error { // TODO: OK, need a better parser. switch cmd.Args[0] { case "CREATE": if len(cmd.Args) != 2 { fmt.Println("ERROR: Must pass single login.") return nil } fmt.Println("TODO: Create user creation routine - see repl/repl.go.") case "DELETE": if len(cmd.Args) != 2 { fmt.Println("ERROR: Must pass single login.") return nil } fmt.Println("TODO: Create user delete routine - see repl/repl.go.") case "SSH": fmt.Println("TODO: Create ssh routine.") case "ADMIN": fmt.Println("TODO: Create an admin bit set/unset routine.") case "NOADMIN": fmt.Println("TODO: Create an admin bit set/unset routine.") case "MOD": fmt.Println("TODO: Create a mod bit set/unset routine.") case "NOMOD": fmt.Println("TODO: Create a mod bit set/unset routine.") case "ENABLE": fmt.Println("TODO: Create a disable bit set/unset routine.") case "DISABLE": fmt.Println("TODO: Create a disable bit set/unset routine.") default: fmt.Println("ERROR: Command not understood.") } return nil } Loading Loading
dclish/dclish.go +25 −3 Original line number Diff line number Diff line Loading @@ -106,11 +106,35 @@ func split(line string) []string { return words } // PrefixMatch searches for a command in a list of possible commands. func PrefixMatch(command string, commands []string) (string, error) { cmd := strings.ToUpper(command) possibles := []string{} for i := range commands { if strings.HasPrefix(cmd, commands[i]) { possibles = append(possibles, commands[i]) } } switch len(possibles) { case 0: return "", fmt.Errorf("Unknown command '%s'", command) case 1: return possibles[0], nil default: return "", fmt.Errorf("Ambiguous command '%s' (matches %s)", command, strings.Join(possibles, ", ")) } } // ParseAndRun parses a command line and runs the command. func (c Commands) ParseAndRun(line string) error { // Split into words. words := split(line) return c.run(words) } func (c Commands) run(words []string) error { // Find the command. wordup := strings.ToUpper(words[0]) cmd, ok := c[wordup] Loading Loading @@ -141,9 +165,7 @@ func (c Commands) ParseAndRun(line string) error { fmt.Printf("ERROR: missing subcommand for %s.\n", wordup) return nil } // TODO: quoting is probably an issue here - break ParseAndRun into ParseAndRun + Run. newline := strings.Join(words[1:], " ") return cmd.Commands.ParseAndRun(newline) return cmd.Commands.run(words[1:]) } if cmd.Action == nil { Loading
folders/sql/1_create_table.up.sql +30 −23 Original line number Diff line number Diff line CREATE TABLE users ( login VARCHAR(12) NOT NULL PRIMARY KEY, name VARCHAR(53) NOT NULL, admin INT DEFAULT 0, disabled INT DEFAULT 0, admin INT DEFAULT 0 NOT NULL, moderator INT DEFAULT 0 NOT NULL, disabled INT DEFAULT 0 NOT NULL, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL Loading Loading @@ -34,16 +35,15 @@ END; CREATE TABLE folders ( name VARCHAR(25) NOT NULL PRIMARY KEY, always INT DEFAULT 0, brief INT DEFAULT 0, description VARCHAR(53) NOT NULL, notify INT DEFAULT 0, owner VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, readnew INT DEFAULT 0, shownew INT DEFAULT 0, system INT DEFAULT 0, expire INT DEFAULT 14, visibility TEXT DEFAULT 'public', always INT DEFAULT 0 NOT NULL, brief INT DEFAULT 0 NOT NULL, description VARCHAR(53) DEFAULT 0 NOT NULL, notify INT DEFAULT 0 NOT NULL, readnew INT DEFAULT 0 NOT NULL, shownew INT DEFAULT 0 NOT NULL, system INT DEFAULT 0 NOT NULL, expire INT DEFAULT 14 NOT NULL, visibility TEXT DEFAULT 'public' NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL ) WITHOUT ROWID; Loading Loading @@ -87,7 +87,7 @@ END; INSERT INTO folders (name, description, system, shownew, owner) VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1, 'SYSTEM'); CREATE TABLE co_owners ( CREATE TABLE owners ( folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, owner VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, Loading @@ -95,11 +95,11 @@ CREATE TABLE co_owners ( PRIMARY KEY (folder, owner) ) WITHOUT ROWID; CREATE TRIGGER co_owners_after_update_update_at AFTER UPDATE ON co_owners FOR EACH ROW CREATE TRIGGER owners_after_update_update_at AFTER UPDATE ON owners FOR EACH ROW WHEN NEW.update_at = OLD.update_at --- avoid infinite loop BEGIN UPDATE co_owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner; UPDATE owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner; END; CREATE TABLE messages ( Loading @@ -108,8 +108,8 @@ CREATE TABLE messages ( author VARCHAR(25) REFERENCES users(login) ON UPDATE CASCADE, subject VARCHAR(53) NOT NULL, message TEXT NOT NULL, permanent INT DEFAULT 0, shutdown INT DEFAULT 0, permanent INT DEFAULT 0 NOT NULL, shutdown INT DEFAULT 0 NOT NULL, expiration TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, Loading @@ -118,7 +118,7 @@ CREATE TABLE messages ( CREATE INDEX messages_idx_shutdown ON messages(shutdown); CREATE INDEX messages_idx_expiration ON messages(expiration); CREATE TABLE read ( CREATE TABLE seen ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, msgid INT, Loading @@ -142,13 +142,20 @@ CREATE TABLE mark ( ON UPDATE CASCADE ) WITHOUT ROWID; CREATE TABLE access ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (login, folder), ) WITHOUT ROWID; --- TODO: The following is incomplete: --- User configs. CREATE TABLE config ( login VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE, folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE, always INT NOT NULL, always INT NOT NULL DEFAULT 0, alert INT NOT NULL DEFAULT 0, --- 0=no, 1=brief, 2=readnew always INT NOT NULL ) WITHOUT ROWID; --- System configs. Loading
repl/command.go +22 −60 Original line number Diff line number Diff line Loading @@ -1439,16 +1439,22 @@ to see what is presently set. This is a privileged command. The parameters are one or more privileges separated by commas. To remove a privilege, specify the privilege preceeded by "NO". If /ID is specified, the parameters are rights identifiers.`, Flags: dclish.Flags{ "/ID": { Description: `/[NO]ID specified, the parameters are rights identifiers. If specified, then the rights identifier which is specified as the parameter will allow users holding that rights identifier to execute privileged commands. If /NOID is specified, the identifier is removed.`, }, }, For the reimplementation this is used to manage users. The following parameters are available. Format: SET PRIVILEGES CREATE login SET PRIVILEGES DELETE login SET PRIVILEGES SSH [login] SET PRIVILEGES [NO]ADMIN login SET PRIVILEGES [NO]MOD login [folder] SET PRIVILEGES ENABLE login SET PRIVILEGES DISABLE login`, MinArgs: 1, MaxArgs: 3, Action: ActionSetPrivileges, }, "PROMPT_EXPIRE": { Description: `Specifies that a user will be prompted for an expiration date when Loading Loading @@ -1492,17 +1498,8 @@ the EXIT command will cause you to skip to those folders. (See HELP SET SYSTEM for a description of a SYSTEM folder).`, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET [NO]READNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the [NO]READNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, Description: ` Specifies that the SET READNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, }, "/PERMANENT": { Description: `/[NO]PERMANENT Loading @@ -1515,30 +1512,11 @@ SYSTEM for a description of a SYSTEM folder).`, "NOREADNEW": { Description: `Turns off READNEW. Format: SET NOREADNEW NOTE: If you have several folders with READNEW enabled, each folder's messages will be displayed separately. However, if you EXIT the READNEW mode before all the folders have been displayed, you will not be alerted of the new messages in the undisplayed folders the next time you login. However, if you enter BULLETIN, you will be told that new messages are present in those other folders. Also, it is not possible to EXIT the READNEW mode if there are SYSTEM folders which have new messages. Typing the EXIT command will cause you to skip to those folders. (See HELP SET SYSTEM for a description of a SYSTEM folder).`, SET NOREADNEW`, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET [NO]READNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the [NO]READNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, Description: ` Specifies that the SET NOREADNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, }, "/FOLDER": { Description: `/FOLDER=foldername Loading @@ -1564,15 +1542,8 @@ In order to apply this to a specific folder, first select the folder Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET SHOWNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, the specified folder. This is a privileged qualifier.`, }, "/DEFAULT": { Description: ` Specifies that the SHOWNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`}, "/PERMANENT": { Description: `/[NO]PERMANENT Loading @@ -1590,16 +1561,7 @@ In order to apply this to a specific folder, first select the folder Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET NOSHOWNEW option is the default for all users for the specified folder. This is a privileged qualifier. The difference between this and /DEFAULT is that the latter will only apply to new users (i.e. any users which have never executed BULLETIN).`, }, "/DEFAULT": { Description: ` Specifies that the NOSHOWNEW option is the default for the specified folder. This is a privileged qualifier. It will only affect brand new users (or those that have never logged in). Use /ALL to modify all users.`, for the specified folder. This is a privileged qualifier.`, }, "/FOLDER": { Description: `/FOLDER=foldername Loading
repl/set.go +32 −2 Original line number Diff line number Diff line Loading @@ -89,8 +89,38 @@ func ActionSetNonotify(_ *dclish.Command) error { } // ActionSetPrivileges handles the `SET PRIVILEGES` command. func ActionSetPrivileges(_ *dclish.Command) error { fmt.Println("TODO: implement ActionSetPrivileges.") func ActionSetPrivileges(cmd *dclish.Command) error { // TODO: OK, need a better parser. switch cmd.Args[0] { case "CREATE": if len(cmd.Args) != 2 { fmt.Println("ERROR: Must pass single login.") return nil } fmt.Println("TODO: Create user creation routine - see repl/repl.go.") case "DELETE": if len(cmd.Args) != 2 { fmt.Println("ERROR: Must pass single login.") return nil } fmt.Println("TODO: Create user delete routine - see repl/repl.go.") case "SSH": fmt.Println("TODO: Create ssh routine.") case "ADMIN": fmt.Println("TODO: Create an admin bit set/unset routine.") case "NOADMIN": fmt.Println("TODO: Create an admin bit set/unset routine.") case "MOD": fmt.Println("TODO: Create a mod bit set/unset routine.") case "NOMOD": fmt.Println("TODO: Create a mod bit set/unset routine.") case "ENABLE": fmt.Println("TODO: Create a disable bit set/unset routine.") case "DISABLE": fmt.Println("TODO: Create a disable bit set/unset routine.") default: fmt.Println("ERROR: Command not understood.") } return nil } Loading