Author: LakeFox
Email: [email protected]
Date: Sun, 20 Apr 2025 21:12:40 -0600
email/main.go
Re made the entire thing
Commits
Diff
diff --git a/email/main.go b/email/main.go
deleted file mode 100644
index 8919f0d..0000000
--- a/email/main.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package email
-
-import (
-	"github.com/emersion/go-imap"
-	"github.com/emersion/go-imap/client"
-	"io"
-	"log"
-	"mime/quotedprintable"
-	"net/mail"
-	"strings"
-)
-
-type Inbox struct {
-	Client  *client.Client
-	Threads []Thread
-}
-
-type Thread struct {
-	Tag string `json:"tag" xml:"tag" text:"Tag"`
-	Root Message  `json:"root" xml:"root" text:"Root"`
-	Subject string `json:"subject" xml:"subject" text:"Subject"`
-	ThreadId string `json:"threadid" xml:"threadid" text:"Thread Id"`
-}
-
-type Message struct {
-	Children  []*Message `json:"children" xml:"children>message" text:"Children"`
-	InReplyTo string     `json:"inreplyto" xml:"inreplyto" text:"In Reply To,omitempty"`
-	To string `json:"to" xml:"to" text:"To"`
-	From string `json:"from" xml:"from" text:"from"`
-	Cc string `json:"cc" xml:"cc" text:"CC"`
-	Bcc string `json:"bcc" xml:"bcc" text:"BCC"`
-	Tag      string   `json:"tag" xml:"tag" text:"Tag"`
-	Subject   string     `json:"subject" xml:"subject" text:"Subject"`
-	Body      string     `json:"body" xml:"body" text:"Body"`
-	MessageId string     `json:"messageId" xml:"messageid" text:"Message ID"`
-}
-
-func Connect(server, username, password string) Inbox {
-	// Connect to server
-	c, err := client.DialTLS(server, nil)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	// Login
-	if err := c.Login(username, password); err != nil {
-		log.Fatal(err)
-	}
-
-	return Inbox{
-		Threads: []Thread{},
-		Client:  c,
-	}
-}
-
-func (i *Inbox) GetMessages(inbox string) {
-	mbox, _ := i.Client.Select(inbox, false)
-	from := uint32(1)
-	to := mbox.Messages
-
-	seqset := new(imap.SeqSet)
-	seqset.AddRange(from, to)
-
-	messages := make(chan *imap.Message, 10)
-	done := make(chan error, 1)
-	go func() {
-		done <- i.Client.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchItem("BODY.PEEK[]")}, messages)
-	}()
-
-	// Initialize a map to store messages by their In-Reply-To for efficient parent-child linking
-	messageMap := make(map[string]*Message)
-
-	for msg := range messages {
-		tags := parseTags(msg.Envelope.Subject)
-		if len(tags) > 0 {
-			m := Message{
-				Children: []*Message{},
-			}
-
-			holder := ""
-			for _, bodyPart := range msg.Body {
-				if bodyPart != nil {
-					b, _ := io.ReadAll(bodyPart)
-					holder += string(b)
-				}
-			}
-			msgReader, _ := mail.ReadMessage(strings.NewReader(holder))
-			body, _ := io.ReadAll(msgReader.Body)
-
-			decoder := quotedprintable.NewReader(strings.NewReader(string(body)))
-
-			decoded, _ := io.ReadAll(decoder)
-			m.Body = string(decoded)
-			m.Tag = tags[0]
-			m.Subject = parseSubject(msg.Envelope.Subject)
-			m.InReplyTo = msg.Envelope.InReplyTo
-			var to, from, cc, bcc string
-			for _, v := range msg.Envelope.To {
-				to += ", "+v.AtDomainList
-			}
-			for _, v := range msg.Envelope.From {
-				from += ", "+v.AtDomainList
-			}
-			for _, v := range msg.Envelope.Cc {
-				cc += ", "+v.AtDomainList
-			}
-			for _, v := range msg.Envelope.Bcc {
-				bcc += ", "+v.AtDomainList
-			}
-			m.To = to
-			m.From = from
-			m.Cc = cc
-			m.Bcc = bcc
-			m.InReplyTo = msg.Envelope.InReplyTo
-
-			// Store the message in the map using its Message-ID as the key
-			messageID := msg.Envelope.MessageId
-			m.MessageId = messageID[1:strings.Index(messageID,"@")]
-			messageMap[messageID] = &m
-		}
-	}
-
-	// Link parent and child messages
-	for _, msg := range messageMap {
-		if msg.InReplyTo != "" { // Only process root-level messages initially
-			if parentMsg, ok := messageMap[msg.InReplyTo]; ok {
-				parentMsg.Children = append(parentMsg.Children, msg)
-			}
-		}
-	}
-
-	// Create threads from root-level messages
-	for _, v := range messageMap {
-		if v.InReplyTo == "" {
-			thread := Thread{
-				Tag: v.Tag,
-				Root: *v, // Dereference here to avoid storing a pointer in the Thread root
-				Subject: v.Subject,
-				ThreadId: v.MessageId,
-			}
-			i.Threads = append(i.Threads, thread)
-		}
-	}
-}
-
-func parseTags(subject string) []string {
-	tags := []string{}
-	currentTag := ""
-	record := false
-
-	for _, v := range subject {
-		if v == ']' && record {
-			record = false
-			tags = append(tags, currentTag)
-			currentTag = ""
-		}
-		if record {
-			currentTag += string(v)
-		}
-		if v == '[' && !record {
-			record = true
-		}
-
-	}
-	return tags
-}
-
-func parseSubject(subject string) string {
-	var title string
-
-	for i := len(subject) - 1; i >= 0; i-- {
-		if subject[i] == ']' {
-			break
-		} else {
-			title = string(subject[i]) + title
-		}
-	}
-	return strings.TrimSpace(title)
-}
package email

