aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lmtp_handle_patch.go15
-rw-r--r--lmtp_server.go52
-rw-r--r--ssh_utils.go6
-rw-r--r--url.go11
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
diff --git a/url.go b/url.go
index b9c5753..ad5c8bb 100644
--- a/url.go
+++ b/url.go
@@ -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
}