diff --git a/cmd/main.go b/cmd/main.go index 37814ac..07c3cd6 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" "sync" + "xdcc-cli/config" "xdcc-cli/pb" "xdcc-cli/search" table "xdcc-cli/table" @@ -158,7 +159,7 @@ func loadUrlListFile(filePath string) []string { } func printGetUsageAndExit(flagSet *flag.FlagSet) { - fmt.Printf("usage: get url1 url2 ... [-o path] [-i file] [--ssl-only]\n\nFlag set:\n") + fmt.Printf("usage: get url1 url2 ... [-o path] [-i file] [--ssl-only] [-c config]\n\nFlag set:\n") flagSet.PrintDefaults() os.Exit(0) } @@ -167,11 +168,18 @@ func execGet(args []string) { getCmd := flag.NewFlagSet("get", flag.ExitOnError) path := getCmd.String("o", ".", "output folder of dowloaded file") inputFile := getCmd.String("i", "", "input file containing a list of urls") + configFile := getCmd.String("c", "", "config file for network-channel mappings (defaults to ~/.xdcc-cli-config.json)") sslOnly := getCmd.Bool("ssl-only", false, "force the client to use TSL connection") urlList := parseFlags(getCmd, args) + // Bestimme den Konfigurationspfad + configPath := *configFile + if configPath == "" { + configPath = config.DefaultConfigPath() + } + if *inputFile != "" { urlList = append(urlList, loadUrlListFile(*inputFile)...) } @@ -194,9 +202,10 @@ func execGet(args []string) { } transfer := xdcc.NewTransfer(xdcc.Config{ - File: *url, - OutPath: *path, - SSLOnly: *sslOnly, + File: *url, + OutPath: *path, + SSLOnly: *sslOnly, + ConfigPath: configPath, }) wg.Add(1) diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..652f6bf --- /dev/null +++ b/config/config.go @@ -0,0 +1,138 @@ +package config + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +// NetworkChannelsConfig definiert die Konfiguration für automatische Channel-Joins +type NetworkChannelsConfig struct { + Networks map[string][]string `json:"networks"` +} + +// DefaultConfigPath gibt den Standardpfad für die Konfigurationsdatei zurück +func DefaultConfigPath() string { + homeDir, err := os.UserHomeDir() + if err != nil { + return ".xdcc-cli-config.json" + } + return filepath.Join(homeDir, ".xdcc-cli-config.json") +} + +// LoadConfig lädt die Konfiguration aus einer JSON-Datei +func LoadConfig(configPath string) (*NetworkChannelsConfig, error) { + // Wenn die Datei nicht existiert, gibt eine leere Konfiguration zurück + if _, err := os.Stat(configPath); os.IsNotExist(err) { + return &NetworkChannelsConfig{ + Networks: make(map[string][]string), + }, nil + } + + file, err := os.Open(configPath) + if err != nil { + return nil, fmt.Errorf("fehler beim Öffnen der Konfigurationsdatei: %v", err) + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + return nil, fmt.Errorf("fehler beim Lesen der Konfigurationsdatei: %v", err) + } + + var config NetworkChannelsConfig + if err := json.Unmarshal(data, &config); err != nil { + return nil, fmt.Errorf("fehler beim Parsen der Konfigurationsdatei: %v", err) + } + + // Initialisiere Networks falls nil + if config.Networks == nil { + config.Networks = make(map[string][]string) + } + + return &config, nil +} + +// SaveConfig speichert die Konfiguration in eine JSON-Datei +func SaveConfig(configPath string, config *NetworkChannelsConfig) error { + data, err := json.MarshalIndent(config, "", " ") + if err != nil { + return fmt.Errorf("fehler beim Serialisieren der Konfiguration: %v", err) + } + + if err := os.WriteFile(configPath, data, 0644); err != nil { + return fmt.Errorf("fehler beim Schreiben der Konfigurationsdatei: %v", err) + } + + return nil +} + +// GetChannelsForNetwork gibt die konfigurierten Channels für ein Netzwerk zurück +func (c *NetworkChannelsConfig) GetChannelsForNetwork(network string) []string { + channels, exists := c.Networks[network] + if !exists { + return []string{} + } + + // Stelle sicher, dass alle Channels mit # beginnen + normalizedChannels := make([]string, len(channels)) + for i, channel := range channels { + if channel != "" && !strings.HasPrefix(channel, "#") { + normalizedChannels[i] = "#" + channel + } else { + normalizedChannels[i] = channel + } + } + + return normalizedChannels +} + +// AddChannelToNetwork fügt einen Channel zu einem Netzwerk hinzu +func (c *NetworkChannelsConfig) AddChannelToNetwork(network, channel string) { + if c.Networks == nil { + c.Networks = make(map[string][]string) + } + + // Normalisiere den Channel-Namen + if channel != "" && !strings.HasPrefix(channel, "#") { + channel = "#" + channel + } + + // Prüfe ob der Channel bereits existiert + for _, existingChannel := range c.Networks[network] { + if existingChannel == channel { + return // Channel bereits vorhanden + } + } + + c.Networks[network] = append(c.Networks[network], channel) +} + +// RemoveChannelFromNetwork entfernt einen Channel von einem Netzwerk +func (c *NetworkChannelsConfig) RemoveChannelFromNetwork(network, channel string) { + if c.Networks == nil { + return + } + + // Normalisiere den Channel-Namen + if channel != "" && !strings.HasPrefix(channel, "#") { + channel = "#" + channel + } + + channels := c.Networks[network] + for i, existingChannel := range channels { + if existingChannel == channel { + // Entferne den Channel aus dem Slice + c.Networks[network] = append(channels[:i], channels[i+1:]...) + break + } + } + + // Entferne das Netzwerk wenn keine Channels mehr vorhanden sind + if len(c.Networks[network]) == 0 { + delete(c.Networks, network) + } +} \ No newline at end of file diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..f99b3e4 --- /dev/null +++ b/config/config.json @@ -0,0 +1,16 @@ +{ + "networks": { + "irc.rizon.net": [ + "#elitewarez" + ], + "irc.highway.net": [ + "#beast-xdcc", + "#moviegods" + ], + "irc.abjects.net": [ + "#beast-xdcc", + "#moviegods", + "#mg-chat" + ] + } +} \ No newline at end of file diff --git a/xdcc/xdcc.go b/xdcc/xdcc.go index 07a57c1..1863ed8 100644 --- a/xdcc/xdcc.go +++ b/xdcc/xdcc.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "time" + "xdcc-cli/config" irc "github.com/fluffle/goirc/client" ) @@ -168,9 +169,10 @@ type XdccTransfer struct { } type Config struct { - File IRCFile - OutPath string - SSLOnly bool + File IRCFile + OutPath string + SSLOnly bool + ConfigPath string } func NewTransfer(c Config) Transfer { @@ -207,7 +209,7 @@ func newXdccTransfer(c Config, enableSSL bool, skipCertificateCheck bool) *XdccT connAttempts: 0, events: make(chan TransferEvent, defaultEventChanSize), } - t.setupHandlers(file.Channel, file.UserName, file.Slot) + t.setupHandlers(file.Channel, file.UserName, file.Slot, c.ConfigPath) return t } @@ -215,14 +217,30 @@ func (transfer *XdccTransfer) send(req CTCPRequest) { transfer.conn.Privmsg(transfer.url.UserName, req.String()) } -func (transfer *XdccTransfer) setupHandlers(channel string, userName string, slot int) { +func (transfer *XdccTransfer) setupHandlers(channel string, userName string, slot int, configPath string) { conn := transfer.conn // e.g. join channel on connect. conn.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { transfer.connAttempts = 0 + + // Betrete den Haupt-Channel (für den Download) conn.Join(channel) + + // Lade die Konfiguration und betrete zusätzliche Channels + if configPath != "" { + if cfg, err := config.LoadConfig(configPath); err == nil { + additionalChannels := cfg.GetChannelsForNetwork(transfer.url.Network) + for _, additionalChannel := range additionalChannels { + // Verhindere doppeltes Betreten des gleichen Channels + if !strings.EqualFold(additionalChannel, channel) { + conn.Join(additionalChannel) + } + } + } + // Ignoriere Konfigurationsfehler stillschweigend - die Anwendung soll weiter funktionieren + } }) conn.HandleFunc(irc.ERROR, func(conn *irc.Conn, line *irc.Line) {