<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"html/template"
	"log"
	"mime"
	"net"
	"net/http"
	"net/mail"
	"net/smtp"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/mhale/smtpd"
	"github.com/streadway/simpleuuid"
)

var (
	config Config  // Filters & routes
	stats  Stats   // Statistics of sent and dropped mail
	logs   LogList // Recent mail log for Dashboard
)

var httpAddr *string = flag.String("http", ":8080", "Address & port for HTTP server")
var smtpAddr *string = flag.String("smtp", ":2525", "Address & port for SMTP server")
var confFile *string = flag.String("conf", "/etc/mailrouter.conf", "Full path to configuration file")

// Handler for handling incoming mail messages.
func mailHandler(origin net.Addr, from string, to []string, data []byte) {
	originIPStr, _, _ := net.SplitHostPort(origin.String())
	originIP := net.ParseIP(originIPStr)

	// Parse the message to get the Subject header.
	msg, err := mail.ReadMessage(bytes.NewReader(data))
	if err != nil {
		log.Printf("Failed to parse message: %s\n", err)
		log.Printf("Aborting processing of message.")
		return
	}
	subject := msg.Header.Get("Subject")

	// Check each filter in order.
	var filterName string
	var routeId string
	for _, filter := range SortedFilters() {
		if filter.Match(from, to, subject, originIP) {
			filterName = filter.Name
			routeId = filter.RouteId
			break
		}
	}

	// Use the default route if no filters were matched.
	if routeId == "" {
		for _, route := range config.Routes {
			if route.IsDefault {
				routeId = route.Id
			}
		}
	}

	// If the message is to be dropped, record the drop and return.
	if routeId == "DROP" {
		stats.Dropped(len(data))
		logs.Add(originIP, from, to, subject, filterName, "Drop")
		return
	}

	// Otherwise, deliver the mail to the selected route and record the delivery.
	route := config.Routes[routeId]
	addr := route.Hostname + ":" + strconv.Itoa(route.Port)

	// Override the recipient if To field is set.
	if route.To != "" {
		to = []string{route.To}
	}

	// Deliver the mail.
	err = smtp.SendMail(addr, nil, from, to, data)
	if err != nil {
		log.Printf("Failed to deliver mail to route %s (%s): %s", route.Name, addr, err)
		return
	}

	// Record the successful delivery.
	stats.Sent(len(data))
	logs.Add(originIP, from, to, subject, filterName, route.Name)
}

// Utility function for parsing URLs like /route/:id/:action
func ParsePath(path string) (base string, id string, action string) {
	path = strings.Trim(path, "/")
	parts := strings.Split(path, "/")
	if len(parts) > 0 {
		base = parts[0]
	}
	if len(parts) > 1 {
		id = parts[1]
	}
	if len(parts) > 2 {
		action = parts[2]
	}
	return base, id, action
}

