Пример #1
0
func (msg Jmessage) DecSubject() string {
	header := msg.Header
	splitsubj := strings.Fields(header.Get("Subject"))
	var bufSubj bytes.Buffer
	for seq, parts := range splitsubj {
		switch {
		case !strings.HasPrefix(parts, "=?"):
			// エンコードなし
			if seq > 0 {
				// 先頭以外はSpaceで区切りなおし
				bufSubj.WriteByte(' ')
			}
			bufSubj.WriteString(parts)

		case len(parts) > len(SUBJ_PREFIX_ISO2022JP_B) && strings.HasPrefix(strings.ToLower(parts[0:len(SUBJ_PREFIX_ISO2022JP_B)]), SUBJ_PREFIX_ISO2022JP_B):
			// iso-2022-jp / base64
			beforeDecode := parts[len(SUBJ_PREFIX_ISO2022JP_B):strings.LastIndex(parts, "?=")]
			afterDecode := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(beforeDecode))
			subj_bytes, _ := ioutil.ReadAll(transform.NewReader(afterDecode, japanese.ISO2022JP.NewDecoder()))
			bufSubj.Write(subj_bytes)

		case len(parts) > len(SUBJ_PREFIX_ISO2022JP_Q) && strings.HasPrefix(strings.ToLower(parts[0:len(SUBJ_PREFIX_ISO2022JP_Q)]), SUBJ_PREFIX_ISO2022JP_Q):
			// iso-2022-jp / quoted-printable
			beforeDecode := parts[len(SUBJ_PREFIX_ISO2022JP_Q):strings.LastIndex(parts, "?=")]
			afterDecode := quotedprintable.NewReader(bytes.NewBufferString(beforeDecode))
			subj_bytes, _ := ioutil.ReadAll(transform.NewReader(afterDecode, japanese.ISO2022JP.NewDecoder()))
			bufSubj.Write(subj_bytes)

		case len(parts) > len(SUBJ_PREFIX_UTF8_B) && strings.HasPrefix(strings.ToLower(parts[0:len(SUBJ_PREFIX_UTF8_B)]), SUBJ_PREFIX_UTF8_B):
			// utf-8 / base64
			beforeDecode := parts[len(SUBJ_PREFIX_UTF8_B):strings.LastIndex(parts, "?=")]
			subj_bytes, _ := base64.StdEncoding.DecodeString(beforeDecode)
			bufSubj.Write(subj_bytes)

		case len(parts) > len(SUBJ_PREFIX_UTF8_Q) && strings.HasPrefix(strings.ToLower(parts[0:len(SUBJ_PREFIX_UTF8_Q)]), SUBJ_PREFIX_UTF8_Q):
			// utf-8 / quoted-printable
			beforeDecode := parts[len(SUBJ_PREFIX_UTF8_Q):strings.LastIndex(parts, "?=")]
			afterDecode := quotedprintable.NewReader(bytes.NewBufferString(beforeDecode))
			subj_bytes, _ := ioutil.ReadAll(afterDecode)
			bufSubj.Write(subj_bytes)
		}
	}
	return bufSubj.String()
}
Пример #2
0
func ReadPlainMail(msg *mail.Message) (email JsonMail, err error) {
	const cte = "Content-Transfer-Encoding"
	if msg.Header.Get(cte) == "quoted-printable" {
		msg.Body = quotedprintable.NewReader(msg.Body)
	}
	body, err := ioutil.ReadAll(msg.Body)
	if err != nil {
		return email, errors.New("ERROR: reading non multipart mail body")

	}
	if msg.Header.Get(cte) == "base64" {
		msg.Body = quotedprintable.NewReader(msg.Body)
		body, err = base64.StdEncoding.DecodeString(string(body))
		if err != nil {
			return email, errors.New("ERROR: decoding base64")
		}
	}

	b := `<pre>` + string(body) + `</pre>`
	subject := msg.Header.Get("Subject")
	decoder := WordDecoder()
	decodedSubject, err := decoder.Decode(subject)
	if err == nil {
		subject = decodedSubject
	}
	decodedFrom, err := decoder.Decode(msg.Header.Get("From"))
	if err != nil {
		parts := strings.Split(email.From, " ")
		for i, part := range parts {
			decodedPart, err := decoder.Decode(part)
			if err == nil {
				parts[i] = decodedPart
			}
		}
		decodedFrom = strings.Join(parts, " ")
	}
	email.From = decodedFrom
	email.Subject = subject
	email.BodyText = b
	email.Body = b
	return email, nil
}
Пример #3
0
// contentReader ...
func contentReader(headers Header, bodyReader io.Reader) *bufio.Reader {
	if headers.Get("Content-Transfer-Encoding") == "quoted-printable" {
		headers.Del("Content-Transfer-Encoding")
		return bufioReader(quotedprintable.NewReader(bodyReader))
	}
	if headers.Get("Content-Transfer-Encoding") == "base64" {
		headers.Del("Content-Transfer-Encoding")
		return bufioReader(base64.NewDecoder(base64.StdEncoding, bodyReader))
	}
	return bufioReader(bodyReader)
}
Пример #4
0
// Read body from text/plain
func readPlainText(header textproto.MIMEHeader, body io.Reader) (mailbody []byte, err error) {
	contentType := header.Get("Content-Type")
	encoding := header.Get("Content-Transfer-Encoding")
	_, params, err := mime.ParseMediaType(contentType)
	if encoding == ENC_QUOTED_PRINTABLE {
		if strings.ToLower(params["charset"]) == CHARSET_ISO2022JP {
			mailbody, err = ioutil.ReadAll(transform.NewReader(quotedprintable.NewReader(body), japanese.ISO2022JP.NewDecoder()))
		} else {
			mailbody, err = ioutil.ReadAll(quotedprintable.NewReader(body))
		}
	} else if encoding == ENC_BASE64 {
		mailbody, err = ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, body))
	} else if len(contentType) == 0 || strings.ToLower(params["charset"]) == CHARSET_ISO2022JP {
		// charset=ISO-2022-JP
		mailbody, err = ioutil.ReadAll(transform.NewReader(body, japanese.ISO2022JP.NewDecoder()))
	} else {
		// encoding = 8bit or 7bit
		mailbody, err = ioutil.ReadAll(body)
	}
	return mailbody, err
}
Пример #5
0
Файл: mail.go Проект: kaey/mail
// DecodeTransfer decodes base64, quoted-printable or plain text.
func decodeTransfer(r io.Reader, label string) io.Reader {
	switch strings.ToLower(label) {
	case "base64":
		return base64.NewDecoder(base64.StdEncoding, transform.NewReader(r, nonASCIITransformer{}))
	case "quoted-printable":
		return quotedprintable.NewReader(transform.NewReader(r, transform.Chain(nonASCIITransformer{}, newlineAppendTransformer{})))
	case "", "7bit", "8bit", "binary":
		return r
	default:
		return failReader{fmt.Errorf("unsupported transfer encoding: %v", label)}
	}
}
Пример #6
0
func Decode(e string, bstr []byte) ([]byte, error) {
	var err error
	switch strings.ToUpper(e) {
	case "Q":
		bstr, err = ioutil.ReadAll(quotedprintable.NewReader(bytes.NewReader(bstr)))
	case "B":
		bstr, err = base64.StdEncoding.DecodeString(string(bstr))
	default:
		//not set encoding type

	}
	return bstr, err
}
Пример #7
0
func ExampleNewReader() {
	for _, s := range []string{
		`=48=65=6C=6C=6F=2C=20=47=6F=70=68=65=72=73=21`,
		`invalid escape: =B`,
		"Hello, Gophers! This symbol will be unescaped: =3D and this will be written in =\r\none line.",
	} {
		b, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(s)))
		fmt.Printf("%s %v\n", b, err)
	}
	// Output:
	// Hello, Gophers! <nil>
	// invalid escape:  unexpected EOF
	// Hello, Gophers! This symbol will be unescaped: = and this will be written in one line. <nil>
}
Пример #8
0
func newPart(mr *Reader) (*Part, error) {
	bp := &Part{
		Header: make(map[string][]string),
		mr:     mr,
	}
	if err := bp.populateHeaders(); err != nil {
		return nil, err
	}
	bp.r = partReader{bp}
	const cte = "Content-Transfer-Encoding"
	if bp.Header.Get(cte) == "quoted-printable" {
		bp.Header.Del(cte)
		bp.r = quotedprintable.NewReader(bp.r)
	}
	return bp, nil
}
Пример #9
0
// Decode body text and store it in a string
func extractText(con *data.Context, header emailHeader, bodyReader io.Reader) (*TextBody, error) {
	var ret TextBody

	s, err := ioutil.ReadAll(bodyReader)
	if err != nil {
		return nil, err
	}
	con.Log.Debugf("header: %v", header)

	ret.ContentType = header.Get("Content-Type")

	encoding := header.Get("Content-Transfer-Encoding")
	con.Log.Debugf("extractTextBody encoding: %v", encoding)

	if encoding == "base64" {
		b, err := base64.StdEncoding.DecodeString(string(s))
		if err != nil {
			return nil, err
		}
		ret.Body = string(b)
		return &ret, nil
	}

	if encoding == "7bit" {
		// that is just US ASCII (7bit)
		// https://stackoverflow.com/questions/25710599/content-transfer-encoding-7bit-or-8-bit
		ret.Body = string(s)
		return &ret, nil
	}

	if encoding == "quoted-printable" {
		// https://stackoverflow.com/questions/24883742/how-to-decode-mail-body-in-go
		r := quotedprintable.NewReader(bytes.NewReader(s))
		b, err := ioutil.ReadAll(r)
		if err != nil {
			return nil, err
		}
		ret.Body = string(b)
		return &ret, nil
	}

	// ok, let's guess this is just plain text and put it into a string
	ret.Body = string(s)

	return &ret, nil
}
Пример #10
0
func main() {
	flag.Parse()

	var in io.Reader
	var out io.Writer

	if input == nil || strings.TrimSpace(*input) == "" {
		in = bufio.NewReader(os.Stdin)
	} else {
		fileBytes, err := ioutil.ReadFile(*input)
		if err != nil {
			log.Fatal(err)
		}
		in = bytes.NewReader(fileBytes)
	}

	if decode != nil && *decode == true {
		in = qp.NewReader(in)
	}

	inBytes, err := ioutil.ReadAll(in)
	if err != nil {
		log.Fatal(err)
	}

	if output == nil || strings.TrimSpace(*output) == "" {
		out = os.Stdout
	} else {
		out, err = os.OpenFile(*output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
		if err != nil {
			log.Fatal(err)
		}
	}

	if decode == nil || *decode == false {
		out = qp.NewWriter(out)
	}

	n, err := out.Write(inBytes)
	if err != nil {
		log.Fatal(err)
	}
	if n != len(inBytes) {
		log.Fatalf("Partial write (%d != %d)\n", n, len(inBytes))
	}
}
Пример #11
0
func addContent(email *Email, header Header, r io.Reader) error {
	switch header.Get("Content-Transfer-Encoding") {
	case "quoted-printable":
		r = quotedprintable.NewReader(r)
	case "base64":
		r = base64.NewDecoder(base64.StdEncoding, r)
	}

	data, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	mediaType, params, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil {
		return err
	}

	if isPlainText(mediaType) && email.Text == "" {
		email.Text = string(data)
		email.Text = strings.Replace(email.Text, "\n", "<br>\n", -1)
	} else if isHtml(mediaType) && email.Html == nil {
		html := string(data)
		email.Html = &Attachment{Data: []byte(html), Filename: "email-content.html"}
	} else if isMultipart(mediaType) {
		if err := handleMultipart(email, bytes.NewReader(data), params["boundary"]); err != nil {
			return err
		}
	} else {
		// figure out filename
		filename := getFilename(header.Get("Content-Disposition"))
		if filename == "" {
			if isPlainText(mediaType) {
				filename = "attachment.txt"
			} else if isHtml(mediaType) {
				filename = "attachment.html"
			} else {
				return errors.New("don't know how to generate filename for " + mediaType)
			}
		}

		email.Attachments = append(email.Attachments, Attachment{Data: data, Filename: filename})
	}

	return nil
}
Пример #12
0
// decodeSection attempts to decode the data from reader using the algorithm listed in
// the Content-Transfer-Encoding header, returning the raw data if it does not known
// the encoding type.
func decodeSection(encoding string, reader io.Reader) ([]byte, error) {
	// Default is to just read input into bytes
	decoder := reader

	switch strings.ToLower(encoding) {
	case "quoted-printable":
		decoder = quotedprintable.NewReader(reader)
	case "base64":
		cleaner := NewBase64Cleaner(reader)
		decoder = base64.NewDecoder(base64.StdEncoding, cleaner)
	}

	// Read bytes into buffer
	buf := new(bytes.Buffer)
	_, err := buf.ReadFrom(decoder)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
Пример #13
0
func decodeContent(content Content) {
	for contentType, curPart := range content {
		switch curPart.Encoding {
		case "quoted-printable":
			{
				var buf bytes.Buffer
				_, err := io.Copy(&buf, quotedprintable.NewReader(strings.NewReader(curPart.Body)))
				if err != nil {
					fmt.Printf("[watney] ERROR while trying to decode content of type " +
						"'quoted-printable'\n")
					continue
				}
				content[contentType] = ContentPart{
					Encoding: curPart.Encoding,
					Charset:  curPart.Charset,
					Body:     buf.String(),
				}
			}
		}
	}
}
Пример #14
0
// *Since the mime library in use by ```email``` is now in the stdlib, this test is deprecated
func Test_quotedPrintDecode(t *testing.T) {
	text := []byte("Dear reader!\r\n\r\n" +
		"This is a test email to try and capture some of the corner cases that exist=\r\n" +
		" within\r\n" +
		"the quoted-printable encoding.\r\n" +
		"There are some wacky parts like =3D, and this input assumes UNIX line break=\r\n" +
		"s so\r\n" +
		"it can come out a little weird.  Also, we need to support unicode so here's=\r\n" +
		" a fish: =F0=9F=90=9F\r\n")
	expected := []byte("Dear reader!\r\n\r\n" +
		"This is a test email to try and capture some of the corner cases that exist within\r\n" +
		"the quoted-printable encoding.\r\n" +
		"There are some wacky parts like =, and this input assumes UNIX line breaks so\r\n" +
		"it can come out a little weird.  Also, we need to support unicode so here's a fish: 🐟\r\n")
	qp := quotedprintable.NewReader(bytes.NewReader(text))
	got, err := ioutil.ReadAll(qp)
	if err != nil {
		t.Fatal("quotePrintDecode: ", err)
	}

	if !bytes.Equal(got, expected) {
		t.Errorf("quotedPrintDecode generated incorrect results: %#q != %#q", got, expected)
	}
}
Пример #15
0
func getDecodingContent(lang, encoding, content string) string {

	if encoding == "b" {
		decoded, err := base64.StdEncoding.DecodeString(content)
		if err != nil {
			log.Printf("decode error:%s", err)
			return ""
		}

		if lang == "utf-8" {
			//log.Printf("utf-8, noneed to convert: %s\n", string(decoded))
			return string(decoded)
		}

		//非u8编码语言需要统一转为u8
		dec := mahonia.NewDecoder(lang)
		if u8Decoded, ok := dec.ConvertStringOK(string(decoded)); ok {
			//log.Printf("%s convert to utf-8: %s\n", lang, string(decoded))
			return string(u8Decoded) //注意作用域
		}

	} else if encoding == "q" {
		//通过字符串构造Reader
		r := quotedprintable.NewReader(strings.NewReader(content))
		body, err := ioutil.ReadAll(r)
		if err != nil {
			log.Printf("read content error: %s", err)
			return ""
		}
		log.Printf("quoted decode: %s\n", string(body))
		return string(body)
	}

	//转换失败,返回空
	return ""
}
Пример #16
0
func partWalker(r io.Reader, path []int, header map[string][]string, parse ParseFn, pc *ParserContext, depth int) error {
	depth--
	if depth < 0 {
		return nil
	}
	cds := getHeader(header, "content-disposition")
	contentDisposition_str, cdParams, err := mime.ParseMediaType(cds)
	var contentDisposition ContentDisposition
	if err != nil {
		contentDisposition = CDInline
	} else {
		contentDisposition = ContentDispositionFromStr(contentDisposition_str)
	}

	contentType := getHeader(header, "content-type")
	mediaType, params, err := mime.ParseMediaType(contentType)
	if err != nil {
		mediaType = "text/plain"
	}

	isMultipart := true
	boundary := ""
	mediaType = strings.ToLower(mediaType)
	if !strings.HasPrefix(mediaType, "multipart/") {
		isMultipart = false
	} else {
		var ok bool
		boundary, ok = params["boundary"]
		if !ok {
			isMultipart = false
		}
	}

	partIndex := 0
	if isMultipart {
		err = parse(pc, path, nil, PartDescr{mediaType, params, contentDisposition, cdParams})
		if err != nil {
			return err
		}
		mr := multipart.NewReader(r, boundary)
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			}
			if err != nil {
				return err
			}
			err = partWalker(p, append(path, partIndex), p.Header, parse, pc, depth)
			if err != nil {
				return err
			}
			partIndex++
		}
		return nil
	}

	qp := false
	cte := strings.ToLower(getHeader(header, "Content-Transfer-Encoding"))

	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	br := bytes.NewReader(buf)

	var reader io.Reader
	switch cte {
	case "base64":
		reader = base64.NewDecoder(base64.StdEncoding, br)
	case "quoted-printable":
		qp = true
		reader = quotedprintable.NewReader(br)
	default:
		reader = br
	}
retry:
	decodedBuf, err := ioutil.ReadAll(reader)
	if err != nil {
		if qp {
			/* qp tends to fail often, retry in non-qp */
			qp = false
			br.Seek(0, 0)
			reader = br
			goto retry
		}
		return err
	}
	return parse(pc, path, bytes.NewBuffer(decodedBuf), PartDescr{mediaType, params, contentDisposition, cdParams})
}