Commit bca3975fdb1111af509f4c3049c799a499661df3

Authored by Marko Tikvić
1 parent d3cc6a2895
Exists in master

email

Showing 2 changed files with 158 additions and 2 deletions   Show diff stats
File was created 1 package webutility
2
3 // TODO(markO): test test test test test (and open source?)
4
5 import (
6 "crypto/tls"
7 "errors"
8 "fmt"
9 "net/smtp"
10 "strings"
11 )
12
13 type EmailConfig struct {
14 ServerName string
15 Identity string
16 Username string
17 Password string
18 Host string
19 Port int
20 }
21
22 func NewEmailConfig(ident, uname, pword, host string, port int) *EmailConfig {
23 return &EmailConfig{
24 ServerName: host + fmt.Sprintf(":%d", port),
25 Identity: ident,
26 Username: uname,
27 Password: pword,
28 Host: host,
29 Port: port,
30 }
31 }
32
33 type Email struct {
34 To []string
35 From string
36 Subject string
37 Body string
38 }
39
40 func NewEmail(to []string, from, subject, body string) *Email {
41 return &Email{
42 To: to,
43 From: from,
44 Subject: subject,
45 Body: body,
46 }
47 }
48
49 func SendEmail(email *Email, conf *EmailConfig) error {
50 if email == nil {
51 return errors.New("no email to send")
52
53 }
54
55 if conf == nil {
56 // use (some?) default settings
57 conf = NewEmailConfig("", "marko.tikvic@to-net.rs", "quantumleap010", "mail.to-net.rs", 25)
58 }
59
60 c, err := smtp.Dial(conf.ServerName)
61 if err != nil {
62 return err
63 }
64
65 defer c.Close()
66
67 // not sure if this is needed
68 //if err = c.Hello(conf.ServerName); err != nil {
69 // return err
70 //}
71
72 if ok, _ := c.Extension("STARTTLS"); ok {
73 // disable stupid tls check for self-signed certificates
74 config := &tls.Config{
75 ServerName: conf.ServerName,
76 InsecureSkipVerify: true,
77 }
78 // for golang testing
79 //if testHookStartTLS != nil {
80 // testHookStartTLS(config)
81 //}
82 if err = c.StartTLS(config); err != nil {
83 return err
84 }
85 }
86
87 /*
88 // don't know what to do with this
89 if a != nil && c.ext != nil {
90 if _, ok := c.ext["AUTH"]; !ok {
91 return errors.New("smtp: server doesn't support AUTH")
92 }
93 if err = c.Auth(a); err != nil {
94 return err
95 }
96 }
97 */
98
99 // Set up authentication information.
100 auth := smtp.PlainAuth(conf.Identity, conf.Username, conf.Password, conf.Host)
101 if err = c.Auth(auth); err != nil {
102 return err
103 }
104
105 if err = c.Mail(email.From); err != nil {
106 return err
107 }
108
109 for _, addr := range email.To {
110 if err = c.Rcpt(addr); err != nil {
111 return err
112 }
113 }
114
115 w, err := c.Data()
116 if err != nil {
117 return err
118 }
119
120 _, err = w.Write(email.Bytes())
121 if err != nil {
122 return err
123 }
124
125 err = w.Close()
126 if err != nil {
127 return err
128 }
129
130 return c.Quit()
131 }
132
133 func (e *Email) String() string {
134 var str strings.Builder
135
136 str.WriteString("From:" + e.From + "\r\n")
137
138 str.WriteString("To:")
139 for i, _ := range e.To {
140 if i > 0 {
141 str.WriteString(",")
142 }
143 str.WriteString(e.To[i])
144 }
145 str.WriteString("\r\n")
146
147 str.WriteString("Subject:" + e.Subject + "\r\n")
148
149 // body
150 str.WriteString("\r\n" + e.Body + "\r\n")
151
152 return str.String()
153 }
154
155 func (e *Email) Bytes() []byte {
156 return []byte(e.String())
157 }
158
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "net/http" 5 "net/http"
6 "strings" 6 "strings"
7 ) 7 )
8 8
9 type Filter map[string]string 9 type Filter map[string]string
10 10
11 func (fs Filter) validate(validFilters []string) (Filter, bool) { 11 func (fs Filter) validate(validFilters []string) (Filter, bool) {
12 goodFilters := make(map[string]string) 12 goodFilters := make(map[string]string)
13 cnt := 0 13 cnt := 0
14 len := 0 14 len := 0
15 for f, _ := range fs { 15 for f, _ := range fs {
16 len++ 16 len++
17 for _, v := range validFilters { 17 for _, v := range validFilters {
18 if f == v { 18 if f == v {
19 cnt++ 19 cnt++
20 goodFilters[f] = fs[f] 20 goodFilters[f] = fs[f]
21 } 21 }
22 } 22 }
23 } 23 }
24 24
25 result := true 25 result := true
26 if len > 0 && cnt == 0 { 26 if len > 0 && cnt == 0 {
27 // if no valid filters are found declare filtering request as invalid 27 // if no valid filters are found declare filtering request as invalid
28 result = false 28 result = false
29 } 29 }
30 30
31 return goodFilters, result 31 return goodFilters, result
32 } 32 }
33 33
34 // requires input in format: "param1::value1|param2::value2..." 34 // requires input in format: "param1::value1|param2::value2..."
35 func ParseFilters(req *http.Request, header string) (filters Filter) { 35 func ParseFilters(req *http.Request, header string) (filters Filter) {
36 q := req.FormValue(header) 36 q := req.FormValue(header)
37 q = strings.Trim(q, "\"") 37 q = strings.Trim(q, "\"")
38 kvp := strings.Split(q, "|") 38 kvp := strings.Split(q, "|")
39 filters = make(map[string]string, len(kvp)) 39 filters = make(map[string]string, len(kvp))
40 40
41 for i, _ := range kvp { 41 for i, _ := range kvp {
42 kv := strings.Split(kvp[i], "::") 42 kv := strings.Split(kvp[i], "::")
43 if len(kv) == 2 { 43 if len(kv) == 2 {
44 key := kv[0] 44 key := kv[0]
45 val := kv[1] 45 val := kv[1]
46 filters[key] = val 46 filters[key] = val
47 } 47 }
48 } 48 }
49 49
50 return filters 50 return filters
51 } 51 }
52 52
53 // TODO(marko): very dodgy, needs more robustness 53 // TODO(marko): very dodgy, needs more robustness
54 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) { 54 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) {
55 if prefix != "" { 55 if prefix != "" {
56 prefix += "." 56 prefix += "."
57 } 57 }
58 if len(filters) == 0 { 58 if len(filters) == 0 {
59 return "", true 59 return "", true
60 } 60 }
61 61
62 filters, ok = filters.validate(validFilters) 62 filters, ok = filters.validate(validFilters)
63 if !ok { 63 if !ok {
64 return "", ok 64 return "", ok
65 } 65 }
66 66
67 symbol := "=" 67 symbol := "="
68 for k, v := range filters { 68 for k, v := range filters {
69 if res != "" { 69 if res != "" {
70 res += " and " 70 res += " and "
71 } else { 71 } else {
72 res += " where " 72 res += " where "
73 } 73 }
74 c := string(v[0]) 74 c := string(v[0])
75 if c == "<" || c == ">" { 75 if c == "<" || c == ">" {
76 symbol = c 76 symbol = "" // examples: >3, >=3
77 v = string(v[1:])
78 } else { 77 } else {
79 symbol = "=" 78 symbol = "="
80 } 79 }
81 80
82 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v) 81 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v)
83 } 82 }
84 83
85 return res, ok 84 return res, ok
86 } 85 }
87 86