From 9902b65d3feef74a30001b8f150299467693e699 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sat, 3 Aug 2024 11:50:24 +0700 Subject: lib/email: export the field Fields in Header By exporting the field, this allow the caller to filter or manage the Header Fields manually. --- lib/email/header.go | 63 ++++++++++++++++++++++++++-------------------------- lib/email/message.go | 14 ++++++------ 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/lib/email/header.go b/lib/email/header.go index 1e0eae03..10f84b86 100644 --- a/lib/email/header.go +++ b/lib/email/header.go @@ -12,14 +12,15 @@ import ( "strings" ) -// Header represent list of fields in message. +// Header represent header of message. +// It contains list of field in message. type Header struct { - // fields is ordered from top to bottom, the first field in message + // Fields is ordered from top to bottom, the first field in message // header is equal to the first element in slice. // // We are not using map here it to prevent the header being reordered // when packing the message back into raw format. - fields []*Field + Fields []*Field } // ParseHeader parse the raw header from top to bottom. @@ -59,7 +60,7 @@ func ParseHeader(raw []byte) (hdr *Header, rest []byte, err error) { if hdr == nil { hdr = &Header{} } - hdr.fields = append(hdr.fields, field) + hdr.Fields = append(hdr.Fields, field) } if len(rest) == 0 { return hdr, rest, nil @@ -75,7 +76,7 @@ func (hdr *Header) addMailboxes(ft FieldType, mailboxes []byte) (err error) { f, field *Field ) - for _, f = range hdr.fields { + for _, f = range hdr.Fields { if f.Type == ft { field = f break @@ -85,7 +86,7 @@ func (hdr *Header) addMailboxes(ft FieldType, mailboxes []byte) (err error) { field = &Field{ Type: ft, } - hdr.fields = append(hdr.fields, field) + hdr.Fields = append(hdr.Fields, field) field.setName([]byte(fieldNames[ft])) field.setValue(mailboxes) return field.unpack() @@ -107,7 +108,7 @@ func (hdr *Header) Boundary() string { // ContentType return the unpacked value of field "Content-Type", or nil if no // field Content-Type exist or there is an error when unpacking. func (hdr *Header) ContentType() *ContentType { - for _, f := range hdr.fields { + for _, f := range hdr.Fields { if f.Type != FieldTypeContentType { continue } @@ -129,27 +130,27 @@ func (hdr *Header) ContentType() *ContentType { // For example, to get the second DKIM-Signature from the top, call it with // "n=2", but if no second DKIM-Signature it will return nil. func (hdr *Header) DKIM(n int) (dkimHeader *Header) { - if n == 0 || len(hdr.fields) == 0 { + if n == 0 || len(hdr.Fields) == 0 { return nil } x := 0 - for ; x < len(hdr.fields); x++ { - if hdr.fields[x].Type == FieldTypeDKIMSignature { + for ; x < len(hdr.Fields); x++ { + if hdr.Fields[x].Type == FieldTypeDKIMSignature { n-- if n == 0 { break } } } - if x == len(hdr.fields) { + if x == len(hdr.Fields) { return nil } dkimHeader = &Header{ - fields: make([]*Field, 0, len(hdr.fields)-x), + Fields: make([]*Field, 0, len(hdr.Fields)-x), } - for ; x < len(hdr.fields); x++ { - dkimHeader.fields = append(dkimHeader.fields, hdr.fields[x]) + for ; x < len(hdr.Fields); x++ { + dkimHeader.Fields = append(dkimHeader.Fields, hdr.Fields[x]) } return dkimHeader @@ -158,9 +159,9 @@ func (hdr *Header) DKIM(n int) (dkimHeader *Header) { // Filter specific field type. If multiple fields type exist it will // return all of them. func (hdr *Header) Filter(ft FieldType) (fields []*Field) { - for x := len(hdr.fields) - 1; x >= 0; x-- { - if hdr.fields[x].Type == ft { - fields = append(fields, hdr.fields[x]) + for x := len(hdr.Fields) - 1; x >= 0; x-- { + if hdr.Fields[x].Type == ft { + fields = append(fields, hdr.Fields[x]) } } return @@ -168,9 +169,9 @@ func (hdr *Header) Filter(ft FieldType) (fields []*Field) { // ID return the Message-ID or empty if not exist. func (hdr *Header) ID() string { - for x := len(hdr.fields) - 1; x >= 0; x-- { - if hdr.fields[x].Type == FieldTypeMessageID { - return hdr.fields[x].oriValue + for x := len(hdr.Fields) - 1; x >= 0; x-- { + if hdr.Fields[x].Type == FieldTypeMessageID { + return hdr.Fields[x].oriValue } } return `` @@ -178,14 +179,14 @@ func (hdr *Header) ID() string { // PushTop put the field at the top of header. func (hdr *Header) PushTop(f *Field) { - hdr.fields = append([]*Field{f}, hdr.fields...) + hdr.Fields = append([]*Field{f}, hdr.Fields...) } // Relaxed canonicalize the header using "relaxed" algorithm and return it. func (hdr *Header) Relaxed() []byte { var bb bytes.Buffer - for _, f := range hdr.fields { + for _, f := range hdr.Fields { if len(f.Name) > 0 && len(f.Value) > 0 { bb.Write(f.Relaxed()) } @@ -213,13 +214,13 @@ func (hdr *Header) Set(ft FieldType, value []byte) (err error) { return fmt.Errorf("Set: %w", err) } - for x, f = range hdr.fields { + for x, f = range hdr.Fields { if f.Type == ft { - hdr.fields[x] = field + hdr.Fields[x] = field return nil } } - hdr.fields = append(hdr.fields, field) + hdr.Fields = append(hdr.Fields, field) return nil } @@ -227,7 +228,7 @@ func (hdr *Header) Set(ft FieldType, value []byte) (err error) { func (hdr *Header) Simple() []byte { var bb bytes.Buffer - for _, f := range hdr.fields { + for _, f := range hdr.Fields { if len(f.oriName) > 0 && len(f.oriValue) > 0 { bb.WriteString(f.oriName) bb.WriteByte(':') @@ -240,10 +241,10 @@ func (hdr *Header) Simple() []byte { // popByName remove the field where the name match from header. func (hdr *Header) popByName(name string) (f *Field) { - for x := len(hdr.fields) - 1; x >= 0; x-- { - if strings.EqualFold(hdr.fields[x].Name, name) { - f = hdr.fields[x] - hdr.fields = append(hdr.fields[:x], hdr.fields[x+1:]...) + for x := len(hdr.Fields) - 1; x >= 0; x-- { + if strings.EqualFold(hdr.Fields[x].Name, name) { + f = hdr.Fields[x] + hdr.Fields = append(hdr.Fields[:x], hdr.Fields[x+1:]...) } } return f @@ -276,7 +277,7 @@ func (hdr *Header) WriteTo(w io.Writer) (n int64, err error) { f *Field m int ) - for _, f = range hdr.fields { + for _, f = range hdr.Fields { switch f.Type { case FieldTypeContentType: m, err = fmt.Fprintf(w, "%s: %s\r\n", f.Name, f.contentType.String()) diff --git a/lib/email/message.go b/lib/email/message.go index a3028267..e2570947 100644 --- a/lib/email/message.go +++ b/lib/email/message.go @@ -212,9 +212,9 @@ func (msg *Message) DKIMSign(pk *rsa.PrivateKey, sig *dkim.Signature) (err error } subHeader := &Header{ - fields: make([]*Field, len(msg.Header.fields)), + Fields: make([]*Field, len(msg.Header.Fields)), } - copy(subHeader.fields, msg.Header.fields) + copy(subHeader.Fields, msg.Header.Fields) hh, _ := sig.Hash(msg.CanonHeader(subHeader, dkimField)) @@ -247,12 +247,12 @@ func (msg *Message) DKIMVerify() (*dkim.Status, error) { // Only process the first DKIM-Signature for now. subHeader := msg.Header.DKIM(1) - if subHeader == nil || len(subHeader.fields) == 0 { + if subHeader == nil || len(subHeader.Fields) == 0 { msg.dkimStatus.Type = dkim.StatusNoSignature return msg.dkimStatus, nil } - sig, err := dkim.Parse([]byte(subHeader.fields[0].Value)) + sig, err := dkim.Parse([]byte(subHeader.Fields[0].Value)) if sig != nil && len(sig.SDID) > 0 { msg.dkimStatus.SDID = libbytes.Copy(sig.SDID) @@ -303,7 +303,7 @@ func (msg *Message) DKIMVerify() (*dkim.Status, error) { return nil, err } - canonHeader := msg.CanonHeader(subHeader, subHeader.fields[0]) + canonHeader := msg.CanonHeader(subHeader, subHeader.Fields[0]) hh, _ := sig.Hash(canonHeader) err = sig.Verify(key, hh) @@ -636,9 +636,9 @@ func (msg *Message) setDKIMHeaders(sig *dkim.Signature) { return } - sig.Headers = make([][]byte, 0, len(msg.Header.fields)) + sig.Headers = make([][]byte, 0, len(msg.Header.Fields)) - for _, f := range msg.Header.fields { + for _, f := range msg.Header.Fields { sig.Headers = append(sig.Headers, []byte(f.Name)) } } -- cgit v1.3