This repository has been archived by the owner on Nov 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
mailbox.go
135 lines (116 loc) · 3.53 KB
/
mailbox.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2019 Martin Pritchard
//
// This file is part of Pinbox.
//
// Pinbox is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pinbox is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pinbox. If not, see <https://www.gnu.org/licenses/>.
package pinbox
import (
"errors"
"fmt"
"log"
"sort"
"time"
)
// The Mailbox interface acts as a wrapper for all email actions to abstract any
// direct email access from the business logic of the Pinbox API transport.
type Mailbox interface {
Labels() ([]Label, error)
ReadMessage(id string) (MessageContent, error)
Search(query string) ([]Thread, error)
}
// Inbox returns all email messages that match the configured 'Inbox' whilst
// grouping together any messages that match the labels configured in the 'Bundle' list.
//
// Returns a mixed list of Thread and Bundle objects.
// The list is returned in reverse chronological order.
func Inbox(mailbox Mailbox, config Config) ([]interface{}, error) {
inboxLabel := config.Inbox
queryString := "tag:" + inboxLabel
for _, label := range config.Bundle {
queryString += " and not tag:" + label
}
threads, err := mailbox.Search(queryString)
if err != nil {
return nil, errors.New("Search failed: " + err.Error())
}
bundles := make(map[string][]*Bundle)
for _, label := range config.Bundle {
res, err := mailbox.Search("tag:" + inboxLabel + " and tag:" + label)
if err != nil {
log.Println(fmt.Sprintf("Error with bundle '%s': %s", label, err))
continue
}
bundled := make([]Thread, 0)
var latestDate int64
for _, thread := range res {
date := thread.NewestDate
if date > latestDate {
latestDate = date
}
bundled = append(bundled, thread)
}
if len(bundled) > 0 {
latest := time.Unix(latestDate, 0)
month := fmt.Sprintf("%d %d", latest.Month(), latest.Year())
bundles[month] = append(
bundles[month],
&Bundle{
ID: label,
Type: "bundle",
Date: latestDate,
Threads: bundled,
})
}
}
for key := range bundles {
sort.Slice(bundles[key], func(i, j int) bool {
return bundles[key][i].Date > bundles[key][j].Date
})
}
inbox := make([]interface{}, 0)
var prevDate time.Time
for _, thread := range threads {
date := time.Unix(thread.NewestDate, 0)
month := fmt.Sprintf("%d %d", date.Month(), date.Year())
if len(bundles[month]) > 0 {
for _, bundle := range bundles[month] {
bundleDate := bundle.Date
if bundleDate > date.Unix() {
bundle.Type = "bundle"
inbox = append(inbox, bundle)
}
}
}
thread.Type = "thread"
inbox = append(inbox, thread)
prevDate = date
}
// We have already added all top-level threads.
// There may still be bundles that have not been included.
// Flush out any remaining bundles that are older than our last top-level thread.
keys := make([]string, 0)
for key := range bundles {
keys = append(keys, key)
}
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
for _, key := range keys {
for _, bundle := range bundles[key] {
if bundle.Date < prevDate.Unix() {
bundle.Type = "bundle"
inbox = append(inbox, bundle)
}
}
}
return inbox, nil
}