123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- package util
- import (
- "bytes"
- "compress/zlib"
- "crypto/md5"
- "encoding/base64"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "regexp"
- "strings"
- "gopkg.in/iconv.v1"
- "github.com/sloonz/go-qprintable"
- )
- type EmailParts struct {
- User string
- Host string
- }
- func ValidateEmailData(mailFrom, rcptTo string) (*EmailParts, *EmailParts, error) {
- var user, host string
- var addrErr error
- if user, host, addrErr = extractEmail(mailFrom); addrErr != nil {
- return nil, nil, addrErr
- }
- from := &EmailParts{User: user, Host: host}
- if user, host, addrErr = extractEmail(rcptTo); addrErr != nil {
- return nil, nil, addrErr
- }
- to := &EmailParts{User: user, Host: host}
- return from, to, nil
- }
- var extractEmailRegex, _ = regexp.Compile(`<(.+?)@(.+?)>`) // go home regex, you're drunk!
- func extractEmail(str string) (name string, host string, err error) {
- if matched := extractEmailRegex.FindStringSubmatch(str); len(matched) > 2 {
- host = validHost(matched[2])
- name = matched[1]
- } else {
- if res := strings.Split(str, "@"); len(res) > 1 {
- name = res[0]
- host = validHost(res[1])
- }
- }
- if host == "" || name == "" {
- err = errors.New("Invalid address, [" + name + "@" + host + "] address:" + str)
- }
- return name, host, err
- }
- var mimeRegex, _ = regexp.Compile(`=\?(.+?)\?([QBqp])\?(.+?)\?=`)
- // Decode strings in Mime header format
- // eg. =?ISO-2022-JP?B?GyRCIVo9dztSOWJAOCVBJWMbKEI=?=
- func MimeHeaderDecode(str string) string {
- matched := mimeRegex.FindAllStringSubmatch(str, -1)
- var charset, encoding, payload string
- if matched != nil {
- for i := 0; i < len(matched); i++ {
- if len(matched[i]) > 2 {
- charset = matched[i][1]
- encoding = strings.ToUpper(matched[i][2])
- payload = matched[i][3]
- switch encoding {
- case "B":
- str = strings.Replace(
- str,
- matched[i][0],
- MailTransportDecode(payload, "base64", charset),
- 1)
- case "Q":
- str = strings.Replace(
- str,
- matched[i][0],
- MailTransportDecode(payload, "quoted-printable", charset),
- 1)
- }
- }
- }
- }
- return str
- }
- var valihostRegex, _ = regexp.Compile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`)
- func validHost(host string) string {
- host = strings.Trim(host, " ")
- if valihostRegex.MatchString(host) {
- return host
- }
- return ""
- }
- // decode from 7bit to 8bit UTF-8
- // encodingType can be "base64" or "quoted-printable"
- func MailTransportDecode(str string, encodingType string, charset string) string {
- if charset == "" {
- charset = "UTF-8"
- } else {
- charset = strings.ToUpper(charset)
- }
- if encodingType == "base64" {
- str = fromBase64(str)
- } else if encodingType == "quoted-printable" {
- str = fromQuotedP(str)
- }
- if charset != "UTF-8" {
- charset = fixCharset(charset)
- if cd, err := iconv.Open("UTF-8", charset); err == nil {
- defer func() {
- cd.Close()
- if r := recover(); r != nil {
- //logln(1, fmt.Sprintf("Recovered in %v", r))
- }
- }()
- // eg. charset can be "ISO-2022-JP"
- return cd.ConvString(str)
- }
- }
- return str
- }
- func fromBase64(data string) string {
- buf := bytes.NewBufferString(data)
- decoder := base64.NewDecoder(base64.StdEncoding, buf)
- res, _ := ioutil.ReadAll(decoder)
- return string(res)
- }
- func fromQuotedP(data string) string {
- buf := bytes.NewBufferString(data)
- decoder := qprintable.NewDecoder(qprintable.BinaryEncoding, buf)
- res, _ := ioutil.ReadAll(decoder)
- return string(res)
- }
- var charsetRegex, _ = regexp.Compile(`[_:.\/\\]`)
- func fixCharset(charset string) string {
- fixed_charset := charsetRegex.ReplaceAllString(charset, "-")
- // Fix charset
- // borrowed from http://squirrelmail.svn.sourceforge.net/viewvc/squirrelmail/trunk/squirrelmail/include/languages.php?revision=13765&view=markup
- // OE ks_c_5601_1987 > cp949
- fixed_charset = strings.Replace(fixed_charset, "ks-c-5601-1987", "cp949", -1)
- // Moz x-euc-tw > euc-tw
- fixed_charset = strings.Replace(fixed_charset, "x-euc", "euc", -1)
- // Moz x-windows-949 > cp949
- fixed_charset = strings.Replace(fixed_charset, "x-windows_", "cp", -1)
- // windows-125x and cp125x charsets
- fixed_charset = strings.Replace(fixed_charset, "windows-", "cp", -1)
- // ibm > cp
- fixed_charset = strings.Replace(fixed_charset, "ibm", "cp", -1)
- // iso-8859-8-i -> iso-8859-8
- fixed_charset = strings.Replace(fixed_charset, "iso-8859-8-i", "iso-8859-8", -1)
- if charset != fixed_charset {
- return fixed_charset
- }
- return charset
- }
- // returns an md5 hash as string of hex characters
- func MD5Hex(stringArguments ...*string) string {
- h := md5.New()
- var r *strings.Reader
- for i := 0; i < len(stringArguments); i++ {
- r = strings.NewReader(*stringArguments[i])
- io.Copy(h, r)
- }
- sum := h.Sum([]byte{})
- return fmt.Sprintf("%x", sum)
- }
- // concatenate & compress all strings passed in
- func Compress(stringArguments ...*string) string {
- var b bytes.Buffer
- var r *strings.Reader
- w, _ := zlib.NewWriterLevel(&b, zlib.BestSpeed)
- for i := 0; i < len(stringArguments); i++ {
- r = strings.NewReader(*stringArguments[i])
- io.Copy(w, r)
- }
- w.Close()
- return b.String()
- }
|