|
@@ -0,0 +1,125 @@
|
|
|
+package fs
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type Flag string
|
|
|
+
|
|
|
+func cat(f []Flag) string {
|
|
|
+ var list []string
|
|
|
+ for _, el := range f {
|
|
|
+ list = append(list, string(el))
|
|
|
+ }
|
|
|
+ return strings.Join(list, "")
|
|
|
+}
|
|
|
+
|
|
|
+const (
|
|
|
+ Seen Flag = "S"
|
|
|
+ Answered = "R"
|
|
|
+ Flagged = "F"
|
|
|
+ Deleted = "T"
|
|
|
+ Draft = "D"
|
|
|
+)
|
|
|
+
|
|
|
+// MailFile holds the information needed to format the name of the file
|
|
|
+// containing a single email. The format is:
|
|
|
+// `<%d_%d.%d.%s>,U=<%d>,FMD5=<%s>:2,<FLAGS>`
|
|
|
+// (logical groups being enclosed by angle brackets) where:
|
|
|
+// - `<%d_%d.%d.%s>` is the concatenation of:
|
|
|
+// * system unix timestamp of arrival time of the message
|
|
|
+// * a progressive number to distinguish messages arrived at once
|
|
|
+// * pid of the current process
|
|
|
+// * hostname of the local machine
|
|
|
+// - `,U=<%d>` holds the UID of the message as decided by the server
|
|
|
+// - `,FMD5=<%s>:2` holds the md5sum of the name of the current mailbox
|
|
|
+// - `,<FLAGS>` carries the flags active on the message
|
|
|
+type MailFile struct {
|
|
|
+ timestamp time.Time
|
|
|
+ progressive int
|
|
|
+ pid int
|
|
|
+ hostname string
|
|
|
+ uid int
|
|
|
+ md5 string
|
|
|
+ flags []Flag
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MailFile) SetUid(uid int) {
|
|
|
+ m.uid = uid
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MailFile) SetMd5(md5 string) {
|
|
|
+ m.md5 = md5
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MailFile) SetFlags(flags []Flag) {
|
|
|
+ m.flags = flags
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MailFile) String() string {
|
|
|
+ return fmt.Sprintf(
|
|
|
+ "%d_%d.%d.%s,U=%d,FMD5=%s:2,%s",
|
|
|
+ m.timestamp.Unix(),
|
|
|
+ m.progressive,
|
|
|
+ m.pid,
|
|
|
+ m.hostname,
|
|
|
+ m.uid,
|
|
|
+ m.md5,
|
|
|
+ cat(m.flags),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+type MailFileRequest struct {
|
|
|
+ respCh chan MailFile
|
|
|
+}
|
|
|
+
|
|
|
+func NewMailFileRequest() MailFileRequest {
|
|
|
+ ch := make(chan MailFile)
|
|
|
+ return MailFileRequest{respCh: ch}
|
|
|
+}
|
|
|
+
|
|
|
+func (r MailFileRequest) Response() MailFile {
|
|
|
+ return <-r.respCh
|
|
|
+}
|
|
|
+
|
|
|
+func NewOracle() chan MailFileRequest {
|
|
|
+ r := realClock{}
|
|
|
+ return newOracle(r)
|
|
|
+}
|
|
|
+
|
|
|
+func newOracle(c clock) chan MailFileRequest {
|
|
|
+ reqCh := make(chan MailFileRequest, 10)
|
|
|
+ go spawnOracle(reqCh, c)
|
|
|
+ return reqCh
|
|
|
+}
|
|
|
+
|
|
|
+func spawnOracle(reqCh <-chan MailFileRequest, c clock) {
|
|
|
+ count := 0
|
|
|
+ C := c.Ticker().getC()
|
|
|
+ pid := os.Getpid()
|
|
|
+ hostname, err := os.Hostname()
|
|
|
+ if err != nil {
|
|
|
+ hostname = "MISSING"
|
|
|
+ }
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-C:
|
|
|
+ count = 0
|
|
|
+ case req := <-reqCh:
|
|
|
+ req.respCh <- MailFile{
|
|
|
+ timestamp: c.Now(),
|
|
|
+ progressive: count,
|
|
|
+ pid: pid,
|
|
|
+ hostname: hostname,
|
|
|
+ }
|
|
|
+ count += 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type MailDir struct {
|
|
|
+ basePath string
|
|
|
+}
|