OpenSMTPD filter for flatfile mail queue archiving
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

153 行
3.2KB

  1. //
  2. // Copyright (c) 2019 Björn Kalkbrenner <terminar@cyberphoria.org>
  3. //
  4. // Permission to use, copy, modify, and distribute this software for any
  5. // purpose with or without fee is hereby granted, provided that the above
  6. // copyright notice and this permission notice appear in all copies.
  7. //
  8. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. //
  16. package main
  17. import (
  18. "os"
  19. "bufio"
  20. "path"
  21. "time"
  22. "strconv"
  23. "errors"
  24. )
  25. var archiveStoragePath = ""
  26. var archiveStorageFlat = false
  27. type archiveStorage struct {
  28. dataFile *os.File
  29. data *bufio.Writer
  30. metaFile *os.File
  31. meta *bufio.Writer
  32. }
  33. func careDirectory(dirName string) error {
  34. src, err := os.Stat(dirName)
  35. if os.IsNotExist(err) {
  36. errDir := os.MkdirAll(dirName, 0755)
  37. if errDir != nil {
  38. return errDir
  39. }
  40. return nil
  41. }
  42. if src.Mode().IsRegular() {
  43. return errors.New("already exist as a file!")
  44. }
  45. return nil
  46. }
  47. func getArchiveFolder() (string, error) {
  48. if archiveStoragePath == "" {
  49. return "", errors.New("archive storage path not set")
  50. }
  51. if archiveStorageFlat {
  52. return archiveStoragePath, nil
  53. } else {
  54. return path.Join(archiveStoragePath,time.Now().Format("2006-01"),time.Now().Format("02")), nil
  55. }
  56. }
  57. func (a *archiveStorage) Open(fname string) error {
  58. var err error
  59. var t = time.Now()
  60. var fFolder string
  61. if fFolder, err = getArchiveFolder(); err != nil {
  62. return err
  63. }
  64. fName := fname + "." + strconv.FormatInt(t.Unix(), 10)
  65. if err := careDirectory(fFolder); err != nil {
  66. return err
  67. }
  68. fPath := path.Join(fFolder,fName)
  69. if a.dataFile, err = os.Create(fPath); err != nil {
  70. return err
  71. }
  72. a.data = bufio.NewWriter(a.dataFile)
  73. if a.metaFile, err = os.Create(fPath + ".meta"); err != nil {
  74. return err
  75. }
  76. a.meta = bufio.NewWriter(a.metaFile)
  77. a.Meta("DATAFILE=" + fName)
  78. a.Meta("TIME=" + t.String())
  79. return nil
  80. }
  81. func (a *archiveStorage) Close() error {
  82. if a.data != nil {
  83. if err := a.data.Flush(); err != nil {
  84. return err
  85. }
  86. }
  87. if a.dataFile != nil {
  88. if err := a.dataFile.Close(); err != nil {
  89. return err
  90. }
  91. }
  92. if a.meta != nil {
  93. if err := a.meta.Flush(); err != nil {
  94. return err
  95. }
  96. }
  97. if a.metaFile != nil {
  98. if err := a.metaFile.Close(); err != nil {
  99. return err
  100. }
  101. }
  102. return nil
  103. }
  104. func (a *archiveStorage) Data(text string) {
  105. if a.data != nil {
  106. a.data.WriteString(text + "\n")
  107. }
  108. }
  109. func (a *archiveStorage) Meta(text string) {
  110. if a.meta != nil {
  111. a.meta.WriteString(text + "\n")
  112. }
  113. }
  114. func (a *archiveStorage) Flush() error {
  115. if a.data != nil {
  116. if err := a.data.Flush(); err != nil {
  117. return err
  118. }
  119. }
  120. if a.meta != nil {
  121. if err := a.meta.Flush(); err != nil {
  122. return err
  123. }
  124. }
  125. return nil
  126. }