mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
More MIME parsing progress!
After parsing MIME into a tree of nodes, we can now issue BreadthFirstSearch commands against it to locate the text and HTML portions of the email.
This commit is contained in:
@@ -2,33 +2,56 @@ package inbucket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const MIME_BUF_BYTES = 1024
|
type MIMENodeMatcher func(node *MIMENode) bool
|
||||||
|
|
||||||
type MIMEMessage struct {
|
|
||||||
text string
|
|
||||||
html string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MIMENode struct {
|
type MIMENode struct {
|
||||||
Parent *MIMENode
|
Parent *MIMENode
|
||||||
FirstChild *MIMENode
|
FirstChild *MIMENode
|
||||||
NextSibling *MIMENode
|
NextSibling *MIMENode
|
||||||
Type string
|
Type string
|
||||||
Content *bytes.Buffer
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type MIMEMessage struct {
|
||||||
|
Text string
|
||||||
|
Html string
|
||||||
|
Root *MIMENode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMIMENode(parent *MIMENode, contentType string) *MIMENode {
|
func NewMIMENode(parent *MIMENode, contentType string) *MIMENode {
|
||||||
return &MIMENode{Parent: parent, Type: contentType}
|
return &MIMENode{Parent: parent, Type: contentType}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *MIMENode) BreadthFirstSearch(matcher MIMENodeMatcher) *MIMENode {
|
||||||
|
q := list.New()
|
||||||
|
q.PushBack(n)
|
||||||
|
|
||||||
|
// Push children onto queue and attempt to match in that order
|
||||||
|
for q.Len() > 0 {
|
||||||
|
e := q.Front()
|
||||||
|
n := e.Value.(*MIMENode)
|
||||||
|
if matcher(n) {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
q.Remove(e)
|
||||||
|
c := n.FirstChild
|
||||||
|
for c != nil {
|
||||||
|
q.PushBack(c)
|
||||||
|
c = c.NextSibling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (n *MIMENode) String() string {
|
func (n *MIMENode) String() string {
|
||||||
children := ""
|
children := ""
|
||||||
siblings := ""
|
siblings := ""
|
||||||
@@ -66,9 +89,32 @@ func ParseMIMEMessage(mailMsg *mail.Message) (*MIMEMessage, error) {
|
|||||||
|
|
||||||
err = parseNodes(root, mailMsg.Body, boundary)
|
err = parseNodes(root, mailMsg.Body, boundary)
|
||||||
fmt.Println(root.String())
|
fmt.Println(root.String())
|
||||||
|
|
||||||
|
// Locate text body
|
||||||
|
match := root.BreadthFirstSearch(func(node *MIMENode) bool {
|
||||||
|
return node.Type == "text/plain"
|
||||||
|
})
|
||||||
|
if match != nil {
|
||||||
|
mimeMsg.Text = string(match.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate HTML body
|
||||||
|
match = root.BreadthFirstSearch(func(node *MIMENode) bool {
|
||||||
|
return node.Type == "text/html"
|
||||||
|
})
|
||||||
|
if match != nil {
|
||||||
|
mimeMsg.Html = string(match.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(mimeMsg.String())
|
||||||
|
|
||||||
return mimeMsg, err
|
return mimeMsg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MIMEMessage) String() string {
|
||||||
|
return fmt.Sprintf("----TEXT----\n%v\n----HTML----\n%v\n----END----\n", m.Text, m.Html)
|
||||||
|
}
|
||||||
|
|
||||||
func parseNodes(parent *MIMENode, reader io.Reader, boundary string) error {
|
func parseNodes(parent *MIMENode, reader io.Reader, boundary string) error {
|
||||||
var prevSibling *MIMENode
|
var prevSibling *MIMENode
|
||||||
|
|
||||||
@@ -106,14 +152,12 @@ func parseNodes(parent *MIMENode, reader io.Reader, boundary string) error {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Content is data, allocate a buffer
|
// Content is data, allocate a buffer
|
||||||
node.Content = new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
_, err = io.Copy(node.Content, part)
|
_, err = buf.ReadFrom(part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("\n----\n")
|
node.Content = buf.Bytes()
|
||||||
io.Copy(os.Stdout, node.Content)
|
|
||||||
fmt.Printf("\n----\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user