ultisuite-backend/internal/mail/imap/folders.go
R3D347HR4Y cd0a80f5e8 huhu
2026-05-25 13:52:27 +02:00

119 lines
2.8 KiB
Go

package imap
import (
"strings"
"github.com/emersion/go-imap/v2"
)
var folderDisplayNames = map[string]string{
"inbox": "Inbox",
"sent": "Sent",
"drafts": "Drafts",
"trash": "Trash",
"archive": "Archive",
"spam": "Spam",
}
var folderNameHeuristics = map[string]string{
"inbox": "inbox",
"sent": "sent",
"sent items": "sent",
"sent messages": "sent",
"[gmail]/sent mail": "sent",
"inbox.sent": "sent",
"drafts": "drafts",
"[gmail]/drafts": "drafts",
"trash": "trash",
"deleted": "trash",
"[gmail]/trash": "trash",
"archive": "archive",
"all mail": "archive",
"[gmail]/all mail": "archive",
"junk": "spam",
"spam": "spam",
"[gmail]/spam": "spam",
}
// DetectFolderType classifies an IMAP mailbox for sync using SPECIAL-USE
// attributes when present, otherwise name heuristics. NoSelect mailboxes
// return "" so callers can skip sync.
func DetectFolderType(mailbox string, attrs []imap.MailboxAttr) string {
for _, attr := range attrs {
if attr == imap.MailboxAttrNoSelect {
return ""
}
}
if folderType := folderTypeFromAttrs(attrs); folderType != "" {
return folderType
}
return folderTypeFromName(mailbox)
}
// DisplayName returns a user-facing folder label from the detected type,
// or the last path segment of mailbox when type is custom or unknown.
func DisplayName(mailbox, folderType string) string {
folderType = strings.ToLower(strings.TrimSpace(folderType))
if name, ok := folderDisplayNames[folderType]; ok {
return name
}
return mailboxLeaf(mailbox)
}
func folderTypeFromAttrs(attrs []imap.MailboxAttr) string {
for _, attr := range attrs {
switch attr {
case imap.MailboxAttrSent:
return "sent"
case imap.MailboxAttrDrafts:
return "drafts"
case imap.MailboxAttrTrash:
return "trash"
case imap.MailboxAttrArchive:
return "archive"
case imap.MailboxAttrJunk:
return "spam"
}
}
return ""
}
func folderTypeFromName(mailbox string) string {
full := strings.ToLower(strings.TrimSpace(mailbox))
if folderType, ok := folderNameHeuristics[full]; ok {
return folderType
}
leaf := strings.ToLower(mailboxLeaf(mailbox))
if folderType, ok := folderNameHeuristics[leaf]; ok {
return folderType
}
return "custom"
}
func mailboxLeaf(mailbox string) string {
mailbox = strings.TrimSpace(mailbox)
if mailbox == "" {
return ""
}
leaf := mailbox
for _, sep := range []string{"/", "."} {
if idx := strings.LastIndex(leaf, sep); idx >= 0 && idx < len(leaf)-len(sep) {
leaf = leaf[idx+len(sep):]
}
}
return leaf
}
// FolderDerivedLabels returns Ultimail labels inferred from IMAP mailbox path/name.
func FolderDerivedLabels(mailbox string) []string {
if strings.ToLower(mailboxLeaf(mailbox)) == "important" {
return []string{"important"}
}
return nil
}