// Copyright 2019 The Mellium Contributors. // Use of this source code is governed by the BSD 2-clause // license that can be found in the LICENSE file. // The echobot command listens on the given JID and replies to messages with the // same contents. // // For more information try running: // // echobot -help package main import ( "context" "flag" "fmt" "io" "io/ioutil" "log" "os" "os/signal" ) /* #nosec */ const ( envAddr = "XMPP_ADDR" envPass = "XMPP_PASS" ) type logWriter struct { logger *log.Logger } func (lw logWriter) Write(p []byte) (int, error) { lw.logger.Printf("%s", p) return len(p), nil } func main() { // Setup logging and verbose logging that's disabled by default. logger := log.New(os.Stderr, "", log.LstdFlags) debug := log.New(ioutil.Discard, "DEBUG ", log.LstdFlags) // Configure behavior based on flags and environment variables. var ( addr = os.Getenv(envAddr) verbose bool logXML bool ) flags := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) flags.Usage = func() { fmt.Fprintf(flags.Output(), "Usage of %s:\n", flags.Name()) fmt.Fprintf(flags.Output(), "\n $%s: The JID which will be used to listen for messages to echo\n $%s: The password\n\n", envAddr, envPass) flags.PrintDefaults() } flags.BoolVar(&verbose, "v", verbose, "turns on verbose debug logging") flags.BoolVar(&logXML, "vv", logXML, "turns on verbose debug and XML logging") switch err := flags.Parse(os.Args[1:]); err { case flag.ErrHelp: return case nil: default: logger.Fatal(err) } // Return a sane error if the address is empty instead of erroring out when we // try to parse it. if addr == "" { logger.Fatalf("Address not specified, use the -addr flag or set $%s", envAddr) } // Enable verbose logging if the flag was set. if verbose || logXML { debug.SetOutput(os.Stderr) } // Enable XML logging if the flag was set. var xmlIn, xmlOut io.Writer if logXML { xmlIn = logWriter{log.New(os.Stdout, "IN ", log.LstdFlags)} xmlOut = logWriter{log.New(os.Stdout, "OUT ", log.LstdFlags)} } pass := os.Getenv(envPass) if pass == "" { debug.Printf("The environment variable $%s is empty", envPass) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Handle SIGINT and gracefully shut down the bot. c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go func() { select { case <-ctx.Done(): case <-c: cancel() } }() if err := echo(ctx, addr, pass, xmlIn, xmlOut, logger, debug); err != nil { logger.Fatal(err) } }