// Command dkim-proxy implements a simple SMTP proxy that DKIM signs incoming e-mail and relays to another SMTP server for delivery
package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"net/smtp"

	"github.com/chrj/smtpd"
	"github.com/eaigner/dkim"
)

var (
	welcomeMsg  = flag.String("welcome", "DKIM-proxy ESMTP ready.", "Welcome message for SMTP session")
	inAddr      = flag.String("inaddr", "localhost:10025", "Address to listen for incoming SMTP on")
	outAddr     = flag.String("outaddr", "localhost:25", "Address to deliver outgoing SMTP on")
	privKeyFile = flag.String("key", "", "Private key file.")
	dkimS       = flag.String("s", "default", "DKIM selector")
	dkimD       = flag.String("d", "", "DKIM domain")

	dkimConf dkim.Conf
	privKey  []byte
)

func handler(peer smtpd.Peer, env smtpd.Envelope) error {

	d, err := dkim.New(dkimConf, privKey)
	if err != nil {
		log.Printf("DKIM error: %v", err)
		return smtpd.Error{450, "Internal server error"}
	}

	// The dkim package expects \r\n newlines, so replace to that
	data, err := d.Sign(bytes.Replace(env.Data, []byte("\n"), []byte("\r\n"), -1))
	if err != nil {
		log.Printf("DKIM signing error: %v", err)
		return smtpd.Error{450, "Internal server error"}
	}

	return smtp.SendMail(
		*outAddr,
		nil,
		env.Sender,
		env.Recipients,
		data,
	)

}

func main() {

	flag.Parse()

	var err error

	dkimConf, err = dkim.NewConf(*dkimD, *dkimS)
	if err != nil {
		log.Fatalf("DKIM configuration error: %v", err)
	}

	privKey, err = ioutil.ReadFile(*privKeyFile)
	if err != nil {
		log.Fatalf("Couldn't read private key: %v", err)
	}

	_, err = dkim.New(dkimConf, privKey)
	if err != nil {
		log.Fatalf("DKIM error: %v", err)
	}

	server := &smtpd.Server{
		WelcomeMessage: *welcomeMsg,
		Handler:        handler,
	}

	server.ListenAndServe(*inAddr)

}
