diff options
Diffstat (limited to 'vendor/gopkg.in/gomail.v2/writeto.go')
-rw-r--r-- | vendor/gopkg.in/gomail.v2/writeto.go | 306 |
1 files changed, 0 insertions, 306 deletions
diff --git a/vendor/gopkg.in/gomail.v2/writeto.go b/vendor/gopkg.in/gomail.v2/writeto.go deleted file mode 100644 index 9fb6b86e..00000000 --- a/vendor/gopkg.in/gomail.v2/writeto.go +++ /dev/null @@ -1,306 +0,0 @@ -package gomail - -import ( - "encoding/base64" - "errors" - "io" - "mime" - "mime/multipart" - "path/filepath" - "strings" - "time" -) - -// WriteTo implements io.WriterTo. It dumps the whole message into w. -func (m *Message) WriteTo(w io.Writer) (int64, error) { - mw := &messageWriter{w: w} - mw.writeMessage(m) - return mw.n, mw.err -} - -func (w *messageWriter) writeMessage(m *Message) { - if _, ok := m.header["Mime-Version"]; !ok { - w.writeString("Mime-Version: 1.0\r\n") - } - if _, ok := m.header["Date"]; !ok { - w.writeHeader("Date", m.FormatDate(now())) - } - w.writeHeaders(m.header) - - if m.hasMixedPart() { - w.openMultipart("mixed") - } - - if m.hasRelatedPart() { - w.openMultipart("related") - } - - if m.hasAlternativePart() { - w.openMultipart("alternative") - } - for _, part := range m.parts { - w.writePart(part, m.charset) - } - if m.hasAlternativePart() { - w.closeMultipart() - } - - w.addFiles(m.embedded, false) - if m.hasRelatedPart() { - w.closeMultipart() - } - - w.addFiles(m.attachments, true) - if m.hasMixedPart() { - w.closeMultipart() - } -} - -func (m *Message) hasMixedPart() bool { - return (len(m.parts) > 0 && len(m.attachments) > 0) || len(m.attachments) > 1 -} - -func (m *Message) hasRelatedPart() bool { - return (len(m.parts) > 0 && len(m.embedded) > 0) || len(m.embedded) > 1 -} - -func (m *Message) hasAlternativePart() bool { - return len(m.parts) > 1 -} - -type messageWriter struct { - w io.Writer - n int64 - writers [3]*multipart.Writer - partWriter io.Writer - depth uint8 - err error -} - -func (w *messageWriter) openMultipart(mimeType string) { - mw := multipart.NewWriter(w) - contentType := "multipart/" + mimeType + ";\r\n boundary=" + mw.Boundary() - w.writers[w.depth] = mw - - if w.depth == 0 { - w.writeHeader("Content-Type", contentType) - w.writeString("\r\n") - } else { - w.createPart(map[string][]string{ - "Content-Type": {contentType}, - }) - } - w.depth++ -} - -func (w *messageWriter) createPart(h map[string][]string) { - w.partWriter, w.err = w.writers[w.depth-1].CreatePart(h) -} - -func (w *messageWriter) closeMultipart() { - if w.depth > 0 { - w.writers[w.depth-1].Close() - w.depth-- - } -} - -func (w *messageWriter) writePart(p *part, charset string) { - w.writeHeaders(map[string][]string{ - "Content-Type": {p.contentType + "; charset=" + charset}, - "Content-Transfer-Encoding": {string(p.encoding)}, - }) - w.writeBody(p.copier, p.encoding) -} - -func (w *messageWriter) addFiles(files []*file, isAttachment bool) { - for _, f := range files { - if _, ok := f.Header["Content-Type"]; !ok { - mediaType := mime.TypeByExtension(filepath.Ext(f.Name)) - if mediaType == "" { - mediaType = "application/octet-stream" - } - f.setHeader("Content-Type", mediaType+`; name="`+f.Name+`"`) - } - - if _, ok := f.Header["Content-Transfer-Encoding"]; !ok { - f.setHeader("Content-Transfer-Encoding", string(Base64)) - } - - if _, ok := f.Header["Content-Disposition"]; !ok { - var disp string - if isAttachment { - disp = "attachment" - } else { - disp = "inline" - } - f.setHeader("Content-Disposition", disp+`; filename="`+f.Name+`"`) - } - - if !isAttachment { - if _, ok := f.Header["Content-ID"]; !ok { - f.setHeader("Content-ID", "<"+f.Name+">") - } - } - w.writeHeaders(f.Header) - w.writeBody(f.CopyFunc, Base64) - } -} - -func (w *messageWriter) Write(p []byte) (int, error) { - if w.err != nil { - return 0, errors.New("gomail: cannot write as writer is in error") - } - - var n int - n, w.err = w.w.Write(p) - w.n += int64(n) - return n, w.err -} - -func (w *messageWriter) writeString(s string) { - n, _ := io.WriteString(w.w, s) - w.n += int64(n) -} - -func (w *messageWriter) writeHeader(k string, v ...string) { - w.writeString(k) - if len(v) == 0 { - w.writeString(":\r\n") - return - } - w.writeString(": ") - - // Max header line length is 78 characters in RFC 5322 and 76 characters - // in RFC 2047. So for the sake of simplicity we use the 76 characters - // limit. - charsLeft := 76 - len(k) - len(": ") - - for i, s := range v { - // If the line is already too long, insert a newline right away. - if charsLeft < 1 { - if i == 0 { - w.writeString("\r\n ") - } else { - w.writeString(",\r\n ") - } - charsLeft = 75 - } else if i != 0 { - w.writeString(", ") - charsLeft -= 2 - } - - // While the header content is too long, fold it by inserting a newline. - for len(s) > charsLeft { - s = w.writeLine(s, charsLeft) - charsLeft = 75 - } - w.writeString(s) - if i := lastIndexByte(s, '\n'); i != -1 { - charsLeft = 75 - (len(s) - i - 1) - } else { - charsLeft -= len(s) - } - } - w.writeString("\r\n") -} - -func (w *messageWriter) writeLine(s string, charsLeft int) string { - // If there is already a newline before the limit. Write the line. - if i := strings.IndexByte(s, '\n'); i != -1 && i < charsLeft { - w.writeString(s[:i+1]) - return s[i+1:] - } - - for i := charsLeft - 1; i >= 0; i-- { - if s[i] == ' ' { - w.writeString(s[:i]) - w.writeString("\r\n ") - return s[i+1:] - } - } - - // We could not insert a newline cleanly so look for a space or a newline - // even if it is after the limit. - for i := 75; i < len(s); i++ { - if s[i] == ' ' { - w.writeString(s[:i]) - w.writeString("\r\n ") - return s[i+1:] - } - if s[i] == '\n' { - w.writeString(s[:i+1]) - return s[i+1:] - } - } - - // Too bad, no space or newline in the whole string. Just write everything. - w.writeString(s) - return "" -} - -func (w *messageWriter) writeHeaders(h map[string][]string) { - if w.depth == 0 { - for k, v := range h { - if k != "Bcc" { - w.writeHeader(k, v...) - } - } - } else { - w.createPart(h) - } -} - -func (w *messageWriter) writeBody(f func(io.Writer) error, enc Encoding) { - var subWriter io.Writer - if w.depth == 0 { - w.writeString("\r\n") - subWriter = w.w - } else { - subWriter = w.partWriter - } - - if enc == Base64 { - wc := base64.NewEncoder(base64.StdEncoding, newBase64LineWriter(subWriter)) - w.err = f(wc) - wc.Close() - } else if enc == Unencoded { - w.err = f(subWriter) - } else { - wc := newQPWriter(subWriter) - w.err = f(wc) - wc.Close() - } -} - -// As required by RFC 2045, 6.7. (page 21) for quoted-printable, and -// RFC 2045, 6.8. (page 25) for base64. -const maxLineLen = 76 - -// base64LineWriter limits text encoded in base64 to 76 characters per line -type base64LineWriter struct { - w io.Writer - lineLen int -} - -func newBase64LineWriter(w io.Writer) *base64LineWriter { - return &base64LineWriter{w: w} -} - -func (w *base64LineWriter) Write(p []byte) (int, error) { - n := 0 - for len(p)+w.lineLen > maxLineLen { - w.w.Write(p[:maxLineLen-w.lineLen]) - w.w.Write([]byte("\r\n")) - p = p[maxLineLen-w.lineLen:] - n += maxLineLen - w.lineLen - w.lineLen = 0 - } - - w.w.Write(p) - w.lineLen += len(p) - - return n + len(p), nil -} - -// Stubbed out for testing. -var now = time.Now |