/*
   * Parse the contents of this multipart message and create the
   * child body parts.
   */
  protected synchronized void parse() throws MessagingException {
    if (parsed) return;

    InputStream in = null;

    try {
      in = ds.getInputStream();
      if (!(in instanceof ByteArrayInputStream) && !(in instanceof BufferedInputStream))
        in = new BufferedInputStream(in);
    } catch (Exception ex) {
      throw new MessagingException("No inputstream from datasource");
    }

    String line;
    int bl = boundary.length();
    byte[] bndbytes = new byte[bl];
    boundary.getBytes(0, bl, bndbytes, 0);

    try {
      /*
       * Skip any kind of junk until we get to the first
       * boundary line.
       */
      LineInputStream lin = new LineInputStream(in);
      while ((line = lin.readLine()) != null) {
        if (line.trim().equals(boundary)) break;
      }
      if (line == null) throw new MessagingException("Missing start boundary");

      /*
       * Read and process body parts until we see the
       * terminating boundary line (or EOF).
       */
      for (; ; ) {
        /*
         * Collect the headers for this body part.
         */
        InternetHeaders headers = new InternetHeaders(in);

        if (!in.markSupported()) throw new MessagingException("Stream doesn't support mark");

        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        int b;

        /*
         * Read and save the content bytes in buf.
         */
        while ((b = in.read()) >= 0) {
          if (b == '\r' || b == '\n') {
            /*
             * Found the end of a line, check whether the
             * next line is a boundary.
             */
            int i;
            in.mark(bl + 4 + 1); // "4" for possible "--\r\n"
            if (b == '\r' && in.read() != '\n') {
              in.reset();
              in.mark(bl + 4);
            }
            // read bytes, matching against the boundary
            for (i = 0; i < bl; i++) if (in.read() != bndbytes[i]) break;
            if (i == bl) {
              int b2 = in.read();
              // check for end of line
              if (b2 == '\n') break; // got it!  break out of the while loop
              if (b2 == '\r') {
                in.mark(1);
                if (in.read() != '\n') in.reset();
                break; // got it!  break out of the while loop
              }
            }
            // failed to match, reset and proceed normally
            in.reset();
          }
          buf.write(b);
        }

        /*
         * Create a SunV3BodyPart to represent this body part.
         */
        SunV3BodyPart body = new SunV3BodyPart(headers, buf.toByteArray());
        addBodyPart(body);
        if (b < 0) break;
      }
    } catch (IOException e) {
      throw new MessagingException("IO Error"); // XXX
    }

    parsed = true;
  }