func routeHandler(w http.ResponseWriter, req *http.Request) {
	var msg string
	_, id, action := ParsePath(req.URL.Path)
	method := req.FormValue("_method")

	if req.Method == "GET" {
		data := make(map[string]interface{})
		data["list"] = SortedRoutes()

		// Populate the form if requested.
		if id != "" && action == "edit" {
			data["id"] = id
			data["edit"] = config.Routes[id]
		}

		// Render the page. Reparsing the template every time eases development at the expense of performance.
		html, _ := Asset("views/routes.html")
		tmpl, err := template.New("routes").Parse(string(html))
		if err != nil {
			log.Println(err)
		}
		err = tmpl.Execute(w, data)
		if err != nil {
			log.Println(err)
		}
	}

	if req.Method == "POST" {
		config.Lock()
		defer config.Unlock()

		if method == "delete" {
			msg = fmt.Sprintf("Deleted route %s.", config.Routes[id].Name)
			delete(config.Routes, id)
		}

		if method == "default" {
			msg = fmt.Sprintf("Set %s as default route.", config.Routes[id].Name)
			for id, route := range config.Routes {
				route.IsDefault = false
				config.Routes[id] = route
			}
			route := config.Routes[id]
			route.IsDefault = true
			config.Routes[id] = route
		}

		if method == "save" {
			// Unset id means a new route is being added
			if id == "" {
				msg = fmt.Sprintf("Added route %s to host %s.", req.FormValue("routename"), req.FormValue("hostname"))
				uuid, _ := simpleuuid.NewTime(time.Now())
				id = uuid.String()
			} else {
				msg = fmt.Sprintf("Updated route %s.", req.FormValue("routename"))
			}

			// Create a new Route from the form submission.
			port, _ := strconv.Atoi(req.FormValue("port"))
			route := Route{
				Id:       id,<commit_msg>Improve info message.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"html/template"
	"log"
	"mime"
	"net"
	"net/http"
	"net/mail"
	"net/smtp"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/mhale/smtpd"
	"github.com/streadway/simpleuuid"
)

var (
	config Config  // Filters & routes
	stats  Stats   // Statistics of sent and dropped mail
	logs   LogList // Recent mail log for Dashboard
)

var httpAddr *string = flag.String("http", ":8080", "Address & port for HTTP server")
var smtpAddr *string = flag.String("smtp", ":2525", "Address & port for SMTP server")
var confFile *string = flag.String("conf", "/etc/mailrouter.conf", "Full path to configuration file")

// Handler for handling incoming mail messages.
func mailHandler(origin net.Addr, from string, to []string, data []byte) {
	originIPStr, _, _ := net.SplitHostPort(origin.String())
	originIP := net.ParseIP(originIPStr)

	// Parse the message to get the Subject header.
	msg, err := mail.ReadMessage(bytes.NewReader(data))
	if err != nil {
		log.Printf("Failed to parse message: %s\n", err)
		log.Printf("Aborting processing of message.")
		return
	}
	subject := msg.Header.Get("Subject")

	// Check each filter in order.
	var filterName string
	var routeId string
	for _, filter := range SortedFilters() {
		if filter.Match(from, to, subject, originIP) {
			filterName = filter.Name
			routeId = filter.RouteId
			break
		}
	}

	// Use the default route if no filters were matched.
	if routeId == "" {
		for _, route := range config.Routes {
			if route.IsDefault {
				routeId = route.Id
			}
		}
	}

	// If the message is to be dropped, record the drop and return.
	if routeId == "DROP" {
		stats.Dropped(len(data))
		logs.Add(originIP, from, to, subject, filterName, "Drop")
		return
	}

	// Otherwise, deliver the mail to the selected route and record the delivery.
	route := config.Routes[routeId]
	addr := route.Hostname + ":" + strconv.Itoa(route.Port)

	// Override the recipient if To field is set.
	if route.To != "" {
		to = []string{route.To}
	}

	// Deliver the mail.
	err = smtp.SendMail(addr, nil, from, to, data)
	if err != nil {
		log.Printf("Failed to deliver mail to route %s (%s): %s", route.Name, addr, err)
		return
	}

	// Record the successful delivery.
	stats.Sent(len(data))
	logs.Add(originIP, from, to, subject, filterName, route.Name)
}

// Utility function for parsing URLs like /route/:id/:action
func ParsePath(path string) (base string, id string, action string) {
	path = strings.Trim(path, "/")
	parts := strings.Split(path, "/")
	if len(parts) > 0 {
		base = parts[0]
	}
	if len(parts) > 1 {
		id = parts[1]
	}
	if len(parts) > 2 {
		action = parts[2]
	}
	return base, id, action
}

func routeHandler(w http.ResponseWriter, req *http.Request) {
	var msg string
	_, id, action := ParsePath(req.URL.Path)
	method := req.FormValue("_method")

	if req.Method == "GET" {
		data := make(map[string]interface{})
		data["list"] = SortedRoutes()

		// Populate the form if requested.
		if id != "" && action == "edit" {
			data["id"] = id
			data["edit"] = config.Routes[id]
		}

		// Render the page. Reparsing the template every time eases development at the expense of performance.
		html, _ := Asset("views/routes.html")
		tmpl, err := template.New("routes").Parse(string(html))
		if err != nil {
			log.Println(err)
		}
		err = tmpl.Execute(w, data)
		if err != nil {
			log.Println(err)
		}
	}

	if req.Method == "POST" {
		config.Lock()
		defer config.Unlock()

		if method == "delete" {
			msg = fmt.Sprintf("Deleted route %s.", config.Routes[id].Name)
			delete(config.Routes, id)
		}

		if method == "default" {
			msg = fmt.Sprintf("Set %s as the default route.", config.Routes[id].Name)
			for id, route := range config.Routes {
				route.IsDefault = false
				config.Routes[id] = route
			}
			route := config.Routes[id]
			route.IsDefault = true
			config.Routes[id] = route
		}

		if method == "save" {
			// Unset id means a new route is being added
			if id == "" {
				msg = fmt.Sprintf("Added route %s to host %s.", req.FormValue("routename"), req.FormValue("hostname"))
				uuid, _ := simpleuuid.NewTime(time.Now())
				id = uuid.String()
			} else {
				msg = fmt.Sprintf("Updated route %s.", req.FormValue("routename"))
			}

			// Create a new Route from the form submission.
			port, _ := strconv.Atoi(req.FormValue("port"))
			route := Route{
				Id:       id,
{'fraction_non_alphanumeric': 0.14949977262391997, 'fraction_numerical': 0.0031832651205093224, 'mean_word_length': 3.3313638601674054, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6907621', 'n_tokens_mistral': 3310, 'n_tokens_neox': 3038, 'n_words': 878}