func parseParts(parent *Part, reader *bufio.Reader) error {
	firstRecursion := parent.Parent == nil
	// Loop over MIME boundaries.
	br := newBoundaryReader(reader, parent.Boundary)
	for indexPartID := 1; true; indexPartID++ {
		next, err := br.Next()
		if err != nil && errors.Cause(err) != io.EOF {
			return err
		}
		if !next {
			break
		}
		p := &Part{}
		// Set this Part's PartID, indicating its position within the MIME Part tree.
		if firstRecursion {
			p.PartID = strconv.Itoa(indexPartID)
		} else {
			p.PartID = parent.PartID + "." + strconv.Itoa(indexPartID)
		}
		// Look for part header.
		bbr := bufio.NewReader(br)
		err = p.setupHeaders(bbr, "")
		if errors.Cause(err) == errEmptyHeaderBlock {
			// Empty header probably means the part didn't use the correct trailing "--" syntax to
			// close its boundary.
			if _, err = br.Next(); err != nil {
				if errors.Cause(err) == io.EOF || strings.HasSuffix(err.Error(), "EOF") {
					// There are no more Parts. The error must belong to the parent, because this
					// part doesn't exist.
					parent.addWarning(ErrorMissingBoundary, "Boundary %q was not closed correctly",
						parent.Boundary)
					break
				}
				// The error is already wrapped with a stack, so only adding a message here.
				// TODO: Once `errors` releases a version > v0.8.0, change to use errors.WithMessagef()
				return errors.WithMessage(err, fmt.Sprintf("error at boundary %v", parent.Boundary))
			}
		} else if err != nil {
			return err
		}
		// Insert this Part into the MIME tree.
		parent.AddChild(p)
		if p.Boundary == "" {
			// Content is text or data, decode it.
			if err := p.decodeContent(bbr); err != nil {
				return err
			}
		} else {
			// Content is another multipart.
			err = parseParts(p, bbr)
			if err != nil {
				return err
			}
		}
	}
	// Store any content following the closing boundary marker into the epilogue.
	epilogue, err := ioutil.ReadAll(reader)
	if err != nil {
		return errors.WithStack(err)
	}
	parent.Epilogue = epilogue
	// If a Part is "multipart/" Content-Type, it will have .0 appended to its PartID
	// i.e. it is the root of its MIME Part subtree.
	if !firstRecursion {
		parent.PartID += ".0"
	}
	return nil
}
func parseParts(parent *Part, reader *bufio.Reader) error {
	firstRecursion := parent.Parent == nil
	
	br := newBoundaryReader(reader, parent.Boundary)
	for indexPartID := 1; true; indexPartID++ {
		next, err := br.Next()
		if err != nil && errors.Cause(err) != io.EOF {
			return err
		}
		if !next {
			break
		}
		p := &Part{}
		
		if firstRecursion {
			p.PartID = strconv.Itoa(indexPartID)
		} else {
			p.PartID = parent.PartID + "." + strconv.Itoa(indexPartID)
		}
		
		bbr := bufio.NewReader(br)
		err = p.setupHeaders(bbr, "")
		if errors.Cause(err) == errEmptyHeaderBlock {
			
			
			if _, err = br.Next(); err != nil {
				if errors.Cause(err) == io.EOF || strings.HasSuffix(err.Error(), "EOF") {
					
					
					parent.addWarning(ErrorMissingBoundary, "Boundary %q was not closed correctly",
						parent.Boundary)
					break
				}
				
				
				return errors.WithMessage(err, fmt.Sprintf("error at boundary %v", parent.Boundary))
			}
		} else if err != nil {
			return err
		}
		
		parent.AddChild(p)
		if p.Boundary == "" {
			
			if err := p.decodeContent(bbr); err != nil {
				return err
			}
		} else {
			
			err = parseParts(p, bbr)
			if err != nil {
				return err
			}
		}
	}
	
	epilogue, err := ioutil.ReadAll(reader)
	if err != nil {
		return errors.WithStack(err)
	}
	parent.Epilogue = epilogue
	
	
	if !firstRecursion {
		parent.PartID += ".0"
	}
	return nil
}
func parseParts ( parent * Part , reader * bufio . Reader ) error { firstRecursion := parent . Parent == nil // Loop over MIME boundaries. br := newBoundaryReader ( reader , parent . Boundary ) for indexPartID := 1 ; true ; indexPartID ++ { next , err := br . Next ( ) if err != nil && errors . Cause ( err ) != io . EOF { return err } if ! next { break } p := & Part { } // Set this Part's PartID, indicating its position within the MIME Part tree. if firstRecursion { p . PartID = strconv . Itoa ( indexPartID ) } else { p . PartID = parent . PartID + " " + strconv . Itoa ( indexPartID ) } // Look for part header. bbr := bufio . NewReader ( br ) err = p . setupHeaders ( bbr , " " ) if errors . Cause ( err ) == errEmptyHeaderBlock { // Empty header probably means the part didn't use the correct trailing "--" syntax to // close its boundary. if _ , err = br . Next ( ) ; err != nil { if errors . Cause ( err ) == io . EOF || strings . HasSuffix ( err . Error ( ) , " " ) { // There are no more Parts. The error must belong to the parent, because this // part doesn't exist. parent . addWarning ( ErrorMissingBoundary , " " , parent . Boundary ) break } // The error is already wrapped with a stack, so only adding a message here. // TODO: Once `errors` releases a version > v0.8.0, change to use errors.WithMessagef() return errors . WithMessage ( err , fmt . Sprintf ( " " , parent . Boundary ) ) } } else if err != nil { return err } // Insert this Part into the MIME tree. parent . AddChild ( p ) if p . Boundary == " " { // Content is text or data, decode it. if err := p . decodeContent ( bbr ) ; err != nil { return err } } else { // Content is another multipart. err = parseParts ( p , bbr ) if err != nil { return err } } } // Store any content following the closing boundary marker into the epilogue. epilogue , err := ioutil . ReadAll ( reader ) if err != nil { return errors . WithStack ( err ) } parent . Epilogue = epilogue // If a Part is "multipart/" Content-Type, it will have .0 appended to its PartID // i.e. it is the root of its MIME Part subtree. if ! firstRecursion { parent . PartID += " " } return nil }
// parseParts recursively parses a MIME multipart document and sets each Parts PartID.
parseParts recursively parses a MIME multipart document and sets each Parts PartID .