package mailstore import "strings" // FilterAction is the outcome of evaluating a mailbox's filter rules against one // incoming message. type FilterAction struct { Folder string // non-empty: store here instead of INBOX MarkRead bool Drop bool // don't store at all } // ApplyRules evaluates a mailbox's filter rules in priority order and returns the // first match's action (zero value if none match, meaning "store in INBOX, unread"). // headers should have "from"/"to"/"subject" keys — rules run at delivery time, before // the message is encrypted and stored, so real header values are available, not just // the plaintext cache columns used for fast IMAP listing. func (s *Store) ApplyRules(mailboxID int64, headers map[string]string) (FilterAction, error) { rules, err := s.DB.ListRulesForMailbox(mailboxID) if err != nil { return FilterAction{}, err } for _, r := range rules { if !r.IsActive { continue } if !matchCondition(r.ConditionOp, headers[r.ConditionField], r.ConditionValue) { continue } switch r.Action { case "move_to_folder": return FilterAction{Folder: r.ActionValue}, nil case "delete": return FilterAction{Drop: true}, nil case "mark_read": return FilterAction{MarkRead: true}, nil } } return FilterAction{}, nil } func matchCondition(op, value, target string) bool { value = strings.ToLower(value) target = strings.ToLower(target) switch op { case "contains": return strings.Contains(value, target) case "equals": return value == target case "starts_with": return strings.HasPrefix(value, target) } return false }