add readme, remove attachment handling
This commit is contained in:
parent
6a0d581b89
commit
6dba279c9a
|
@ -0,0 +1,13 @@
|
|||
# JupeMail
|
||||
> -- "noSmtp"--
|
||||
|
||||
Meant to catch both incoming and outgoing email and route it to specific destinations that will be defined by the destination address
|
||||
|
||||
Destinations like:
|
||||
|
||||
* irc
|
||||
* matrix
|
||||
* mattermost
|
||||
* RFC1149
|
||||
|
||||
pretty much any destination that isn't POP3 or IMAP delivery.
|
|
@ -1,13 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/jhillyerd/enmime"
|
||||
)
|
||||
|
||||
type Attachment struct {
|
||||
*enmime.Part
|
||||
}
|
||||
|
||||
func (a *Attachment) MarshalMultipart() (string, []byte) {
|
||||
return a.FileName, a.Content
|
||||
}
|
43
broker.go
43
broker.go
|
@ -6,10 +6,10 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var LocalPipe chan *Message
|
||||
var LocalPipe chan []byte
|
||||
|
||||
func init() {
|
||||
LocalPipe = make(chan *Message, 20)
|
||||
LocalPipe = make(chan []byte, 20)
|
||||
}
|
||||
|
||||
type Ticket struct {
|
||||
|
@ -24,14 +24,14 @@ type Status struct {
|
|||
|
||||
type Broker interface {
|
||||
GetName() string
|
||||
Deliver(*Message) Ticket
|
||||
Deliver([]byte) Ticket
|
||||
Available() bool
|
||||
// GetStatus(Ticket) Status
|
||||
}
|
||||
|
||||
type IRCBroker struct {
|
||||
Name string
|
||||
Backlog chan *Message
|
||||
Backlog chan []byte
|
||||
Overload chan bool
|
||||
IsAvailable bool
|
||||
Results map[Ticket]Status
|
||||
|
@ -40,27 +40,18 @@ type IRCBroker struct {
|
|||
}
|
||||
|
||||
func (bus *IRCBroker) PostalService() {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case msg := <-bus.Backlog:
|
||||
println("msg in")
|
||||
LocalPipe <- msg
|
||||
case <-bus.Overload:
|
||||
println("overload")
|
||||
return
|
||||
default:
|
||||
println("default")
|
||||
bus.mu.Lock()
|
||||
bus.IsAvailable = false
|
||||
bus.mu.Unlock()
|
||||
bus.Overload <- true
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case msg := <-bus.Backlog:
|
||||
println("msg in")
|
||||
LocalPipe <- msg
|
||||
default:
|
||||
time.Sleep(time.Duration(25) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (bus *IRCBroker) Deliver(incoming *Message) Ticket {
|
||||
func (bus *IRCBroker) Deliver(incoming []byte) Ticket {
|
||||
bus.Backlog <- incoming
|
||||
return Ticket{Timestamp: time.Now()}
|
||||
}
|
||||
|
@ -74,12 +65,16 @@ func (bus *IRCBroker) GetName() string {
|
|||
}
|
||||
|
||||
func NewIRCBroker(room string) *IRCBroker {
|
||||
return &IRCBroker{
|
||||
bro := &IRCBroker{
|
||||
Name: "IRCBroker",
|
||||
Backlog: make(chan *Message, 10),
|
||||
Backlog: make(chan []byte, 20),
|
||||
Overload: make(chan bool),
|
||||
IsAvailable: false,
|
||||
ToChannel: room,
|
||||
mu: sync.RWMutex{},
|
||||
}
|
||||
go bro.PostalService()
|
||||
go bro.StartBot(bro.Name)
|
||||
return bro
|
||||
}
|
||||
|
||||
|
|
90
codec.go
90
codec.go
|
@ -1,9 +1,10 @@
|
|||
// Code generated by Gojay. DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
// Code generated by Gojay.
|
||||
|
||||
import (
|
||||
"github.com/francoispqt/gojay"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AddresssPtr []*Address
|
||||
|
@ -27,27 +28,6 @@ func (s AddresssPtr) IsNil() bool {
|
|||
return len(s) == 0
|
||||
}
|
||||
|
||||
type AttachmentsPtr []*Attachment
|
||||
|
||||
func (s *AttachmentsPtr) UnmarshalJSONArray(dec *gojay.Decoder) error {
|
||||
var value = &Attachment{}
|
||||
if err := dec.Object(value); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = append(*s, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s AttachmentsPtr) MarshalJSONArray(enc *gojay.Encoder) {
|
||||
for i := range s {
|
||||
enc.Object(s[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (s AttachmentsPtr) IsNil() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
type Strings []string
|
||||
|
||||
// UnmarshalJSONArray decodes JSON array elements into slice
|
||||
|
@ -100,28 +80,6 @@ func (a *Address) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
|
|||
// NKeys returns the number of keys to unmarshal
|
||||
func (a *Address) NKeys() int { return 2 }
|
||||
|
||||
// MarshalJSONObject implements MarshalerJSONObject
|
||||
func (a *Attachment) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
|
||||
}
|
||||
|
||||
// IsNil checks if instance is nil
|
||||
func (a *Attachment) IsNil() bool {
|
||||
return a == nil
|
||||
}
|
||||
|
||||
// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
|
||||
func (a *Attachment) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
|
||||
|
||||
switch k {
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NKeys returns the number of keys to unmarshal
|
||||
func (a *Attachment) NKeys() int { return 0 }
|
||||
|
||||
// MarshalJSONObject implements MarshalerJSONObject
|
||||
func (m *Mail) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("Sender", m.Sender)
|
||||
|
@ -173,15 +131,13 @@ func (m *Message) MarshalJSONObject(enc *gojay.Encoder) {
|
|||
var replyToSlice = AddresssPtr(m.ReplyTo)
|
||||
enc.ArrayKey("ReplyTo", replyToSlice)
|
||||
enc.StringKey("Subject", m.Subject)
|
||||
enc.ObjectKey("Date", m.Date)
|
||||
enc.TimeKey("Date", &m.Date, time.RFC3339)
|
||||
enc.StringKey("MessageID", m.MessageID)
|
||||
enc.StringKey("InReplyTo", m.InReplyTo)
|
||||
var referencesSlice = Strings(m.References)
|
||||
enc.ArrayKey("References", referencesSlice)
|
||||
enc.StringKey("Text", m.Text)
|
||||
enc.StringKey("HTML", m.HTML)
|
||||
var attachmentsSlice = AttachmentsPtr(m.Attachments)
|
||||
enc.ArrayKey("Attachments", attachmentsSlice)
|
||||
}
|
||||
|
||||
// IsNil checks if instance is nil
|
||||
|
@ -237,12 +193,12 @@ func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
|
|||
return dec.String(&m.Subject)
|
||||
|
||||
case "Date":
|
||||
var value = &Time{}
|
||||
err := dec.Object(value)
|
||||
var format = time.RFC3339
|
||||
var value = time.Time{}
|
||||
err := dec.Time(&value, format)
|
||||
if err == nil {
|
||||
m.Date = value
|
||||
}
|
||||
|
||||
return err
|
||||
|
||||
case "MessageID":
|
||||
|
@ -265,39 +221,9 @@ func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
|
|||
case "HTML":
|
||||
return dec.String(&m.HTML)
|
||||
|
||||
case "Attachments":
|
||||
var aSlice = AttachmentsPtr{}
|
||||
err := dec.Array(&aSlice)
|
||||
if err == nil && len(aSlice) > 0 {
|
||||
m.Attachments = []*Attachment(aSlice)
|
||||
}
|
||||
return err
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NKeys returns the number of keys to unmarshal
|
||||
func (m *Message) NKeys() int { return 13 }
|
||||
|
||||
// MarshalJSONObject implements MarshalerJSONObject
|
||||
func (t *Time) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
|
||||
}
|
||||
|
||||
// IsNil checks if instance is nil
|
||||
func (t *Time) IsNil() bool {
|
||||
return t == nil
|
||||
}
|
||||
|
||||
// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
|
||||
func (t *Time) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
|
||||
|
||||
switch k {
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NKeys returns the number of keys to unmarshal
|
||||
func (t *Time) NKeys() int { return 0 }
|
||||
func (m *Message) NKeys() int { return 12 }
|
||||
|
|
|
@ -9,11 +9,6 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
Map map[string]interface{}
|
||||
Debug bool
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "0.0"
|
||||
Title = "jupemail"
|
||||
|
@ -36,6 +31,9 @@ var (
|
|||
home string
|
||||
logBuffer *lineBuffer
|
||||
defaults map[string]map[string]interface{}
|
||||
|
||||
Map map[string]interface{}
|
||||
Debug bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -175,4 +173,5 @@ func associate() {
|
|||
if Debug = Config.GetBool("logger.debug"); Debug {
|
||||
println("debug on")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
37
db/db.go
37
db/db.go
|
@ -1,10 +1,11 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/prologic/bitcask"
|
||||
"github.com/rs/zerolog/log"
|
||||
"jupemail/config"
|
||||
// "time"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -12,13 +13,19 @@ var (
|
|||
maxSizeObj uint64
|
||||
dataDir string
|
||||
err error
|
||||
key []byte
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
Owner string
|
||||
Time int64
|
||||
}
|
||||
|
||||
const megabyte = float64(1024 * 1024)
|
||||
|
||||
func DbInit() {
|
||||
dataDir = config.Map["data.directory"].(string)
|
||||
maxSizeObj = config.Map["email.maxsize"].(uint64)
|
||||
dataDir = config.Config.GetString("data.directory")
|
||||
maxSizeObj = config.Config.GetUint64("email.maxsize")
|
||||
var dbo = []bitcask.Option{
|
||||
bitcask.WithMaxValueSize(maxSizeObj * uint64(1024)),
|
||||
}
|
||||
|
@ -28,12 +35,18 @@ func DbInit() {
|
|||
|
||||
}
|
||||
|
||||
//func CompressAndStore(recpt string, json []byte) error {
|
||||
// timestamp := time.Now()
|
||||
|
||||
// data, err := Gzip(json)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// Storage.Put()
|
||||
//}
|
||||
func CompressAndStore(rcpt string, valdata []byte) error {
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
key, err = json.Marshal(&Key{
|
||||
Owner: rcpt,
|
||||
Time: time.Now().Unix(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := Gzip(valdata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Storage.Put(key, data)
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
github.com/chrj/smtpd v0.3.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/jhillyerd/enmime v0.9.1
|
||||
github.com/json-iterator/go v1.1.6
|
||||
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/prologic/bitcask v0.3.10
|
||||
|
|
3
go.sum
3
go.sum
|
@ -141,6 +141,7 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
|
|||
github.com/jhillyerd/enmime v0.9.1 h1:HcC2WZA6dMCobs8WeyF/6FRSvdRCrr8O+UiLBae4eNE=
|
||||
github.com/jhillyerd/enmime v0.9.1/go.mod h1:S5ge4lnv/dDDBbAWwtoOFlj14NHiXdw/EqMB2lJz3b8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
|
@ -180,7 +181,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
|||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/lrstanley/girc"
|
||||
)
|
||||
|
||||
type BotStatus struct {
|
||||
Ready bool
|
||||
Error string
|
||||
Info string
|
||||
}
|
||||
|
||||
func (b *IRCBroker) StartBot(nick string, server string, port int, ssl bool, channel string, incoming chan []byte) chan Status {
|
||||
var client *girc.Client
|
||||
var status chan Status
|
||||
|
||||
client = girc.New(girc.Config{
|
||||
Server: server,
|
||||
Port: port,
|
||||
Nick: nick,
|
||||
Name: "jupemail",
|
||||
User: "jupemail",
|
||||
SSL: ssl,
|
||||
AllowFlood: true,
|
||||
Version: "~ JupeMail v0.0101 ~",
|
||||
})
|
||||
|
||||
client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
|
||||
status <- &BotStatus{
|
||||
Available: true,
|
||||
Info: "[IRC] Successfully connected to: " + server + " joining channel...",
|
||||
}
|
||||
c.Cmd.Join(ircHome)
|
||||
})
|
||||
|
||||
client.Handlers.Add(girc.ERR_CANNOTSENDTOCHAN, func(c *girc.Client, e girc.Event) {
|
||||
status <- &BotStatus{
|
||||
Available: false,
|
||||
Error: "ERR_CANNOTSENDTOCHAN",
|
||||
}
|
||||
})
|
||||
|
||||
sslString := " "
|
||||
if ircSSL == true {
|
||||
sslString = "-ssl"
|
||||
}
|
||||
status <- &BotStatus{
|
||||
Available: false,
|
||||
Info: "[IRC] Connecting...",
|
||||
}
|
||||
go botLoop()
|
||||
return status
|
||||
}
|
||||
|
||||
func botLoop() {
|
||||
for {
|
||||
if err := client.Connect(); err != nil {
|
||||
status <- &BotStatus{
|
||||
Available: false,
|
||||
Info: "[IRC] Reconnecting to " + ircHost + "/" + strconv.Itoa(ircPort) + " " + sslString,
|
||||
Error: err.Error(),
|
||||
}
|
||||
time.Sleep(time.Duration(500) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
5
main.go
5
main.go
|
@ -12,6 +12,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -61,7 +62,6 @@ func init() {
|
|||
Config := config.Blueprint()
|
||||
Debug := Config.GetBool("logger.debug")
|
||||
logDir = Config.GetString("logger.logdir")
|
||||
dataDir = Config.GetString("data.directory")
|
||||
bindTo = Config.GetString("email.listen")
|
||||
err = os.MkdirAll(logDir, 0755)
|
||||
if err != nil {
|
||||
|
@ -86,12 +86,13 @@ func init() {
|
|||
case dbgstr := <-dbgchan:
|
||||
log.Debug().Msg(dbgstr)
|
||||
default:
|
||||
//
|
||||
time.Sleep(time.Duration(25) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}(Rater.DebugChannel())
|
||||
}
|
||||
config.PrintConfigLog()
|
||||
db.DbInit()
|
||||
bnr()
|
||||
println("jupemail v0.0101 init")
|
||||
Quit = make(chan bool)
|
||||
|
|
48
message.go
48
message.go
|
@ -9,19 +9,18 @@ import (
|
|||
)
|
||||
|
||||
type Message struct {
|
||||
From []*Address `multipart:"from"`
|
||||
To []*Address `multipart:"to"`
|
||||
Cc []*Address `multipart:"cc"`
|
||||
Bcc []*Address `multipart:"bcc"`
|
||||
ReplyTo []*Address `multipart:"reply_to"`
|
||||
Subject string `multipart:"subject"`
|
||||
Date *Time `multipart:"date"`
|
||||
MessageID string `multipart:"message_id"`
|
||||
InReplyTo string `multipart:"in_reply_to"`
|
||||
References []string `multipart:"references"`
|
||||
Text string `multipart:"text"`
|
||||
HTML string `multipart:"html"`
|
||||
Attachments []*Attachment `multipart:"attachments"`
|
||||
From []*Address `multipart:"from"`
|
||||
To []*Address `multipart:"to"`
|
||||
Cc []*Address `multipart:"cc"`
|
||||
Bcc []*Address `multipart:"bcc"`
|
||||
ReplyTo []*Address `multipart:"reply_to"`
|
||||
Subject string `multipart:"subject"`
|
||||
Date time.Time `multipart:"date"`
|
||||
MessageID string `multipart:"message_id"`
|
||||
InReplyTo string `multipart:"in_reply_to"`
|
||||
References []string `multipart:"references"`
|
||||
Text string `multipart:"text"`
|
||||
HTML string `multipart:"html"`
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
|
@ -37,17 +36,12 @@ func NewMessage(r io.Reader) (*Message, error) {
|
|||
}
|
||||
|
||||
msg := &Message{
|
||||
Subject: env.GetHeader("Subject"),
|
||||
MessageID: env.GetHeader("Message-ID"),
|
||||
InReplyTo: env.GetHeader("In-Reply-To"),
|
||||
References: strings.Fields(env.GetHeader("References")),
|
||||
Text: env.Text,
|
||||
HTML: env.HTML,
|
||||
Attachments: make([]*Attachment, len(env.Attachments)),
|
||||
}
|
||||
|
||||
for i, attachment := range env.Attachments {
|
||||
msg.Attachments[i] = &Attachment{attachment}
|
||||
Subject: env.GetHeader("Subject"),
|
||||
MessageID: env.GetHeader("Message-ID"),
|
||||
InReplyTo: env.GetHeader("In-Reply-To"),
|
||||
References: strings.Fields(env.GetHeader("References")),
|
||||
Text: env.Text,
|
||||
HTML: env.HTML,
|
||||
}
|
||||
|
||||
if msg.From, err = readAddressListHeader(env, "From"); err != nil {
|
||||
|
@ -90,13 +84,13 @@ func readAddressListHeader(env *enmime.Envelope, key string) ([]*Address, error)
|
|||
return emails, nil
|
||||
}
|
||||
|
||||
func readDateHeader(env *enmime.Envelope) (*Time, error) {
|
||||
func readDateHeader(env *enmime.Envelope) (time.Time, error) {
|
||||
hdr := env.GetHeader("Date")
|
||||
|
||||
if hdr == "" {
|
||||
return &Time{time.Now()}, nil
|
||||
return time.Now(), nil
|
||||
}
|
||||
date, err := mail.ParseDate(hdr)
|
||||
|
||||
return &Time{date}, err
|
||||
return date, err
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ func NewDefaultLimiter(id Identity) *Queue {
|
|||
|
||||
func (q *Queue) DebugChannel() chan string {
|
||||
q.Patrons.OnEvicted(func(src string, count interface{}) {
|
||||
q.debugPrint("ratelimit (expired): ", src, count)
|
||||
q.debugPrint("ratelimit (expired): ", src, " ", count)
|
||||
})
|
||||
q.Debug = true
|
||||
debugChannel = make(chan string, 10)
|
||||
|
|
37
server.go
37
server.go
|
@ -2,9 +2,10 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/chrj/smtpd"
|
||||
"github.com/francoispqt/gojay"
|
||||
"io/ioutil"
|
||||
"jupemail/db"
|
||||
)
|
||||
|
||||
type Mail struct {
|
||||
|
@ -20,16 +21,19 @@ func NewMail(sender, recipient string, msg *Message) *Mail {
|
|||
type Server struct {
|
||||
srv *smtpd.Server
|
||||
Addresses map[string]Broker
|
||||
CatchAll bool
|
||||
}
|
||||
|
||||
func NewServer(newsmtpd *smtpd.Server) *Server {
|
||||
a := make(map[string]Broker)
|
||||
ibroker := NewIRCBroker("#go")
|
||||
a["kayos@crip.haus"] = ibroker
|
||||
a["kayos@crip.haus"] = NewIRCBroker("#go")
|
||||
|
||||
mx := &Server{
|
||||
srv: newsmtpd,
|
||||
Addresses: a,
|
||||
}
|
||||
|
||||
mx.CatchAll = false
|
||||
mx.srv.Handler = mx.ServeSMTP
|
||||
mx.srv.RecipientChecker = mx.CheckRecipient
|
||||
mx.srv.ConnectionChecker = mx.CheckConn
|
||||
|
@ -43,16 +47,21 @@ func (s *Server) CheckConn(p smtpd.Peer) error {
|
|||
// we're gonna DoS ourselves, maybe start doing batches
|
||||
return smtpd.Error{
|
||||
Code: 421,
|
||||
Message: "r e l a x",
|
||||
Message: "you are being ratelimited",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) CheckRecipient(p smtpd.Peer, addr string) error {
|
||||
if s.CatchAll {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := s.Addresses[addr]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warn().Str("caller", p.Addr.String()).Str("address", addr).
|
||||
Msg("denied unknown recipient address")
|
||||
return smtpd.Error{
|
||||
|
@ -81,18 +90,26 @@ func (s *Server) ServeSMTP(p smtpd.Peer, env smtpd.Envelope) error {
|
|||
buf := bytes.NewBuffer(nil)
|
||||
enc := gojay.NewEncoder(buf)
|
||||
enc.Encode(NewMail(env.Sender, addr, msg))
|
||||
|
||||
//enc := NewMultipartEncoder(buf)
|
||||
if err := enc.Encode(NewMail(env.Sender, addr, msg)); err != nil {
|
||||
//if err := enc.Encode("mail", NewMail(env.Sender, addr, msg)); err != nil {
|
||||
fmt.Println("could not encode request body:", err)
|
||||
|
||||
log.Error().Err(err).Msg("could not encode request body")
|
||||
return smtpd.Error{
|
||||
Code: 451,
|
||||
Message: "internal server error",
|
||||
}
|
||||
}
|
||||
fmt.Println(buf)
|
||||
d, err := ioutil.ReadAll(buf)
|
||||
if err != nil {
|
||||
log.Error().Interface("envelope", env).Err(err).Msg("!!!")
|
||||
}
|
||||
go s.deliverMessage(addr, d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) deliverMessage(addr string, d []byte) {
|
||||
err = db.CompressAndStore(addr, d)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("!!!")
|
||||
}
|
||||
s.Addresses[addr].Deliver(d)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue