This repository has been archived by the owner on Feb 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
maildir.go
122 lines (106 loc) · 2.63 KB
/
maildir.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
package mailz // import "github.com/mndrix/mailz"
import (
"fmt"
"io"
"os"
"path/filepath"
"github.com/pkg/errors"
)
// Maildir represents a mail storage location in maildir format or a
// directory containing other maildirs.
type Maildir struct {
// Path is an OS-specific path (see "path/filepath") to this
// maildir's location in the file system.
Path string
// HasMessages is true if this maildir contains messages directly.
// Otherwise, it's a container for other maildirs.
HasMessages bool
// Messages contains all the messages within this maildir.
//Messages []Message
// Folders contains all the subfolders within this maildir.
Folders []*Maildir
}
var errNoMessages = errors.New("No messages in folder")
// Skim reads through a maildir's directory structure to find folders
// and messages.
func (md *Maildir) Skim() error {
// make sure path exists ...
stat, err := os.Stat(md.Path)
if err != nil {
return errors.Wrap(err, "stat maildir")
}
// ... and is a directory
if !stat.IsDir() {
return fmt.Errorf("%s is not a directory", md.Path)
}
// look for subfolders or messages
dir, err := os.Open(md.Path)
if err != nil {
return errors.Wrap(err, "opening maildir")
}
hasCur, hasNew, hasTmp := false, false, false
for {
entries, err := dir.Readdir(2) // TODO increase after testing
if err == io.EOF {
break
}
if err != nil {
return errors.Wrap(err, "reading maildir entries")
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
switch entry.Name() {
case "cur":
hasCur = true
case "new":
hasNew = true
case "tmp":
hasTmp = true
default:
folder := &Maildir{}
folder.Path = filepath.Join(md.Path, entry.Name())
md.Folders = append(md.Folders, folder)
}
}
}
md.HasMessages = hasCur && hasNew && hasTmp
// done reading this directory
err = dir.Close()
if err != nil {
return errors.Wrap(err, "closing maildir")
}
dir = nil
// skim the sub-folders
trueFolders := make([]*Maildir, 0, len(md.Folders))
for i, folder := range md.Folders {
err := folder.Skim()
switch err {
case nil:
trueFolders = append(trueFolders, md.Folders[i])
case errNoMessages:
// ignore this folder
default:
return errors.Wrap(err, "skimming subfolders")
}
}
md.Folders = trueFolders
if !md.HasMessages && len(trueFolders) == 0 {
return errNoMessages
}
return nil
}
// HasAnyMessages returns true if this maildir or any of its folders
// has a message.
func (md *Maildir) HasAnyMessages() bool {
if md.HasMessages {
return true
}
for _, folder := range md.Folders {
if folder.HasAnyMessages() {
return true
}
}
return false
}