package config import ( "fmt" "os" "github.com/BurntSushi/toml" ) // Config is the top-level configuration for URIT BBS. type Config struct { System SystemConfig `toml:"system"` Telnet TelnetConfig `toml:"telnet"` SSH SSHConfig `toml:"ssh"` HTTP HTTPConfig `toml:"http"` Storage StorageConfig `toml:"storage"` Users UsersConfig `toml:"users"` Logging LoggingConfig `toml:"logging"` } // SystemConfig holds general BBS identity and paths. type SystemConfig struct { Name string `toml:"name"` Sysop string `toml:"sysop"` Location string `toml:"location"` Screens string `toml:"screens"` } // TelnetConfig controls the telnet listener. type TelnetConfig struct { Enabled bool `toml:"enabled"` Address string `toml:"address"` } // SSHConfig controls the SSH listener. type SSHConfig struct { Enabled bool `toml:"enabled"` Address string `toml:"address"` HostKey string `toml:"host_key"` } // HTTPConfig controls the HTTP file server. // This serves file libraries for download via browser — the modern // replacement for ZMODEM and other transfer protocols. type HTTPConfig struct { Enabled bool `toml:"enabled"` Address string `toml:"address"` } // StorageConfig selects and configures the storage backend. type StorageConfig struct { Driver string `toml:"driver"` SQLitePath string `toml:"sqlite_path"` } // SecurityLevel defines access levels for a user tier. type SecurityLevel struct { Status int `toml:"status"` Board int `toml:"board"` Library int `toml:"library"` Bulletin int `toml:"bulletin"` } // UsersConfig holds user account defaults. type UsersConfig struct { MaxAccounts int `toml:"max_accounts"` GuestTimeLimit int `toml:"guest_time_limit"` NewTimeLimit int `toml:"new_time_limit"` ValidTimeLimit int `toml:"valid_time_limit"` GuestSecurity SecurityLevel `toml:"guest_security"` NewSecurity SecurityLevel `toml:"new_security"` ValidSecurity SecurityLevel `toml:"valid_security"` } // LoggingConfig controls log output. type LoggingConfig struct { Level string `toml:"level"` File string `toml:"file"` } // Load reads a TOML config file from the given path and returns a Config. // If the file does not exist, it returns a Config populated with defaults. func Load(path string) (*Config, error) { cfg := defaults() data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return cfg, nil } return nil, fmt.Errorf("reading config %s: %w", path, err) } if err := toml.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parsing config %s: %w", path, err) } return cfg, nil } // defaults returns a Config with sensible default values. // These match the values in the shipped config.toml. func defaults() *Config { return &Config{ System: SystemConfig{ Name: "URIT BBS", Sysop: "Sysop", Location: "./data/", Screens: "./screens/", }, Telnet: TelnetConfig{ Enabled: true, Address: ":2323", }, SSH: SSHConfig{ Enabled: false, Address: ":2222", HostKey: "./data/ssh_host_key", }, HTTP: HTTPConfig{ Enabled: true, Address: ":8080", }, Storage: StorageConfig{ Driver: "sqlite", SQLitePath: "./data/urit.db", }, Users: UsersConfig{ MaxAccounts: 500, GuestTimeLimit: 1800, NewTimeLimit: 3600, ValidTimeLimit: 7200, GuestSecurity: SecurityLevel{ Status: 0, Board: 0, Library: 0, Bulletin: 0, }, NewSecurity: SecurityLevel{ Status: 1, Board: 1, Library: 1, Bulletin: 1, }, ValidSecurity: SecurityLevel{ Status: 2, Board: 2, Library: 2, Bulletin: 2, }, }, Logging: LoggingConfig{ Level: "info", File: "", }, } }