mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
96 lines
1.9 KiB
Go
96 lines
1.9 KiB
Go
package emsg
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
const Magic = "EMSG"
|
|
const Version = 1
|
|
|
|
// Bitmask flags for sections
|
|
const (
|
|
FlagPlainText uint32 = 1 << 0
|
|
FlagHTMLBody uint32 = 1 << 1
|
|
)
|
|
|
|
// EmailBlob represents a binary-encoded email body and metadata.
|
|
type EmailBlob struct {
|
|
PlainText []byte
|
|
HTMLBody []byte
|
|
}
|
|
|
|
// EncodeBinary serializes the blob into binary format.
|
|
func (b *EmailBlob) EncodeBinary() ([]byte, error) {
|
|
var flags uint32
|
|
parts := make([][]byte, 0, 5)
|
|
|
|
if len(b.PlainText) > 0 {
|
|
flags |= FlagPlainText
|
|
parts = append(parts, b.PlainText)
|
|
}
|
|
if len(b.HTMLBody) > 0 {
|
|
flags |= FlagHTMLBody
|
|
parts = append(parts, b.HTMLBody)
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
// Write header
|
|
buf.WriteString(Magic) // 4 bytes
|
|
buf.WriteByte(Version) // 1 byte
|
|
binary.Write(buf, binary.BigEndian, flags) // 4 bytes
|
|
|
|
// Write each section [len][data]
|
|
for _, p := range parts {
|
|
binary.Write(buf, binary.BigEndian, uint32(len(p)))
|
|
buf.Write(p)
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// DecodeBinary parses a binary blob into an EmailBlob struct.
|
|
func DecodeBinary(r io.Reader) (*EmailBlob, error) {
|
|
header := make([]byte, 9)
|
|
if _, err := io.ReadFull(r, header); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if string(header[:4]) != Magic {
|
|
return nil, errors.New("invalid magic header")
|
|
}
|
|
version := header[4]
|
|
if version != Version {
|
|
return nil, fmt.Errorf("unsupported version: %d", version)
|
|
}
|
|
|
|
flags := binary.BigEndian.Uint32(header[5:9])
|
|
|
|
readSection := func() ([]byte, error) {
|
|
var length uint32
|
|
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
|
|
return nil, err
|
|
}
|
|
data := make([]byte, length)
|
|
if _, err := io.ReadFull(r, data); err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
b := &EmailBlob{}
|
|
|
|
if flags&FlagPlainText != 0 {
|
|
b.PlainText, _ = readSection()
|
|
}
|
|
if flags&FlagHTMLBody != 0 {
|
|
b.HTMLBody, _ = readSection()
|
|
}
|
|
|
|
return b, nil
|
|
}
|