maildir.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package fs
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "time"
  7. )
  8. type Flag string
  9. func cat(f []Flag) string {
  10. var list []string
  11. for _, el := range f {
  12. list = append(list, string(el))
  13. }
  14. return strings.Join(list, "")
  15. }
  16. const (
  17. Seen Flag = "S"
  18. Answered = "R"
  19. Flagged = "F"
  20. Deleted = "T"
  21. Draft = "D"
  22. )
  23. // MailFile holds the information needed to format the name of the file
  24. // containing a single email. The format is:
  25. // `<%d_%d.%d.%s>,U=<%d>,FMD5=<%s>:2,<FLAGS>`
  26. // (logical groups being enclosed by angle brackets) where:
  27. // - `<%d_%d.%d.%s>` is the concatenation of:
  28. // * system unix timestamp of arrival time of the message
  29. // * a progressive number to distinguish messages arrived at once
  30. // * pid of the current process
  31. // * hostname of the local machine
  32. // - `,U=<%d>` holds the UID of the message as decided by the server
  33. // - `,FMD5=<%s>:2` holds the md5sum of the name of the current mailbox
  34. // - `,<FLAGS>` carries the flags active on the message
  35. type MailFile struct {
  36. timestamp time.Time
  37. progressive int
  38. pid int
  39. hostname string
  40. uid int
  41. md5 string
  42. flags []Flag
  43. }
  44. func (m *MailFile) SetUid(uid int) {
  45. m.uid = uid
  46. }
  47. func (m *MailFile) SetMd5(md5 string) {
  48. m.md5 = md5
  49. }
  50. func (m *MailFile) SetFlags(flags []Flag) {
  51. m.flags = flags
  52. }
  53. func (m *MailFile) String() string {
  54. return fmt.Sprintf(
  55. "%d_%d.%d.%s,U=%d,FMD5=%s:2,%s",
  56. m.timestamp.Unix(),
  57. m.progressive,
  58. m.pid,
  59. m.hostname,
  60. m.uid,
  61. m.md5,
  62. cat(m.flags),
  63. )
  64. }
  65. type MailFileRequest struct {
  66. respCh chan MailFile
  67. }
  68. func NewMailFileRequest() MailFileRequest {
  69. ch := make(chan MailFile)
  70. return MailFileRequest{respCh: ch}
  71. }
  72. func (r MailFileRequest) Response() MailFile {
  73. return <-r.respCh
  74. }
  75. func NewOracle() chan MailFileRequest {
  76. r := realClock{}
  77. return newOracle(r)
  78. }
  79. func newOracle(c clock) chan MailFileRequest {
  80. reqCh := make(chan MailFileRequest, 10)
  81. go spawnOracle(reqCh, c)
  82. return reqCh
  83. }
  84. func spawnOracle(reqCh <-chan MailFileRequest, c clock) {
  85. count := 0
  86. C := c.Ticker().getC()
  87. pid := os.Getpid()
  88. hostname, err := os.Hostname()
  89. if err != nil {
  90. hostname = "MISSING"
  91. }
  92. for {
  93. select {
  94. case <-C:
  95. count = 0
  96. case req := <-reqCh:
  97. req.respCh <- MailFile{
  98. timestamp: c.Now(),
  99. progressive: count,
  100. pid: pid,
  101. hostname: hostname,
  102. }
  103. count += 1
  104. }
  105. }
  106. }
  107. type MailDir struct {
  108. basePath string
  109. }