From cf2f03ae3725453f6d16205a112263eb528607fb Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Tue, 01 Apr 2025 21:42:44 +0800 Subject: [PATCH] LMTP: Patch handling stub --- lmtp_handle_patch.go | 15 +++++++++++++++ lmtp_server.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ ssh_utils.go | 6 ++++-- url.go | 11 ++++++++++- diff --git a/lmtp_handle_patch.go b/lmtp_handle_patch.go new file mode 100644 index 0000000000000000000000000000000000000000..a3064d1a45bf6a482bdd268123f12ca6b6d7d2ac --- /dev/null +++ b/lmtp_handle_patch.go @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu + +package main + +import ( + "log/slog" + + "github.com/emersion/go-message" +) + +func lmtpHandlePatch(groupPath []string, repoName string, email *message.Entity) (err error) { + slog.Info("Pretend like I'm handling a patch!") + return nil +} diff --git a/lmtp_server.go b/lmtp_server.go index 041194ef48e39299c10a49c6aca7a52d2618b263..10ce8362ca98d6959842b34a435f2c206c8e265f 100644 --- a/lmtp_server.go +++ b/lmtp_server.go @@ -7,6 +7,7 @@ import ( "bytes" "errors" + "fmt" "io" "log/slog" "net" @@ -48,13 +49,11 @@ return nil } func (*lmtpHandler) NewSession(_ *smtp.Conn) (smtp.Session, error) { - // TODO session := &lmtpSession{} return session, nil } func serveLMTP(listener net.Listener) error { - // TODO: Manually construct smtp.Server smtpServer := smtp.NewServer(&lmtpHandler{}) smtpServer.LMTP = true smtpServer.Domain = config.LMTP.Domain @@ -99,7 +98,7 @@ } switch strings.ToLower(email.Header.Get("Auto-Submitted")) { case "auto-generated", "auto-replied": - // disregard automatic emails like OOO replies + // Disregard automatic emails like OOO replies. slog.Info("ignoring automatic message", "from", session.from, "to", strings.Join(session.to, ","), @@ -117,12 +116,53 @@ "subject", email.Header.Get("Subject"), ) // Make local copies of the values before to ensure the references will - // still be valid when the queued task function is evaluated. + // still be valid when the task is run. from = session.from to = session.to - // TODO: Process the actual message contents - _, _ = from, to + _ = from + + for _, to := range to { + if !strings.HasSuffix(to, "@"+config.LMTP.Domain) { + continue + } + localPart := to[:len(to)-len("@"+config.LMTP.Domain)] + segments, err := pathToSegments(localPart) + if err != nil { + // TODO: Should the entire email fail or should we just + // notify them out of band? + err = fmt.Errorf("cannot parse path: %w", err) + goto end + } + sepIndex := -1 + for i, part := range segments { + if part == ":" { + sepIndex = i + break + } + } + if segments[len(segments)-1] == "" { + segments = segments[:len(segments)-1] // We don't care about dir or not. + } + if sepIndex == -1 || len(segments) <= sepIndex+2 { + err = errors.New("illegal path") + goto end + } + + groupPath := segments[:sepIndex] + moduleType := segments[sepIndex+1] + moduleName := segments[sepIndex+2] + switch moduleType { + case "repos": + err = lmtpHandlePatch(groupPath, moduleName, email) + if err != nil { + goto end + } + default: + err = fmt.Errorf("Emailing any endpoint other than repositories, is not supported yet.") // TODO + goto end + } + } end: session.to = nil diff --git a/ssh_utils.go b/ssh_utils.go index 94aabe4cf954f495f1fd52f1991597b8bf581c48..6a9a480da51bb9434c9582e95ae99f437bb0168d 100644 --- a/ssh_utils.go +++ b/ssh_utils.go @@ -9,7 +9,6 @@ "errors" "fmt" "io" "net/url" - "strings" "go.lindenii.runxiyu.org/lindenii-common/ansiec" ) @@ -23,7 +22,10 @@ var segments []string var sepIndex int var moduleType, moduleName string - segments = strings.Split(strings.TrimPrefix(sshPath, "/"), "/") + segments, err = pathToSegments(sshPath) + if err != nil { + return + } for i, segment := range segments { var err error diff --git a/url.go b/url.go index b9c575325ab48e3dfdf0282013a5f7b6da7f4024..ad5c8bb51c69b4962d216a93792c3bc2dac0199f 100644 --- a/url.go +++ b/url.go @@ -51,6 +51,16 @@ // and the query parameters. It handles %2F correctly. func parseReqURI(requestURI string) (segments []string, params url.Values, err error) { path, paramsStr, _ := strings.Cut(requestURI, "?") + segments, err = pathToSegments(path) + if err != nil { + return + } + + params, err = url.ParseQuery(paramsStr) + return +} + +func pathToSegments(path string) (segments []string, err error) { segments = strings.Split(strings.TrimPrefix(path, "/"), "/") for i, segment := range segments { @@ -60,7 +70,6 @@ return } } - params, err = url.ParseQuery(paramsStr) return } -- 2.48.1