info.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package imaputils
  2. import (
  3. "fmt"
  4. "git.sr.ht/~blallo/papero/config"
  5. "github.com/emersion/go-imap"
  6. )
  7. func ListMailboxes(conf *config.AccountData, debug bool) ([]*imap.MailboxInfo, error) {
  8. var mailboxes []*imap.MailboxInfo
  9. conn := NewConnection(conf)
  10. err := conn.Start(debug)
  11. if err != nil {
  12. return mailboxes, err
  13. }
  14. defer conn.Close()
  15. mboxChan := make(chan *imap.MailboxInfo, 10)
  16. done := make(chan error, 1)
  17. go func() {
  18. done <- conn.client.List("", "*", mboxChan)
  19. }()
  20. for m := range mboxChan {
  21. mailboxes = append(mailboxes, m)
  22. }
  23. if err := <-done; err != nil {
  24. return mailboxes, err
  25. }
  26. return mailboxes, nil
  27. }
  28. type ListMessagesOpts struct {
  29. Mailbox string
  30. Limit uint32
  31. }
  32. func ListMessages(conf *config.AccountData, opts *ListMessagesOpts, debug bool) ([]*imap.Message, error) {
  33. var messages []*imap.Message
  34. conn := NewConnection(conf)
  35. err := conn.Start(debug)
  36. if err != nil {
  37. return messages, err
  38. }
  39. defer conn.Close()
  40. mbox, err := conn.client.Select(opts.Mailbox, true)
  41. if err != nil {
  42. return messages, err
  43. }
  44. return getMessages(mbox, conn, opts.Limit)
  45. }
  46. func getMessages(mbox *imap.MailboxStatus, conn *IMAPConnection, limit uint32) ([]*imap.Message, error) {
  47. var start uint32
  48. var msgs []*imap.Message
  49. seqset := new(imap.SeqSet)
  50. messages := make(chan *imap.Message, 10)
  51. done := make(chan error, 1)
  52. switch {
  53. case limit == 0:
  54. start = 1
  55. case mbox.Messages > limit:
  56. start = mbox.Messages - limit + 1
  57. default:
  58. start = 1
  59. }
  60. seqset.AddRange(start, mbox.Messages)
  61. go func() {
  62. done <- conn.client.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags}, messages)
  63. }()
  64. for msg := range messages {
  65. msgs = append(msgs, msg)
  66. }
  67. if err := <-done; err != nil {
  68. return []*imap.Message{}, err
  69. }
  70. return msgs, nil
  71. }
  72. type FetchOpts struct {
  73. Mailbox string
  74. IdList []uint32
  75. WithHeaders bool
  76. WithBody bool
  77. WithFlags bool
  78. Peek bool
  79. }
  80. func (o *FetchOpts) String() string {
  81. return fmt.Sprintf(
  82. "FetchOpts{Mailbox: %s, IdList: %v, WithHeaders: %t, WithBody: %t, Peek: %t}",
  83. o.Mailbox,
  84. o.IdList,
  85. o.WithHeaders,
  86. o.WithBody,
  87. o.Peek,
  88. )
  89. }
  90. func FetchMessages(conf *config.AccountData, opts *FetchOpts, debug bool) ([]*imap.Message, error) {
  91. var messages []*imap.Message
  92. conn := NewConnection(conf)
  93. err := conn.Start(debug)
  94. if err != nil {
  95. return messages, err
  96. }
  97. defer conn.Close()
  98. mbox, err := conn.client.Select(opts.Mailbox, true)
  99. if err != nil {
  100. return messages, err
  101. }
  102. return fetchMessage(mbox, conn, opts)
  103. }
  104. func fetchMessage(mbox *imap.MailboxStatus, conn *IMAPConnection, opts *FetchOpts) ([]*imap.Message, error) {
  105. var messageAcc []*imap.Message
  106. messages := make(chan *imap.Message, len(opts.IdList))
  107. done := make(chan error, 1)
  108. seqset := new(imap.SeqSet)
  109. for _, id := range opts.IdList {
  110. seqset.AddNum(id)
  111. }
  112. var items []imap.FetchItem
  113. if opts.WithHeaders {
  114. section := &imap.BodySectionName{Peek: opts.Peek, BodyPartName: imap.BodyPartName{Specifier: imap.HeaderSpecifier}}
  115. items = append(items, section.FetchItem())
  116. }
  117. items = append(items, imap.FetchEnvelope)
  118. if opts.WithBody {
  119. section := &imap.BodySectionName{Peek: opts.Peek, BodyPartName: imap.BodyPartName{Specifier: imap.TextSpecifier}}
  120. items = append(items, section.FetchItem())
  121. }
  122. if opts.WithFlags {
  123. items = append(items, imap.FetchFlags)
  124. }
  125. go func() {
  126. done <- conn.client.Fetch(seqset, items, messages)
  127. }()
  128. for m := range messages {
  129. messageAcc = append(messageAcc, m)
  130. }
  131. if err := <-done; err != nil {
  132. return []*imap.Message{}, err
  133. }
  134. return messageAcc, nil
  135. }