Example #1
1
func mediaTypeOrDefault(header textproto.MIMEHeader) string {
	mediaType, _, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil {
		return "application/octet-stream"
	}
	return mediaType
}
Example #2
1
func checkContentType(h textproto.MIMEHeader, expected string) error {
	ctype := h.Get("Content-Type")
	if ctype != expected {
		return errors.Errorf("expected Content-Type %q, got %q", expected, ctype)
	}
	return nil
}
Example #3
0
// Date parses the Date header field.
func Date(h textproto.MIMEHeader) (time.Time, error) {
	hdr := h.Get("Date")
	if hdr == "" {
		return time.Time{}, ErrHeaderNotPresent
	}
	return parseDate(hdr)
}
Example #4
0
func writeJSONPart(writer *multipart.Writer, contentType string, body Body, compressed bool) (err error) {
	bytes, err := json.Marshal(body)
	if err != nil {
		return err
	}
	if len(bytes) < kMinCompressedJSONSize {
		compressed = false
	}

	partHeaders := textproto.MIMEHeader{}
	partHeaders.Set("Content-Type", contentType)
	if compressed {
		partHeaders.Set("Content-Encoding", "gzip")
	}
	part, err := writer.CreatePart(partHeaders)
	if err != nil {
		return err
	}

	if compressed {
		gz := gzip.NewWriter(part)
		_, err = gz.Write(bytes)
		gz.Close()
	} else {
		_, err = part.Write(bytes)
	}
	return
}
Example #5
0
func newEntity(h textproto.MIMEHeader, r io.Reader, shared *sharedData) (*Entity, error) {
	contType := h.Get("Content-Type")
	if contType == "" {
		return &Entity{
			Header: h,
			body:   &SinglepartBody{Reader: r},
			shared: shared,
		}, nil
	}

	mediaType, params, err := mime.ParseMediaType(contType)
	if err != nil {
		return nil, err
	}

	if !strings.HasPrefix(mediaType, "multipart/") {
		return &Entity{
			Header: h,
			body:   &SinglepartBody{Reader: r},
			shared: shared,
		}, nil
	}

	boundary, ok := params["boundary"]
	if !ok {
		return nil, fmt.Errorf("Boundary not found in Content-Type field: %v", contType)
	}

	return &Entity{
		Header: h,
		body:   &MultipartBody{multipart.NewReader(r, boundary)},
		shared: shared,
	}, nil
}
Example #6
0
// Very Useful for AJAX Validater that require server-side validation
func (f *Form) ValidateSingle(name, value, mime string) error {
	values := Values{
		name: []string{value},
	}
	mimeheader := textproto.MIMEHeader{}
	mimeheader.Add("Content-Type", mime)
	files := FileHeaders{
		name: []*multipart.FileHeader{&multipart.FileHeader{
			Header: mimeheader}},
	}

	val := &Validation{values, files, true, CurVal("")}

	for _, field := range f.fields {
		switch t := field.(type) {
		case Label:
			continue
		default:
			if t.GetName() == name {
				return t.Validate(val)
			}
		}
	}
	return FormError(f.lang["ErrFieldDoesNotExist"])
}
Example #7
0
// Writes a revision to a MIME multipart writer, encoding large attachments as separate parts.
func (db *Database) WriteMultipartDocument(body Body, writer *multipart.Writer, compress bool) {
	// First extract the attachments that should follow:
	following := []attInfo{}
	for name, value := range BodyAttachments(body) {
		meta := value.(map[string]interface{})
		var info attInfo
		info.contentType, _ = meta["content_type"].(string)
		info.data, _ = decodeAttachment(meta["data"])
		if info.data != nil && len(info.data) > kMaxInlineAttachmentSize {
			info.name = name
			following = append(following, info)
			delete(meta, "data")
			meta["follows"] = true
		}
	}

	// Write the main JSON body:
	writeJSONPart(writer, "application/json", body, compress)

	// Write the following attachments
	for _, info := range following {
		partHeaders := textproto.MIMEHeader{}
		if info.contentType != "" {
			partHeaders.Set("Content-Type", info.contentType)
		}
		partHeaders.Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", info.name))
		part, _ := writer.CreatePart(partHeaders)
		part.Write(info.data)
	}
}
Example #8
0
//handleEventMsg processes event messages received from Freeswitch.
func (client *Client) handleEventMsg(resp textproto.MIMEHeader) error {
	event := make(map[string]string)
	//Check that Content-Length is numeric.
	_, err := strconv.Atoi(resp.Get("Content-Length"))
	if err != nil {
		log.Print(logPrefix, "Invalid Content-Length", err)
		return err
	}

	for {
		//Read each line of the event and store into map.
		line, err := client.eventConn.ReadLine()
		if err != nil {
			log.Print(logPrefix, "Event Read failure: ", err)
			return err
		}

		if line == "" { //Empty line means end of event.
			client.sendEvent(event)
			return err
		}

		parts := strings.Split(line, ": ") //Split "Key: value"
		key := parts[0]
		value, err := url.QueryUnescape(parts[1])

		if err != nil {
			log.Print(logPrefix, "Parse failure: ", err)
			return err
		}

		event[key] = value
	}
}
Example #9
0
// Adds a new part to the given multipart writer, containing the given revision.
// The revision will be written as a nested multipart body if it has attachments.
func (db *Database) WriteRevisionAsPart(revBody Body, isError bool, compressPart bool, writer *multipart.Writer) error {
	partHeaders := textproto.MIMEHeader{}
	docID, _ := revBody["_id"].(string)
	revID, _ := revBody["_rev"].(string)
	if len(docID) > 0 {
		partHeaders.Set("X-Doc-ID", docID)
		partHeaders.Set("X-Rev-ID", revID)
	}

	if hasInlineAttachments(revBody) {
		// Write as multipart, including attachments:
		// OPT: Find a way to do this w/o having to buffer the MIME body in memory!
		var buffer bytes.Buffer
		docWriter := multipart.NewWriter(&buffer)
		contentType := fmt.Sprintf("multipart/related; boundary=%q",
			docWriter.Boundary())
		partHeaders.Set("Content-Type", contentType)
		db.WriteMultipartDocument(revBody, docWriter, compressPart)
		docWriter.Close()
		content := bytes.TrimRight(buffer.Bytes(), "\r\n")

		part, err := writer.CreatePart(partHeaders)
		if err == nil {
			_, err = part.Write(content)
		}
		return err
	} else {
		// Write as JSON:
		contentType := "application/json"
		if isError {
			contentType += `; error="true"`
		}
		return writeJSONPart(writer, contentType, revBody, compressPart)
	}
}
Example #10
0
File: smtp.go Project: bfix/gospel
// CreateMailMessage creates a (plain) SMTP email with body and
// optional attachments.
func CreateMailMessage(body []byte, att []*MailAttachment) ([]byte, error) {
	buf := new(bytes.Buffer)
	wrt := multipart.NewWriter(buf)
	buf.WriteString(
		"MIME-Version: 1.0\n" +
			"Content-Type: multipart/mixed;\n" +
			" boundary=\"" + wrt.Boundary() + "\"\n\n" +
			"This is a multi-part message in MIME format.\n")
	hdr := textproto.MIMEHeader{}
	hdr.Set("Content-Type", "text/plain; charset=ISO-8859-15")
	hdr.Set("Content-Transfer-Encoding", "utf-8")
	pw, err := wrt.CreatePart(hdr)
	if err != nil {
		return nil, err
	}
	pw.Write(body)

	for _, a := range att {
		pw, err = wrt.CreatePart(a.Header)
		if err != nil {
			return nil, err
		}
		pw.Write(a.Data)
	}
	wrt.Close()
	return buf.Bytes(), nil
}
func renderPartsToWriter(parts cloudInitParts, writer io.Writer) error {
	mimeWriter := multipart.NewWriter(writer)
	defer mimeWriter.Close()

	writer.Write([]byte(fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\n", mimeWriter.Boundary())))

	for _, part := range parts {
		header := textproto.MIMEHeader{}
		if part.ContentType == "" {
			header.Set("Content-Type", "text/plain")
		} else {
			header.Set("Content-Type", part.ContentType)
		}

		if part.Filename != "" {
			header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, part.Filename))
		}

		if part.MergeType != "" {
			header.Set("X-Merge-Type", part.MergeType)
		}

		partWriter, err := mimeWriter.CreatePart(header)
		if err != nil {
			return err
		}

		_, err = partWriter.Write([]byte(part.Content))
		if err != nil {
			return err
		}
	}

	return nil
}
Example #12
0
// parseMIMEParts will recursively walk a MIME entity and return a []mime.Part containing
// each (flattened) mime.Part found.
// It is important to note that there are no limits to the number of recursions, so be
// careful when parsing unknown MIME structures!
func parseMIMEParts(hs textproto.MIMEHeader, b io.Reader) ([]*part, error) {
	var ps []*part
	// If no content type is given, set it to the default
	if _, ok := hs["Content-Type"]; !ok {
		hs.Set("Content-Type", defaultContentType)
	}
	ct, params, err := mime.ParseMediaType(hs.Get("Content-Type"))
	if err != nil {
		return ps, err
	}
	// If it's a multipart email, recursively parse the parts
	if strings.HasPrefix(ct, "multipart/") {
		if _, ok := params["boundary"]; !ok {
			return ps, ErrMissingBoundary
		}
		mr := multipart.NewReader(b, params["boundary"])
		for {
			var buf bytes.Buffer
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			}
			if err != nil {
				return ps, err
			}
			if _, ok := p.Header["Content-Type"]; !ok {
				p.Header.Set("Content-Type", defaultContentType)
			}
			subct, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
			if strings.HasPrefix(subct, "multipart/") {
				sps, err := parseMIMEParts(p.Header, p)
				if err != nil {
					return ps, err
				}
				ps = append(ps, sps...)
			} else {
				// Otherwise, just append the part to the list
				// Copy the part data into the buffer
				if _, err := io.Copy(&buf, p); err != nil {
					return ps, err
				}
				ps = append(ps, &part{body: buf.Bytes(), header: p.Header})
			}
		}
	} else {
		// If it is not a multipart email, parse the body content as a single "part"
		var buf bytes.Buffer
		if _, err := io.Copy(&buf, b); err != nil {
			return ps, err
		}
		ps = append(ps, &part{body: buf.Bytes(), header: hs})
	}
	return ps, nil
}
Example #13
0
func appendPart(w *multipart.Writer, headers func(h textproto.MIMEHeader), body string) {
	if body == "" {
		return
	}

	h := textproto.MIMEHeader{}
	h.Set("Content-Transfer-Encoding", "quoted-printable")
	headers(h)
	partW, err := w.CreatePart(h)
	log.Panice(err, "create MIME part")
	quoW := quotedprintable.NewWriter(partW)
	defer quoW.Close()
	io.WriteString(quoW, body)
}
Example #14
0
//handleAPIMsg processes API response messages received from Freeswitch.
func (client *Client) handleAPIMsg(resp textproto.MIMEHeader) error {
	//Check that Content-Length is numeric.
	length, err := strconv.Atoi(resp.Get("Content-Length"))
	if err != nil {
		log.Print(logPrefix, "Invalid Content-Length", err)
		client.sendCmdRes(cmdRes{body: "", err: err}, true)
		return err
	}

	//Read Content-Length bytes into a buffer and convert to string.
	buf := make([]byte, length)
	if _, err = io.ReadFull(client.eventConn.R, buf); err != nil {
		log.Print(logPrefix, "API Read failure: ", err)
	}
	client.sendCmdRes(cmdRes{body: string(buf), err: err}, true)
	return err
}
Example #15
0
func createFormFile(writer *multipart.Writer, fieldname, filename string) {
	// Try to open the file.
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// Create a new form-data header with the provided field name and file name.
	// Determine Content-Type of the file by its extension.
	h := textproto.MIMEHeader{}
	h.Set("Content-Disposition", fmt.Sprintf(
		`form-data; name="%s"; filename="%s"`,
		escapeQuotes(fieldname),
		escapeQuotes(filepath.Base(filename)),
	))
	h.Set("Content-Type", "application/octet-stream")
	if ct := mime.TypeByExtension(filepath.Ext(filename)); ct != "" {
		h.Set("Content-Type", ct)
	}
	part, err := writer.CreatePart(h)
	if err != nil {
		panic(err)
	}

	// Copy the content of the file we have opened not reading the whole
	// file into memory.
	_, err = io.Copy(part, file)
	if err != nil {
		panic(err)
	}
}
Example #16
0
func TestSubjectHeaderWithExistingQuotes(t *testing.T) {
	m := simpleMessage()
	m.Subject = `"Hi World"`
	buf := new(bytes.Buffer)
	header := textproto.MIMEHeader{}

	_, err := m.bytes(buf, header)
	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expected := `\"Hi World\"`
	if sub := header.Get("Subject"); sub != expected {
		t.Logf(`Expected Subject to be "%s" but got "%s"`, expected, sub)
		t.Fail()
	}
}
Example #17
0
File: nntp.go Project: ZiRo-/srndv2
// store message, unpack attachments, register with daemon, send to daemon for federation
// in that order
func (self *nntpConnection) storeMessage(daemon *NNTPDaemon, hdr textproto.MIMEHeader, body io.Reader) (err error) {
	var f io.WriteCloser
	msgid := getMessageID(hdr)
	if msgid == "" {
		// drop, invalid header
		log.Println(self.name, "dropping message with invalid mime header, no message-id")
		_, err = io.Copy(Discard, body)
		return
	} else if ValidMessageID(msgid) {
		f = daemon.store.CreateFile(msgid)
	} else {
		// invalid message-id
		log.Println(self.name, "dropping message with invalid message-id", msgid)
		_, err = io.Copy(Discard, body)
		return
	}
	if f == nil {
		// could not open file, probably already storing it from another connection
		log.Println(self.name, "discarding duplicate message")
		_, err = io.Copy(Discard, body)
		return
	}
	path := hdr.Get("Path")
	hdr.Set("Path", daemon.instance_name+"!"+path)
	// now store attachments and article
	err = writeMIMEHeader(f, hdr)
	if err == nil {
		err = daemon.store.ProcessMessageBody(f, hdr, body)
		if err == nil {
			// tell daemon
			daemon.loadFromInfeed(msgid)
		}
	}
	f.Close()
	if err != nil {
		// clean up
		if ValidMessageID(msgid) {
			DelFile(daemon.store.GetFilename(msgid))
		}
	}
	return
}
Example #18
0
File: util.go Project: ZiRo-/srndv2
// get a message id from a mime header
// checks many values
func getMessageID(hdr textproto.MIMEHeader) (msgid string) {
	msgid = hdr.Get("Message-Id")
	if msgid == "" {
		msgid = hdr.Get("Message-ID")
	}
	if msgid == "" {
		msgid = hdr.Get("message-id")
	}
	if msgid == "" {
		msgid = hdr.Get("MESSAGE-ID")
	}
	return
}
Example #19
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
}
Example #20
0
func TestPostBeacon(t *testing.T) {
	imgData = strings.Replace(imgData, "\n", "", -1)
	imgBytes, err := hex.DecodeString(imgData)
	if err != nil {
		t.Fatalf("Unable to parse image data.")
	}
	body := &bytes.Buffer{}
	partWriter := multipart.NewWriter(body)
	jsonHeader := textproto.MIMEHeader{}
	jsonHeader.Add("Content-Type", "application/json")
	jsonWriter, err := partWriter.CreatePart(jsonHeader)
	io.WriteString(jsonWriter, jsonData)
	imgHeader := textproto.MIMEHeader{}
	imgHeader.Add("Content-Type", "img/jpeg")
	imgWriter, err := partWriter.CreatePart(imgHeader)
	imgWriter.Write(imgBytes)
	partWriter.Close()
	req, _ := http.NewRequest("POST", "http://localhost:8765/beacon", body)
	req.Header.Add("Content-Type", partWriter.FormDataContentType())
	req.SetBasicAuth("1", "0")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Error(err.Error())
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Error(err.Error())
	}
	if !strings.Contains(string(respBody), "id") {
		t.Fatalf("Response did not contain correct content: \n%s", string(respBody))
	}
}
Example #21
0
func HandleGetBeacon(w http.ResponseWriter, r *http.Request, id uint64, db *DBClient) {
	var viewerID int64
	viewerID, err := OptionalAuthenticate(w, r, db)
	beacon, err := db.GetThread(id)
	if err != nil {
		WriteErrorResp(w, err.Error(), DatabaseError)
		return
	}
	respBeaconMsg, err := ToRespBeaconMsg(w, beacon, viewerID, db)
	if err != nil {
		return
	}
	respJson, err := json.Marshal(respBeaconMsg)
	respBody := &bytes.Buffer{}
	partWriter := multipart.NewWriter(respBody)
	jsonHeader := textproto.MIMEHeader{}
	jsonHeader.Add("Content-Type", "application/json")
	jsonWriter, err := partWriter.CreatePart(jsonHeader)
	if err != nil {
		WriteErrorResp(w, err.Error(), ServerError)
		return
	}
	jsonWriter.Write(respJson)
	imgHeader := textproto.MIMEHeader{}
	imgHeader.Add("Content-Type", "img/jpeg")
	imgWriter, err := partWriter.CreatePart(imgHeader)
	if err != nil {
		WriteErrorResp(w, err.Error(), ServerError)
		return
	}
	imgWriter.Write(beacon.Image)
	partWriter.Close()
	w.Header().Add("Content-Type", partWriter.FormDataContentType())
	w.Write(respBody.Bytes())
}
Example #22
0
File: email.go Project: eswdd/bosun
// parseMIMEParts will recursively walk a MIME entity and return a []mime.Part containing
// each (flattened) mime.Part found.
// It is important to note that there are no limits to the number of recursions, so be
// careful when parsing unknown MIME structures!
func parseMIMEParts(hs textproto.MIMEHeader, b io.Reader) ([]*part, error) {
	var ps []*part
	ct, params, err := mime.ParseMediaType(hs.Get("Content-Type"))
	if err != nil {
		return ps, err
	}
	if strings.HasPrefix(ct, "multipart/") {
		if _, ok := params["boundary"]; !ok {
			return ps, ErrMissingBoundary
		}
		mr := multipart.NewReader(b, params["boundary"])
		for {
			var buf bytes.Buffer
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			}
			if err != nil {
				return ps, err
			}
			subct, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
			if strings.HasPrefix(subct, "multipart/") {
				sps, err := parseMIMEParts(p.Header, p)
				if err != nil {
					return ps, err
				}
				ps = append(ps, sps...)
			} else {
				// Otherwise, just append the part to the list
				// Copy the part data into the buffer
				if _, err := io.Copy(&buf, p); err != nil {
					return ps, err
				}
				ps = append(ps, &part{body: buf.Bytes(), header: p.Header})
			}
		}
	}
	return ps, nil
}
Example #23
0
// Bytes converts the Email object to a []byte representation, including all needed MIMEHeaders, boundaries, etc.
func (m *Message) Bytes() ([]byte, error) {
	// TODO: better guess buffer size
	buff := bytes.NewBuffer(make([]byte, 0, 4096))

	headers := m.msgHeaders()
	w := multipart.NewWriter(buff)
	// TODO: determine the content type based on message/attachment mix.
	headers.Set("Content-Type", "multipart/mixed;\r\n boundary="+w.Boundary())
	headerToBytes(buff, headers)
	io.WriteString(buff, "\r\n")

	// Start the multipart/mixed part
	fmt.Fprintf(buff, "--%s\r\n", w.Boundary())
	header := textproto.MIMEHeader{}
	// Check to see if there is a Text or HTML field
	if len(m.Content) > 0 {
		subWriter := multipart.NewWriter(buff)
		// Create the multipart alternative part
		header.Set("Content-Type", fmt.Sprintf("multipart/alternative;\r\n boundary=%s\r\n", subWriter.Boundary()))
		// Write the header
		headerToBytes(buff, header)
		// Create the body sections
		if len(m.Content) > 0 {
			header.Set("Content-Type", fmt.Sprintf("%s; charset=UTF-8", m.ContentType))
			header.Set("Content-Transfer-Encoding", "quoted-printable")
			if _, err := subWriter.CreatePart(header); err != nil {
				return nil, err
			}
			// Write the text
			if err := quotePrintEncode(buff, []byte(m.Content)); err != nil {
				return nil, err
			}
		}

		if err := subWriter.Close(); err != nil {
			return nil, err
		}
	}
	// Create attachment part, if necessary
	for _, a := range m.Attachments {
		ap, err := w.CreatePart(a.Header)
		if err != nil {
			return nil, err
		}
		// Write the base64Wrapped content to the part
		base64Wrap(ap, a.Content)
	}
	if err := w.Close(); err != nil {
		return nil, err
	}
	return buff.Bytes(), nil
}
Example #24
0
// AddressList parses the named header field as a list of addresses.
func AddressList(header textproto.MIMEHeader, key string, utf8ReaderFactory UTF8ReaderFactory) (r []*Address, err error) {
	// h := make(map[string][]string)

	// vals := header[key]
	// if vals == nil {
	// 	return
	// }
	// var newDecodedVals []string
	// for _, val := range vals {
	// 	var newVal string
	// 	newVal, err = DecodeText(val, utf8ReaderFactory)
	// 	if err != nil {
	// 		return
	// 	}
	// 	newDecodedVals = append(newDecodedVals, newVal)
	// }
	// h[key] = newDecodedVals
	hdr := header.Get(key)
	if hdr == "" {
		return nil, ErrHeaderNotPresent
	}

	return newAddrParser(hdr, utf8ReaderFactory).parseAddressList()
}
Example #25
0
//newEvent build event
func newEvent(data *textproto.MIMEHeader) (*AMIEvent, error) {
	if data.Get("Event") == "" {
		return nil, errNotEvent
	}
	ev := &AMIEvent{data.Get("Event"), strings.Split(data.Get("Privilege"), ","), make(map[string]string)}
	for k, v := range *data {
		if k == "Event" || k == "Privilege" {
			continue
		}
		ev.Params[k] = v[0]
	}
	return ev, nil
}
Example #26
0
//newResponse build a response for action
func newResponse(data *textproto.MIMEHeader) (*AMIResponse, error) {
	if data.Get("Response") == "" {
		return nil, errors.New("Not Response")
	}
	response := &AMIResponse{"", "", make(map[string]string)}
	for k, v := range *data {
		if k == "Response" {
			continue
		}
		response.Params[k] = v[0]
	}
	response.ID = data.Get("Actionid")
	response.Status = data.Get("Response")
	return response, nil
}
func renderPartsToWriter(parts cloudInitParts, writer io.Writer) error {
	mimeWriter := multipart.NewWriter(writer)
	defer mimeWriter.Close()

	// we need to set the boundary explictly, otherwise the boundary is random
	// and this causes terraform to complain about the resource being different
	if err := mimeWriter.SetBoundary("MIMEBOUNDARY"); err != nil {
		return err
	}

	writer.Write([]byte(fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\n", mimeWriter.Boundary())))
	writer.Write([]byte("MIME-Version: 1.0\r\n"))

	for _, part := range parts {
		header := textproto.MIMEHeader{}
		if part.ContentType == "" {
			header.Set("Content-Type", "text/plain")
		} else {
			header.Set("Content-Type", part.ContentType)
		}

		header.Set("MIME-Version", "1.0")
		header.Set("Content-Transfer-Encoding", "7bit")

		if part.Filename != "" {
			header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, part.Filename))
		}

		if part.MergeType != "" {
			header.Set("X-Merge-Type", part.MergeType)
		}

		partWriter, err := mimeWriter.CreatePart(header)
		if err != nil {
			return err
		}

		_, err = partWriter.Write([]byte(part.Content))
		if err != nil {
			return err
		}
	}

	return nil
}
Example #28
0
func (handler *HttpHandler) ServeDataObj(obj *DataObj) {

	rng := handler.request.Header["Range"]
	objMime := handler.getObjMime(obj)

	lenStr := strconv.FormatInt(obj.Size(), 10)

	if len(rng) > 0 {
		rangeHeader := rng[0]

		byteRange := strings.Split(rangeHeader, "bytes=")

		if len(byteRange) == 2 && byteRange[0] == "" && byteRange[1] != "" {

			var outputBuffer RangeOutput

			byteRangeSplit := strings.Split(byteRange[1], ",")

			for _, rangeStr := range byteRangeSplit {

				rangeStrSplit := strings.Split(rangeStr, "-")
				if len(rangeStrSplit) == 2 {

					var convErr error
					var firstByteN int64
					var lastByteN int64

					firstByte := rangeStrSplit[0]
					lastByte := rangeStrSplit[1]

					// should we only get last bytes
					if firstByte == "" {
						if lastByteN, convErr = strconv.ParseInt(lastByte, 10, 64); convErr != nil {
							log.Print("Error parsing byte range")
							return
						}

						firstByteN = obj.Size() - lastByteN
						lastByteN = obj.Size() - 1
					} else if lastByte == "" {
						if firstByteN, convErr = strconv.ParseInt(firstByte, 10, 64); convErr != nil {
							log.Print("Error parsing byte range")
							return
						}

						lastByteN = obj.Size() - 1
					} else {
						if firstByteN, convErr = strconv.ParseInt(firstByte, 10, 64); convErr != nil {
							log.Print("Error parsing byte range")
							return
						}

						if lastByteN, convErr = strconv.ParseInt(lastByte, 10, 64); convErr != nil {
							log.Print("Error parsing byte range")
							return
						}
					}

					if byteData, err := obj.ReadBytes(firstByteN, int(lastByteN-firstByteN)+1); err == nil {

						outputBuffer = append(outputBuffer, RangeSegmentOutput{
							ContentRange: "bytes " + strconv.FormatInt(firstByteN, 10) + "-" + strconv.FormatInt(lastByteN, 10) + "/" + lenStr,
							ContentType:  objMime,
							ByteContent:  byteData,
						})

					} else {
						log.Print(err)
					}

				} else {
					log.Print("Error parsing byte range")
				}
			}

			if len(outputBuffer) > 1 {

				handler.response.Header().Set("Accept-Ranges", "bytes")
				//handler.response.Header().Set("Content-Length", outputBuffer.TotalLength())

				mpWriter := multipart.NewWriter(handler.response)

				handler.response.Header().Set("Content-Type", "multipart/byteranges; boundary="+mpWriter.Boundary())

				handler.response.WriteHeader(http.StatusPartialContent)

				for _, outputSegment := range outputBuffer {

					var headers textproto.MIMEHeader = make(textproto.MIMEHeader)

					headers.Add("Content-Type", outputSegment.ContentType)
					headers.Add("Content-Range", outputSegment.ContentRange)

					if writer, err := mpWriter.CreatePart(headers); err != nil {
						log.Print(err)
						continue
					} else {
						writer.Write(outputSegment.ByteContent)
					}
				}

			} else if len(outputBuffer) == 1 {
				handler.response.Header().Set("Content-Range", outputBuffer[0].ContentRange)
				handler.response.Header().Set("Accept-Ranges", "bytes")
				handler.response.Header().Set("Content-Length", strconv.Itoa(len(outputBuffer[0].ByteContent)))
				handler.response.Header().Set("Content-Type", outputBuffer[0].ContentType)

				handler.response.WriteHeader(http.StatusPartialContent)

				handler.response.Write(outputBuffer[0].ByteContent)
			}
		}

	} else {

		if handler.opts.Download || handler.query.Get("download") != "" {
			handler.response.Header().Set("Content-Disposition", "attachment; filename="+obj.Name())
			handler.response.Header().Set("Content-type", "application/octet-stream")
		} else {
			handler.response.Header().Set("Content-type", objMime)
		}

		handler.response.Header().Set("Accept-Ranges", "bytes")
		handler.response.Header().Set("Content-Length", lenStr)

		if readEr := obj.ReadChunk(1024000, func(chunk []byte) {
			handler.response.Write(chunk)
		}); readEr != nil {
			log.Print(readEr)

			handler.response.WriteHeader(http.StatusInternalServerError)
			handler.response.Write([]byte("Error: " + readEr.Error()))

		}
	}

}
Example #29
0
// Bytes converts the Email object to a []byte representation, including all needed MIMEHeaders, boundaries, etc.
func (e *Email) Bytes() ([]byte, error) {
	buff := &bytes.Buffer{}
	w := multipart.NewWriter(buff)
	// Set the appropriate headers (overwriting any conflicts)
	// Leave out Bcc (only included in envelope headers)
	e.Headers.Set("To", strings.Join(e.To, ","))
	if e.Cc != nil {
		e.Headers.Set("Cc", strings.Join(e.Cc, ","))
	}
	e.Headers.Set("From", e.From)
	e.Headers.Set("Subject", e.Subject)
	if len(e.ReadReceipt) != 0 {
		e.Headers.Set("Disposition-Notification-To", strings.Join(e.ReadReceipt, ","))
	}
	e.Headers.Set("MIME-Version", "1.0")
	e.Headers.Set("Content-Type", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary()))

	// Write the envelope headers (including any custom headers)
	if err := headerToBytes(buff, e.Headers); err != nil {
		return nil, fmt.Errorf("Failed to render message headers: %s", err)
	}
	// Start the multipart/mixed part
	fmt.Fprintf(buff, "--%s\r\n", w.Boundary())
	header := textproto.MIMEHeader{}
	// Check to see if there is a Text or HTML field
	if e.Text != "" || e.HTML != "" {
		subWriter := multipart.NewWriter(buff)
		// Create the multipart alternative part
		header.Set("Content-Type", fmt.Sprintf("multipart/alternative;\r\n boundary=%s\r\n", subWriter.Boundary()))
		// Write the header
		if err := headerToBytes(buff, header); err != nil {
			return nil, fmt.Errorf("Failed to render multipart message headers: %s", err)
		}
		// Create the body sections
		if e.Text != "" {
			header.Set("Content-Type", fmt.Sprintf("text/plain; charset=UTF-8"))
			header.Set("Content-Transfer-Encoding", "quoted-printable")
			if _, err := subWriter.CreatePart(header); err != nil {
				return nil, err
			}
			// Write the text
			if err := quotePrintEncode(buff, e.Text); err != nil {
				return nil, err
			}
		}
		if e.HTML != "" {
			header.Set("Content-Type", fmt.Sprintf("text/html; charset=UTF-8"))
			header.Set("Content-Transfer-Encoding", "quoted-printable")
			if _, err := subWriter.CreatePart(header); err != nil {
				return nil, err
			}
			// Write the text
			if err := quotePrintEncode(buff, e.HTML); err != nil {
				return nil, err
			}
		}
		if err := subWriter.Close(); err != nil {
			return nil, err
		}
	}
	// Create attachment part, if necessary
	for _, a := range e.Attachments {
		ap, err := w.CreatePart(a.Header)
		if err != nil {
			return nil, err
		}
		// Write the base64Wrapped content to the part
		base64Wrap(ap, a.Content)
	}
	if err := w.Close(); err != nil {
		return nil, err
	}
	return buff.Bytes(), nil
}
Example #30
0
func SendMailWithAttachments(host string, auth *smtp.Auth, from, subject string, to []string, msg []byte, atch Attachments) error {
	c, err := SMTPConnection(host, auth)
	if err != nil {
		return err
	}
	defer c.Quit()
	if err := c.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err := c.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := c.Data()
	if err != nil {
		return err
	}
	multiw := multipart.NewWriter(w)
	err = write(
		w,
		fmt.Sprintf("From: %s%s", from, CRLF),
		fmt.Sprintf("Subject: %s%s", subject, CRLF),
		fmt.Sprintf("To: %s%s", strings.Join(to, ","), CRLF),
	)
	if err != nil {
		return err
	}
	if atch != nil {
		err = write(
			w,
			fmt.Sprintf(`Content-Type: multipart/mixed; boundary="%s"%s`, multiw.Boundary(), CRLF),
			"--"+multiw.Boundary()+CRLF,
			"Content-Transfer-Encoding: quoted-printable",
		)
	} else {
		return write(w, strings.Repeat(CRLF, 4), string(msg), strings.Repeat(CRLF, 4))
	}
	// We write either the message, or 4*CRLF since SMTP supports files
	// being sent without an actual body.
	if msg != nil {
		err = write(w,
			fmt.Sprintf(
				"%s%s%s",
				strings.Repeat(CRLF, 2),
				msg,
				strings.Repeat(CRLF, 2),
			),
		)
		if err != nil {
			return err
		}
	} else {
		if err := write(w, strings.Repeat(CRLF, 4)); err != nil {
			return err
		}
	}
	for filename, file := range atch {
		ext := mime.TypeByExtension(filepath.Ext(filename))
		if ext == "" {
			ext = "text/plain"
		}

		h := textproto.MIMEHeader{}
		h.Add("Content-Type", ext)
		h.Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
		h.Add("Content-Transfer-Encoding", "base64")
		newpart, err := multiw.CreatePart(h)
		if err != nil {
			return err
		}
		buf := bytes.NewBuffer([]byte{})
		bcdr := NewBase64Email(buf, base64.StdEncoding)
		if _, err = io.Copy(bcdr, file); err != nil {
			return err
		}
		if err = bcdr.Close(); err != nil {
			return err
		}
		if _, err = io.Copy(newpart, buf); err != nil {
			return err
		}
	}
	if err = multiw.Close(); err != nil {
		return err
	}
	return w.Close()
}