main.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package main
  2. import (
  3. "bufio"
  4. "errors"
  5. "flag"
  6. "fmt"
  7. "os"
  8. "strings"
  9. "time"
  10. )
  11. var noVersion = "dev"
  12. var version string
  13. type attachmentList []string
  14. func (a *attachmentList) String() string {
  15. var str string
  16. for _, attachment := range *a {
  17. str += fmt.Sprintf("%s\n", attachment)
  18. }
  19. return str
  20. }
  21. func (a *attachmentList) Set(file string) error {
  22. if _, err := os.Lstat(file); err != nil {
  23. return err
  24. }
  25. if file == "" {
  26. return errors.New("no file provided")
  27. }
  28. *a = append(*a, file)
  29. return nil
  30. }
  31. func readFromConsole(result chan string) {
  32. var text, line string
  33. var err error
  34. counter := 0
  35. reader := bufio.NewReader(os.Stdin)
  36. for counter < 3 {
  37. line, err = reader.ReadString('\n')
  38. if line == "\n" {
  39. counter++
  40. } else {
  41. counter = 0
  42. }
  43. text += fmt.Sprintf("%s\n", line)
  44. }
  45. if err != nil {
  46. Error.F("Error in reading text from console\n%s", err)
  47. os.Exit(1)
  48. }
  49. result <- strings.TrimRight(text, "\n")
  50. return
  51. }
  52. func toList(input string) []string {
  53. var result = []string{}
  54. list := strings.Split(input, ",")
  55. for _, element := range list {
  56. if element != "" {
  57. result = append(result, element)
  58. }
  59. }
  60. return result
  61. }
  62. func initializeConfig(configPath, section string) *Config {
  63. if configPath == "" {
  64. configPath = "/etc/sendmail.toml"
  65. // Ignore non existing config only if `-conf` not used on command line.
  66. if _, err := os.Stat(configPath); os.IsNotExist(err) {
  67. return NewConfig()
  68. }
  69. }
  70. config, err := readConfig(configPath, section)
  71. if err != nil {
  72. if os.IsNotExist(err) {
  73. Error.F("Error in parsing the configuration\n%s", err)
  74. os.Exit(-2)
  75. }
  76. }
  77. Debug.F("---\nConfig from %s\n%s", configPath, *config)
  78. return config
  79. }
  80. func main() {
  81. var err error
  82. var configPath, section, serverAddress, user, password, to, cc, bcc, from, subject, text string
  83. var encryption, dbg, versionFlag, interactive bool
  84. var serverPortAux int
  85. var serverPort int64
  86. var attachments attachmentList
  87. flag.BoolVar(&versionFlag, "version", false, "Prints the version and exits")
  88. flag.StringVar(&configPath, "conf", "", "Path to a config file (defaults to /etc/sendmail.toml)")
  89. flag.StringVar(&section, "section", "default", "Section of the conf to read (defaults to \"default\")")
  90. flag.BoolVar(&dbg, "dbg", false, "Enable debugging output")
  91. flag.BoolVar(&interactive, "interactive", false, "Assume composing mail manually, do not timeout waiting input")
  92. flag.StringVar(&serverAddress, "server-address", "", "The SMTP server address")
  93. flag.IntVar(&serverPortAux, "server-port", 0, "The SMTP server")
  94. flag.BoolVar(&encryption, "force-ssl", false, "Force the use of ssl (defalut: false)")
  95. flag.StringVar(&user, "user", "", "The user to authenticate with to the server")
  96. flag.StringVar(&password, "password", "", "The password to authenticate with to the server")
  97. flag.StringVar(&to, "to", "", "Comma-separated list of recipient(s)")
  98. flag.StringVar(&cc, "cc", "", "Comma-separated list of carbon-copy recipient(s)")
  99. flag.StringVar(&bcc, "bcc", "", "Comma-separated list of blind carbon-copy recipient(s)")
  100. flag.StringVar(&from, "from", "", "Sender of the mail (used as default account user to log in on the SMTP server)")
  101. flag.StringVar(&subject, "sub", "", "Subject of the mail")
  102. flag.Var(&attachments, "attach", "Attachment to the mail (may be repeated)")
  103. flag.Parse()
  104. LogInit(dbg)
  105. if versionFlag {
  106. showVersion := noVersion
  107. if version != "" {
  108. showVersion = version
  109. }
  110. Info.F("Version: %s", showVersion)
  111. os.Exit(0)
  112. }
  113. if flag.NArg() == 0 {
  114. result := make(chan string, 1)
  115. go readFromConsole(result)
  116. if interactive {
  117. text = <-result
  118. } else {
  119. select {
  120. case text = <-result:
  121. Info.Ln("text read from console")
  122. case <-time.After(5 * time.Second):
  123. Error.Ln("timeout reading from console")
  124. os.Exit(3)
  125. }
  126. }
  127. } else {
  128. for _, arg := range flag.Args() {
  129. text += fmt.Sprintf("%s\n", arg)
  130. }
  131. }
  132. serverPort = int64(serverPortAux)
  133. Debug.F(
  134. `
  135. ---
  136. parameters:
  137. conf: %s
  138. dbg: %t
  139. address: %s
  140. port: %d
  141. encryption: %t
  142. user: %s
  143. password: %s
  144. to: %s
  145. from: %s
  146. subject: %s
  147. attachments: %s`,
  148. configPath,
  149. dbg,
  150. serverAddress,
  151. serverPort,
  152. encryption,
  153. user,
  154. password,
  155. to,
  156. from,
  157. subject,
  158. attachments,
  159. )
  160. config := initializeConfig(configPath, section)
  161. config.Server.Merge("Address", serverAddress)
  162. config.Server.Merge("Port", serverPort)
  163. config.Server.Merge("Encryption", encryption)
  164. config.Server.Merge("User", user)
  165. config.Server.Merge("Password", password)
  166. config.Merge("From", from)
  167. config.Merge("To", toList(to))
  168. config.Merge("Cc", toList(cc))
  169. config.Merge("Bcc", toList(bcc))
  170. config.Merge("Subject", subject)
  171. config.Merge("Text", text)
  172. config.Merge("Attachments", attachments)
  173. Debug.F("---\nPre-validation config\n%s", config)
  174. err = config.Validate()
  175. if err != nil {
  176. Error.F("Config validation failed:\n%s\n", err)
  177. os.Exit(1)
  178. }
  179. Info.F("Sending mail | to: %s", config.To)
  180. SendMail(config)
  181. }