aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-01-02 19:30:51 +0000
committerRunxi Yu <me@runxiyu.org>2025-01-02 19:30:51 +0000
commit00f3cb9fb48cfb9768b695bd0d9eb8367ad84782 (patch)
tree2e35b4252b2538c7dbe13d90b501216ded240149
parentFile splitting (diff)
downloadmaild-00f3cb9fb48cfb9768b695bd0d9eb8367ad84782.tar.gz
maild-00f3cb9fb48cfb9768b695bd0d9eb8367ad84782.tar.zst
maild-00f3cb9fb48cfb9768b695bd0d9eb8367ad84782.zip
Deliver to inbox
-rw-r--r--config.go29
-rw-r--r--errors.go9
-rw-r--r--incoming.go20
-rw-r--r--maild.scfg1
-rw-r--r--main.go15
-rw-r--r--mta_recv.go10
6 files changed, 69 insertions, 15 deletions
diff --git a/config.go b/config.go
index 1a89987..c4b5579 100644
--- a/config.go
+++ b/config.go
@@ -1,7 +1,34 @@
package main
+import (
+ "bufio"
+ "go.lindenii.runxiyu.org/lindenii-common/scfg"
+ "os"
+ "sync"
+)
+
var config struct {
Server_name string `scfg:"server_name"`
+ Inbox_path string `scfg:"inbox_path"`
}
+var config_mutex sync.RWMutex
-// TODO: edit scfg to require fields to exist unless explicitly marked optional.
+func load_config(path string) error {
+ config_file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ decoder := scfg.NewDecoder(bufio.NewReader(config_file))
+ if func() error {
+ config_mutex.Lock()
+ defer config_mutex.Unlock()
+ err = decoder.Decode(&config)
+ if err != nil {
+ return err
+ }
+ return nil
+ }() != nil {
+ return err
+ }
+ return nil
+}
diff --git a/errors.go b/errors.go
new file mode 100644
index 0000000..0d6a8d7
--- /dev/null
+++ b/errors.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "errors"
+)
+
+var (
+ err_deliver_write = errors.New("unable to write to filesystem while attempting to deliver message")
+)
diff --git a/incoming.go b/incoming.go
index f915ac0..169bde5 100644
--- a/incoming.go
+++ b/incoming.go
@@ -1,12 +1,28 @@
package main
-import "go.lindenii.runxiyu.org/lindenii-common/clog"
+import (
+ "go.lindenii.runxiyu.org/lindenii-common/clog"
+ "os"
+ "path"
+ "time"
+)
-func deliver_incoming(envelope_from string, envelope_recipients []string, data []byte) {
+func deliver_incoming(envelope_from string, envelope_recipients []string, data []byte) error {
clog.Debug(
"incoming_mail",
"envelope_from", envelope_from,
"envelope_recipients", envelope_recipients,
"data", string(data),
)
+ t := time.Now()
+ fd, err := os.OpenFile(path.Join(config.Inbox_path, envelope_from+" "+t.Format(time.RFC3339Nano)+".eml"), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0660) // TODO: vulnerability
+ if err != nil {
+ // TODO: handle fs.ErrExist
+ return err_deliver_write
+ }
+ _, err = fd.Write(data)
+ if err != nil {
+ return err_deliver_write
+ }
+ return nil
}
diff --git a/maild.scfg b/maild.scfg
index 24f7b84..84c613e 100644
--- a/maild.scfg
+++ b/maild.scfg
@@ -1 +1,2 @@
server_name mail.andrewyu.org
+inbox_path /home/runxiyu/inbox
diff --git a/main.go b/main.go
index 8d6b797..052deec 100644
--- a/main.go
+++ b/main.go
@@ -3,21 +3,18 @@ package main
import (
"bufio"
"net"
- "os"
+ "flag"
+ "errors"
+ "io"
"go.lindenii.runxiyu.org/lindenii-common/clog"
- "go.lindenii.runxiyu.org/lindenii-common/scfg"
)
const VERSION = "lindenii-maild v0.0.0"
func main() {
- config_file, err := os.Open("maild.scfg")
- if err != nil {
- panic(err)
- }
-
- err = scfg.NewDecoder(bufio.NewReader(config_file)).Decode(&config)
+ config_path := flag.String("config", "maild.scfg", "path to configuration file")
+ err := load_config(*config_path)
if err != nil {
panic(err)
}
@@ -36,7 +33,7 @@ func main() {
go func() {
err := handle_incoming_server_connection(bufio.NewReader(conn), bufio.NewWriter(conn))
- if err != nil {
+ if err != nil && !errors.Is(err, io.EOF) {
clog.Error("connection handler returned error", "err", err)
}
}()
diff --git a/mta_recv.go b/mta_recv.go
index 2b4679a..c77c46d 100644
--- a/mta_recv.go
+++ b/mta_recv.go
@@ -129,10 +129,14 @@ func handle_incoming_server_connection(reader *bufio.Reader, writer *bufio.Write
if err != nil {
return err
}
- deliver_incoming(current_mail_from, current_rcpt_to, current_data)
- server_state = server_state_helo
- _, _ = writer.WriteString("250 2.0.0 Ok: Accepted\r\n")
+ err = deliver_incoming(current_mail_from, current_rcpt_to, current_data)
+ if err == nil {
+ _, _ = writer.WriteString("250 2.0.0 Ok: Accepted\r\n")
+ } else {
+ _, _ = writer.WriteString("500 2.0.0 Funderscore\r\n")
+ }
_ = writer.Flush()
+ server_state = server_state_helo
case "QUIT":
_, _ = writer.WriteString("221 2.0.0 Bye\r\n")
_ = writer.Flush()