mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2024-12-18 10:27:16 +00:00
200 lines
4.5 KiB
Go
200 lines
4.5 KiB
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/mailhog/data"
|
||
|
)
|
||
|
|
||
|
// InMemory is an in memory storage backend
|
||
|
type InMemory struct {
|
||
|
MessageIDIndex map[string]int
|
||
|
Messages []*data.Message
|
||
|
mu sync.Mutex
|
||
|
}
|
||
|
|
||
|
// CreateInMemory creates a new in memory storage backend
|
||
|
func CreateInMemory() *InMemory {
|
||
|
return &InMemory{
|
||
|
MessageIDIndex: make(map[string]int),
|
||
|
Messages: make([]*data.Message, 0),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Store stores a message and returns its storage ID
|
||
|
func (memory *InMemory) Store(m *data.Message) (string, error) {
|
||
|
memory.mu.Lock()
|
||
|
defer memory.mu.Unlock()
|
||
|
memory.Messages = append(memory.Messages, m)
|
||
|
memory.MessageIDIndex[string(m.ID)] = len(memory.Messages) - 1
|
||
|
return string(m.ID), nil
|
||
|
}
|
||
|
|
||
|
// Count returns the number of stored messages
|
||
|
func (memory *InMemory) Count() int {
|
||
|
return len(memory.Messages)
|
||
|
}
|
||
|
|
||
|
// Search finds messages matching the query
|
||
|
func (memory *InMemory) Search(kind, query string, start, limit int) (*data.Messages, int, error) {
|
||
|
// FIXME needs optimising, or replacing with a proper db!
|
||
|
query = strings.ToLower(query)
|
||
|
var filteredMessages = make([]*data.Message, 0)
|
||
|
for _, m := range memory.Messages {
|
||
|
doAppend := false
|
||
|
|
||
|
switch kind {
|
||
|
case "to":
|
||
|
for _, to := range m.To {
|
||
|
if strings.Contains(strings.ToLower(to.Mailbox+"@"+to.Domain), query) {
|
||
|
doAppend = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if !doAppend {
|
||
|
if hdr, ok := m.Content.Headers["To"]; ok {
|
||
|
for _, to := range hdr {
|
||
|
if strings.Contains(strings.ToLower(to), query) {
|
||
|
doAppend = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
case "from":
|
||
|
if strings.Contains(strings.ToLower(m.From.Mailbox+"@"+m.From.Domain), query) {
|
||
|
doAppend = true
|
||
|
}
|
||
|
if !doAppend {
|
||
|
if hdr, ok := m.Content.Headers["From"]; ok {
|
||
|
for _, from := range hdr {
|
||
|
if strings.Contains(strings.ToLower(from), query) {
|
||
|
doAppend = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
case "containing":
|
||
|
if strings.Contains(strings.ToLower(m.Content.Body), query) {
|
||
|
doAppend = true
|
||
|
}
|
||
|
if !doAppend {
|
||
|
for _, hdr := range m.Content.Headers {
|
||
|
for _, v := range hdr {
|
||
|
if strings.Contains(strings.ToLower(v), query) {
|
||
|
doAppend = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if doAppend {
|
||
|
filteredMessages = append(filteredMessages, m)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var messages = make([]data.Message, 0)
|
||
|
|
||
|
if len(filteredMessages) == 0 || start > len(filteredMessages) {
|
||
|
msgs := data.Messages(messages)
|
||
|
return &msgs, 0, nil
|
||
|
}
|
||
|
|
||
|
if start+limit > len(filteredMessages) {
|
||
|
limit = len(filteredMessages) - start
|
||
|
}
|
||
|
|
||
|
start = len(filteredMessages) - start - 1
|
||
|
end := start - limit
|
||
|
|
||
|
if start < 0 {
|
||
|
start = 0
|
||
|
}
|
||
|
if end < -1 {
|
||
|
end = -1
|
||
|
}
|
||
|
|
||
|
for i := start; i > end; i-- {
|
||
|
//for _, m := range memory.MessageIndex[start:end] {
|
||
|
messages = append(messages, *filteredMessages[i])
|
||
|
}
|
||
|
|
||
|
msgs := data.Messages(messages)
|
||
|
return &msgs, len(filteredMessages), nil
|
||
|
}
|
||
|
|
||
|
// List lists stored messages by index
|
||
|
func (memory *InMemory) List(start int, limit int) (*data.Messages, error) {
|
||
|
var messages = make([]data.Message, 0)
|
||
|
|
||
|
if len(memory.Messages) == 0 || start > len(memory.Messages) {
|
||
|
msgs := data.Messages(messages)
|
||
|
return &msgs, nil
|
||
|
}
|
||
|
|
||
|
if start+limit > len(memory.Messages) {
|
||
|
limit = len(memory.Messages) - start
|
||
|
}
|
||
|
|
||
|
start = len(memory.Messages) - start - 1
|
||
|
end := start - limit
|
||
|
|
||
|
if start < 0 {
|
||
|
start = 0
|
||
|
}
|
||
|
if end < -1 {
|
||
|
end = -1
|
||
|
}
|
||
|
|
||
|
for i := start; i > end; i-- {
|
||
|
//for _, m := range memory.MessageIndex[start:end] {
|
||
|
messages = append(messages, *memory.Messages[i])
|
||
|
}
|
||
|
|
||
|
msgs := data.Messages(messages)
|
||
|
return &msgs, nil
|
||
|
}
|
||
|
|
||
|
// DeleteOne deletes an individual message by storage ID
|
||
|
func (memory *InMemory) DeleteOne(id string) error {
|
||
|
memory.mu.Lock()
|
||
|
defer memory.mu.Unlock()
|
||
|
|
||
|
var index int
|
||
|
var ok bool
|
||
|
|
||
|
if index, ok = memory.MessageIDIndex[id]; !ok && true {
|
||
|
return errors.New("message not found")
|
||
|
}
|
||
|
|
||
|
delete(memory.MessageIDIndex, id)
|
||
|
for k, v := range memory.MessageIDIndex {
|
||
|
if v > index {
|
||
|
memory.MessageIDIndex[k] = v - 1
|
||
|
}
|
||
|
}
|
||
|
memory.Messages = append(memory.Messages[:index], memory.Messages[index+1:]...)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// DeleteAll deletes all in memory messages
|
||
|
func (memory *InMemory) DeleteAll() error {
|
||
|
memory.mu.Lock()
|
||
|
defer memory.mu.Unlock()
|
||
|
memory.Messages = make([]*data.Message, 0)
|
||
|
memory.MessageIDIndex = make(map[string]int)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Load returns an individual message by storage ID
|
||
|
func (memory *InMemory) Load(id string) (*data.Message, error) {
|
||
|
if idx, ok := memory.MessageIDIndex[id]; ok {
|
||
|
return memory.Messages[idx], nil
|
||
|
}
|
||
|
return nil, nil
|
||
|
}
|