data.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package config
  2. import (
  3. "fmt"
  4. "log"
  5. "os/exec"
  6. "strconv"
  7. "strings"
  8. "github.com/BurntSushi/toml"
  9. )
  10. // maybeInt is an integer that may be nil
  11. type maybeInt struct {
  12. int
  13. bool
  14. }
  15. func (m maybeInt) empty() bool {
  16. return !m.bool
  17. }
  18. func (m maybeInt) value() int {
  19. return m.int
  20. }
  21. func initMaybeInt(value int) maybeInt {
  22. return maybeInt{value, true}
  23. }
  24. func (m *maybeInt) UnmarshalText(text []byte) error {
  25. var err error
  26. var i int64
  27. if text != nil {
  28. str := string(text)
  29. i, err = strconv.ParseInt(str, 10, 64)
  30. m.int = int(i)
  31. m.bool = true
  32. }
  33. return err
  34. }
  35. type fileConfig struct {
  36. Default string `toml:"default_account"`
  37. MailboxPath string `toml:"mailbox_path"`
  38. Accounts []account `toml:"account"`
  39. DefaultMessages maybeInt `toml:"default_messages"`
  40. }
  41. type account struct {
  42. Name string `toml:"name"`
  43. MailboxPath string `toml:"mailbox_path"`
  44. ConnectionInfo *connectionInfo `toml:"connection"`
  45. ExcludedFolders []string `toml:"excluded_folders"`
  46. Messages maybeInt `toml:"messages"`
  47. }
  48. type connectionInfo struct {
  49. Host string `toml:"hostname"`
  50. Port int `toml:"port"`
  51. Username string `toml:"username"`
  52. PasswordExec *ShellScript `toml:"password_exec"`
  53. PasswordFile string `toml:"password_file"`
  54. Password string `toml:"password"`
  55. }
  56. func (c *connectionInfo) String() string {
  57. var res string
  58. res += "{"
  59. res += fmt.Sprintf("Host: %s, ", c.Host)
  60. res += fmt.Sprintf("Port: %d, ", c.Port)
  61. res += fmt.Sprintf("Username: %s, ", c.Username)
  62. res += fmt.Sprintf("Password: **********, ")
  63. res += fmt.Sprintf("PasswordFile: %s, ", c.PasswordFile)
  64. res += fmt.Sprintf("PasswordExec: %s}", c.PasswordExec)
  65. return res
  66. }
  67. // ShellScript might be either:
  68. // - the path to an executable
  69. // - an executable in path
  70. // - a shell command with its argument
  71. // all these must return on stdout the password after successful execution.
  72. type ShellScript struct {
  73. Executable string
  74. }
  75. func (s *ShellScript) UnmarshalText(text []byte) error {
  76. s.Executable = string(text)
  77. return nil
  78. }
  79. func (s *ShellScript) String() string {
  80. return s.Executable
  81. }
  82. // Present indicates if the value has been filled in into the config
  83. func (s *ShellScript) Present() bool {
  84. if s != nil {
  85. return s.Executable != ""
  86. }
  87. return false
  88. }
  89. // Run tries to execute the command, first looking for a corresponding executable and
  90. // invoking it, then invoking the string as a command followed by its parameters.
  91. func (s *ShellScript) Run() (string, error) {
  92. if path, err := exec.LookPath(s.Executable); err == nil {
  93. return doExec(path)
  94. }
  95. parts := strings.Split(s.Executable, " ")
  96. return doExec(parts[0], parts[1:]...)
  97. }
  98. func doExec(path string, args ...string) (string, error) {
  99. cmd := exec.Command(path, args...)
  100. out, err := cmd.Output()
  101. if err != nil {
  102. log.Println("Error running:", cmd)
  103. return "", err
  104. }
  105. return string(out), nil
  106. }
  107. // parseFile reads the given config file and, if succeeding, returns a *FileConfig.
  108. func parseFile(path string) (*fileConfig, error) {
  109. newConfig := fileConfig{}
  110. _, err := toml.DecodeFile(path, &newConfig)
  111. return &newConfig, err
  112. }