sophuwu.site > mailboxxer   
              98
            
             package main

import (
	"bytes"
	"encoding/base64"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"regexp"
	"strings"
)

type FileList map[string][]byte

func getfiles(files *FileList, parts interface{}) {
	var body io.Reader
	var head textproto.MIMEHeader
	switch part := parts.(type) {
	case *mail.Message:
		body = part.Body
		head = textproto.MIMEHeader(part.Header)
	case *multipart.Part:
		body = part
		head = part.Header
	}
	mediaType, params, _ := mime.ParseMediaType(head.Get("Content-Type"))

	if strings.HasPrefix(mediaType, "multipart/") {
		mr := multipart.NewReader(body, params["boundary"])
		var part *multipart.Part
		var err error
		for {
			if part, err = mr.NextPart(); err != nil {
				break
			}
			getfiles(files, part)
			part.Close()
		}
		return
	}
	content, _ := io.ReadAll(body)
	if head.Get("Content-Transfer-Encoding") == "base64" {
		content, _ = base64.StdEncoding.DecodeString(string(content))
	}
	if len(content) == 0 {
		return
	}
	if mediaType == "text/html" || mediaType == "text/plain" {
		content = []byte(func(s string) string {
			s = strings.ReplaceAll(s, "=\n", "")
			s = strings.ReplaceAll(s, "=3D", "=")
			return s
		}(string(content)))
	}
	name := "body.txt"
	if params["name"] != "" {
		name = params["name"]
	}
	if strings.Contains(mediaType, "html") {
		name = "body.html"
	}
	(*files)[name] = append((*files)[name], content...)
	if head.Get("Content-ID") != "" {
		cid := head.Get("Content-ID")
		cid = strings.TrimPrefix(cid, "<")
		cid = strings.TrimSuffix(cid, ">")
		cid = "cidname: " + cid + " " + name + "\n"
		(*files)["header.txt"] = append((*files)["header.txt"], []byte(cid)...)
	}
}

var cidheader = regexp.MustCompile(`^cidname: [^ ]+ [^ ]+$`) // Content-ID header

func EmlFiles(eml *mail.Message, head []byte) FileList {

	files := make(FileList)
	getfiles(&files, eml)
	for _, v := range cidheader.FindAll(files["header.txt"], -1) {
		v = bytes.TrimSuffix(v, []byte("\n"))
		v = bytes.ReplaceAll(v, []byte("cidname: "), []byte("cid:"))
		n := bytes.Index(v, []byte(" "))
		files["body.html"] = bytes.ReplaceAll(files["body.html"], v[:n], v[n+1:])
	}
	files["header.txt"] = head
	return files
}

func GetFiles(b *bytes.Buffer) (FileList, error) {
	head := bytes.SplitN(b.Bytes(), []byte{10, 10}, 2)[0]
	head = bytes.ReplaceAll(head, []byte{'\t'}, []byte{' '})
	e, err := mail.ReadMessage(b)
	if err != nil {
		return nil, err
	}
	return EmlFiles(e, head), nil
}