import (
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
	"io"
	"log"
	"mime/quotedprintable"
	"net/mail"
	"strings"
)

type Inbox struct {
	Client  *client.Client
	Threads []Thread
}

type Thread struct {
	Tag string `json:"tag" xml:"tag" text:"Tag"`
	Root Message  `json:"root" xml:"root" text:"Root"`
	Subject string `json:"subject" xml:"subject" text:"Subject"`
	ThreadId string `json:"threadid" xml:"threadid" text:"Thread Id"`
}

type Message struct {
	Children  []*Message `json:"children" xml:"children>message" text:"Children"`
	InReplyTo string     `json:"inreplyto" xml:"inreplyto" text:"In Reply To,omitempty"`
	To string `json:"to" xml:"to" text:"To"`
	From string `json:"from" xml:"from" text:"from"`
	Cc string `json:"cc" xml:"cc" text:"CC"`
	Bcc string `json:"bcc" xml:"bcc" text:"BCC"`
	Tag      string   `json:"tag" xml:"tag" text:"Tag"`
	Subject   string     `json:"subject" xml:"subject" text:"Subject"`
	Body      string     `json:"body" xml:"body" text:"Body"`
	MessageId string     `json:"messageId" xml:"messageid" text:"Message ID"`
}

func Connect(server, username, password string) Inbox {
	// Connect to server
	c, err := client.DialTLS(server, nil)
	if err != nil {
		log.Fatal(err)
	}

	// Login
	if err := c.Login(username, password); err != nil {
		log.Fatal(err)
	}

	return Inbox{
		Threads: []Thread{},
		Client:  c,
	}
}

func (i *Inbox) GetMessages(inbox string) {
	mbox, _ := i.Client.Select(inbox, false)
	from := uint32(1)
	to := mbox.Messages

	seqset := new(imap.SeqSet)
	seqset.AddRange(from, to)

	messages := make(chan *imap.Message, 10)
	done := make(chan error, 1)
	go func() {
		done <- i.Client.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchItem("BODY.PEEK[]")}, messages)
	}()

	// Initialize a map to store messages by their In-Reply-To for efficient parent-child linking
	messageMap := make(map[string]*Message)

	for msg := range messages {
		tags := parseTags(msg.Envelope.Subject)
		if len(tags) > 0 {
			m := Message{
				Children: []*Message{},
			}

			holder := ""
			for _, bodyPart := range msg.Body {
				if bodyPart != nil {
					b, _ := io.ReadAll(bodyPart)
					holder += string(b)
				}
			}
			msgReader, _ := mail.ReadMessage(strings.NewReader(holder))
			body, _ := io.ReadAll(msgReader.Body)

			decoder := quotedprintable.NewReader(strings.NewReader(string(body)))

			decoded, _ := io.ReadAll(decoder)
			m.Body = string(decoded)
			m.Tag = tags[0]
			m.Subject = parseSubject(msg.Envelope.Subject)
			m.InReplyTo = msg.Envelope.InReplyTo
			var to, from, cc, bcc string
			for _, v := range msg.Envelope.To {
				to += ", "+v.AtDomainList
			}
			for _, v := range msg.Envelope.From {
				from += ", "+v.AtDomainList
			}
			for _, v := range msg.Envelope.Cc {
				cc += ", "+v.AtDomainList
			}
			for _, v := range msg.Envelope.Bcc {
				bcc += ", "+v.AtDomainList
			}
			m.To = to
			m.From = from
			m.Cc = cc
			m.Bcc = bcc
			m.InReplyTo = msg.Envelope.InReplyTo

			// Store the message in the map using its Message-ID as the key
			messageID := msg.Envelope.MessageId
			m.MessageId = messageID[1:strings.Index(messageID,"@")]
			messageMap[messageID] = &m
		}
	}

	// Link parent and child messages
	for _, msg := range messageMap {
		if msg.InReplyTo != "" { // Only process root-level messages initially
			if parentMsg, ok := messageMap[msg.InReplyTo]; ok {
				parentMsg.Children = append(parentMsg.Children, msg)
			}
		}
	}

	// Create threads from root-level messages
	for _, v := range messageMap {
		if v.InReplyTo == "" {
			thread := Thread{
				Tag: v.Tag,
				Root: *v, // Dereference here to avoid storing a pointer in the Thread root
				Subject: v.Subject,
				ThreadId: v.MessageId,
			}
			i.Threads = append(i.Threads, thread)
		}
	}
}

func parseTags(subject string) []string {
	tags := []string{}
	currentTag := ""
	record := false

	for _, v := range subject {
		if v == ']' && record {
			record = false
			tags = append(tags, currentTag)
			currentTag = ""
		}
		if record {
			currentTag += string(v)
		}
		if v == '[' && !record {
			record = true
		}

	}
	return tags
}

func parseSubject(subject string) string {
	var title string

	for i := len(subject) - 1; i >= 0; i-- {
		if subject[i] == ']' {
			break
		} else {
			title = string(subject[i]) + title
		}
	}
	return strings.TrimSpace(title)
}