imap.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package idavollr
  2. import (
  3. "io"
  4. "log"
  5. "mime"
  6. "mime/quotedprintable"
  7. "strings"
  8. "apiote.xyz/p/asgard/himinbjorg"
  9. "apiote.xyz/p/asgard/jotunheim"
  10. "github.com/emersion/go-imap"
  11. "github.com/emersion/go-imap-move"
  12. "github.com/emersion/go-imap/client"
  13. "github.com/emersion/go-sasl"
  14. "github.com/emersion/go-smtp"
  15. )
  16. func SendRepeatedQuarantine(address *imap.Address, lock himinbjorg.Lock) {
  17. // todo
  18. log.Printf("sending repeated quarantine to %s from %+v\n", address.Address(), lock)
  19. }
  20. func SendQuarantine(address *imap.Address) {
  21. // todo
  22. log.Printf("sending quarantine to %s\n", address.Address())
  23. }
  24. func MoveMsg(c *client.Client, msg *imap.Message, dest string) error {
  25. log.Printf("moving %v : %s from %s to %s\n", msg.Envelope.Date, msg.Envelope.Subject, msg.Envelope.From[0].Address(), dest)
  26. moveClient := move.NewClient(c)
  27. seqSet := new(imap.SeqSet)
  28. seqSet.AddNum(msg.Uid)
  29. return moveClient.UidMoveWithFallback(seqSet, dest)
  30. }
  31. func MoveMultiple(c *client.Client, seqSet *imap.SeqSet, dest string) error {
  32. moveClient := move.NewClient(c)
  33. if !seqSet.Empty() {
  34. log.Println("moving multiple to " + dest)
  35. err := moveClient.UidMoveWithFallback(seqSet, dest)
  36. return err
  37. }
  38. return nil
  39. }
  40. func MoveFromQuarantine(c *client.Client, mbox *imap.MailboxStatus, address, dest string) error {
  41. log.Printf("moving %s from quarantine to %s\n", address, dest)
  42. moveClient := move.NewClient(c)
  43. from := uint32(1)
  44. to := mbox.Messages
  45. allMessagesSet := new(imap.SeqSet)
  46. allMessagesSet.AddRange(from, to)
  47. var err error = nil
  48. messages := make(chan *imap.Message, 10)
  49. done := make(chan error, 1)
  50. go func() {
  51. done <- c.Fetch(allMessagesSet, []imap.FetchItem{imap.FetchEnvelope, imap.FetchUid}, messages)
  52. }()
  53. moveSet := new(imap.SeqSet)
  54. for msg := range messages {
  55. sender := msg.Envelope.From[0]
  56. if sender.Address() == address {
  57. moveSet.AddNum(msg.Uid)
  58. }
  59. }
  60. if !moveSet.Empty() {
  61. err = moveClient.UidMoveWithFallback(moveSet, dest)
  62. }
  63. if err := <-done; err != nil {
  64. return err
  65. }
  66. return err
  67. }
  68. func ForwardMessage(config jotunheim.Config, category, messageID, inReplyTo, subject string, body []byte, recipients []string, sender *imap.Address) error {
  69. // todo reformat, errors, &c.
  70. msg := "To: " + strings.Join(recipients, ", ") + "\r\n" +
  71. "From: " + himinbjorg.MakeNameAddress(sender, true) + "\r\n" +
  72. "Message-ID: " + messageID + "\r\n" +
  73. "Subject: " + mime.QEncoding.Encode("utf-8", subject) + "\r\n"
  74. if inReplyTo != "" {
  75. msg = msg + "In-Reply-To: " + inReplyTo + "\r\n"
  76. }
  77. msg += "Reply-To: " + mime.QEncoding.Encode("utf-8", strings.Replace(config.Mimir.RecipientTemplate, "[:]", category, 1)) + "\r\n" +
  78. "Content-Type: text/plain; charset=utf-8\r\n" +
  79. "Content-Transfer-Encoding: quoted-printable\r\n" +
  80. "\r\n"
  81. msgReader := strings.NewReader(msg)
  82. auth := sasl.NewPlainClient("", config.Mimir.ImapUsername, config.Mimir.ImapPassword)
  83. c, err := smtp.DialTLS(config.Mimir.SmtpAddress, nil)
  84. if err != nil {
  85. log.Fatal(err)
  86. }
  87. if err = c.Auth(auth); err != nil {
  88. log.Fatal(err)
  89. }
  90. if err := c.Mail(config.Mimir.SmtpSender, nil); err != nil {
  91. log.Fatal(err)
  92. }
  93. for _, recipient := range recipients {
  94. if err := c.Rcpt(recipient, nil); err != nil {
  95. log.Fatal(err)
  96. }
  97. }
  98. wc, err := c.Data()
  99. if err != nil {
  100. log.Fatal(err)
  101. }
  102. _, err = io.Copy(wc, msgReader)
  103. qpWriter := quotedprintable.NewWriter(wc)
  104. _, err = qpWriter.Write(body)
  105. _, err = qpWriter.Write([]byte("\r\n"))
  106. if err != nil {
  107. log.Fatal(err)
  108. }
  109. err = wc.Close()
  110. if err != nil {
  111. log.Fatal(err)
  112. }
  113. err = c.Quit()
  114. if err != nil {
  115. log.Fatal(err)
  116. }
  117. return nil
  118. }
  119. func RemoveMessage(c *client.Client, msgUid uint32, mailbox string) error {
  120. _, err := c.Select(mailbox, false)
  121. if err != nil {
  122. return err
  123. }
  124. seqset := new(imap.SeqSet)
  125. seqset.AddNum(msgUid)
  126. item := imap.FormatFlagsOp(imap.AddFlags, true)
  127. flags := []interface{}{imap.DeletedFlag}
  128. return c.UidStore(seqset, item, flags, nil)
  129. }