diff --git a/cmd/inbucket/main.go b/cmd/inbucket/main.go index 242943a..b11f259 100644 --- a/cmd/inbucket/main.go +++ b/cmd/inbucket/main.go @@ -71,6 +71,7 @@ func main() { config.Usage() return } + // Process configuration. config.Version = version config.BuildDate = date @@ -83,6 +84,7 @@ func main() { conf.POP3.Debug = true conf.SMTP.Debug = true } + // Logger setup. closeLog, err := openLog(conf.LogLevel, *logfile, *logjson) if err != nil { @@ -90,12 +92,15 @@ func main() { os.Exit(1) } startupLog := log.With().Str("phase", "startup").Logger() + // Setup signal handler. sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) + // Initialize logging. startupLog.Info().Str("version", config.Version).Str("buildDate", config.BuildDate). Msg("Inbucket starting") + // Write pidfile if requested. if *pidfile != "" { pidf, err := os.Create(*pidfile) @@ -107,6 +112,7 @@ func main() { startupLog.Fatal().Err(err).Str("path", *pidfile).Msg("Failed to close pidfile") } } + // Configure internal services. rootCtx, rootCancel := context.WithCancel(context.Background()) shutdownChan := make(chan bool) @@ -118,20 +124,25 @@ func main() { msgHub := msghub.New(rootCtx, conf.Web.MonitorHistory) addrPolicy := &policy.Addressing{Config: conf} mmanager := &message.StoreManager{AddrPolicy: addrPolicy, Store: store, Hub: msgHub} + // Start Retention scanner. retentionScanner := storage.NewRetentionScanner(conf.Storage, store, shutdownChan) retentionScanner.Start() + // Start HTTP server. webui.SetupRoutes(web.Router.PathPrefix("/serve/").Subrouter()) rest.SetupRoutes(web.Router.PathPrefix("/api/").Subrouter()) web.Initialize(conf, shutdownChan, mmanager, msgHub) go web.Start(rootCtx) + // Start POP3 server. pop3Server := pop3.New(conf.POP3, shutdownChan, store) go pop3Server.Start(rootCtx) + // Start SMTP server. smtpServer := smtp.NewServer(conf.SMTP, shutdownChan, mmanager, addrPolicy) go smtpServer.Start(rootCtx) + // Loop forever waiting for signals or shutdown channel. signalLoop: for { @@ -154,6 +165,7 @@ signalLoop: break signalLoop } } + // Wait for active connections to finish. go timedExit(*pidfile) smtpServer.Drain() diff --git a/pkg/server/pop3/handler.go b/pkg/server/pop3/handler.go index 04242d1..d07dd96 100644 --- a/pkg/server/pop3/handler.go +++ b/pkg/server/pop3/handler.go @@ -169,6 +169,7 @@ func (s *Server) startSession(id int, conn net.Conn) { } break } + // not an EOF ssn.logger.Warn().Msgf("Connection error: %v", err) if netErr, ok := err.(net.Error); ok { diff --git a/pkg/server/smtp/handler.go b/pkg/server/smtp/handler.go index f3a8e0c..41db786 100644 --- a/pkg/server/smtp/handler.go +++ b/pkg/server/smtp/handler.go @@ -322,6 +322,7 @@ func (s *Session) readyHandler(cmd string, arg string) { if from == "" { from = "unspecified" } + // This is where the client may put BODY=8BITMIME, but we already // read the DATA as bytes, so it does not effect our processing. if m[2] != "" { @@ -436,6 +437,7 @@ func (s *Session) dataHandler() { prefix := fmt.Sprintf("Received: from %s ([%s]) by %s\r\n for <%s>; %s\r\n", s.remoteDomain, s.remoteHost, s.config.Domain, recip.Address.Address, tstamp) + // Deliver message. _, err := s.manager.Deliver( recip, s.from, s.recipients, prefix, mailData.Bytes()) @@ -530,12 +532,14 @@ func (s *Session) parseCmd(line string) (cmd string, arg string, ok bool) { s.logger.Warn().Msgf("Mangled command: %q", line) return "", "", false } + // If we made it here, command is long enough to have args if line[4] != ' ' { // There wasn't a space after the command? s.logger.Warn().Msgf("Mangled command: %q", line) return "", "", false } + // I'm not sure if we should trim the args or not, but we will for now return strings.ToUpper(line[0:4]), strings.Trim(line[5:], " "), true }