diff options
author | Runxi Yu <me@runxiyu.org> | 2025-04-01 21:42:44 +0800 |
---|---|---|
committer | Runxi Yu <me@runxiyu.org> | 2025-04-01 21:46:55 +0800 |
commit | cf2f03ae3725453f6d16205a112263eb528607fb (patch) | |
tree | 6eb1d4b23e8570856fef3601d94b6e07847e6c0c | |
parent | Remove unnecessary clause in the Makefile (diff) | |
download | forge-cf2f03ae3725453f6d16205a112263eb528607fb.tar.gz forge-cf2f03ae3725453f6d16205a112263eb528607fb.tar.zst forge-cf2f03ae3725453f6d16205a112263eb528607fb.zip |
LMTP: Patch handling stub
-rw-r--r-- | lmtp_handle_patch.go | 15 | ||||
-rw-r--r-- | lmtp_server.go | 52 | ||||
-rw-r--r-- | ssh_utils.go | 6 | ||||
-rw-r--r-- | url.go | 11 |
4 files changed, 75 insertions, 9 deletions
diff --git a/lmtp_handle_patch.go b/lmtp_handle_patch.go new file mode 100644 index 0000000..a3064d1 --- /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 <https://runxiyu.org> + +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 041194e..10ce836 100644 --- a/lmtp_server.go +++ b/lmtp_server.go @@ -7,6 +7,7 @@ package main import ( "bytes" "errors" + "fmt" "io" "log/slog" "net" @@ -48,13 +49,11 @@ func (session *lmtpSession) Rcpt(to string, _ *smtp.RcptOptions) error { } 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 @@ func (session *lmtpSession) Data(r io.Reader) error { 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 @@ func (session *lmtpSession) Data(r io.Reader) error { ) // 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 94aabe4..6a9a480 100644 --- a/ssh_utils.go +++ b/ssh_utils.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "net/url" - "strings" "go.lindenii.runxiyu.org/lindenii-common/ansiec" ) @@ -23,7 +22,10 @@ func getRepoInfo2(ctx context.Context, sshPath, sshPubkey string) (groupPath []s 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 @@ -51,6 +51,16 @@ func getParamRefTypeName(request *http.Request) (retRefType, retRefName string, 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 @@ func parseReqURI(requestURI string) (segments []string, params url.Values, err e } } - params, err = url.ParseQuery(paramsStr) return } |