[mel-base-devel] mel.mime:parts not working properly for rfc 2822 (reading from a file)

Jochen Schmidt js at crispylogics.com
Sun Jan 24 02:04:13 UTC 2010


Am 24.01.2010 um 01:00 schrieb Fred Gibson:

> Hi Jochen,
> 
> Your fix works great for text/plain and multipart/alternative where
> the same body tag is used throughout the message.  The problem happens
> when you have a multipart/mixed structure where there is more than one
> boundary in the message.  So what I did in the rewrite of
> read-multipart-body-1 (RMB1) is in the case of a mixed type, read just
> beyond the first boundary which can be ignored, then recurse on RMB1
> again to deal with only the boundaries that matter by reading each one
> in at the top of a message section and then sending it to scan rather
> than trying to use the boundary identified in the message header, thus
> allowing for many boundaries.   I realize it is pretty brute force,
> but it works flawlessly so far.  It made more sense to me to deal with
> the multiple tag issue in RMB1.  Is there a more elegant solution to
> this?  (I've included a sample shortened version of the mixed
> structure below so you can see the varying boundary issue. This is the
> case for any mail with an attachment I think.)


I've checked the example - it is not an issue with RMB1 but with SFBT; believe me :-). Your example exposed another bug in that the content-type header wasn't recognized because SFBT left a newline in the stream.

after a boundary is matched one still has to scan to the end of the line:

(loop while (case (peek) ((#\return #\linefeed) t)
                                (otherwise nil))
                        do (skip))

After this change and still the original RMB1 I get this bodystructure:

(((:TEXT :PLAIN (:CHARSET "ISO-8859-1") NIL NIL NIL 173 8 NIL NIL NIL)
  (:TEXT :HTML (:CHARSET "ISO-8859-1") NIL NIL :QUOTED-PRINTABLE 155 5 NIL NIL NIL)
  :ALTERNATIVE
  (:BOUNDARY "000e0cd1465866ab51047b429ec8")
  NIL
  NIL)
 (:APPLICATION :PDF (:CHARSET "us-ascii" :NAME "Invoice-2290.pdf") NIL NIL :BASE64 125 2 NIL NIL NIL)
 :MIXED
 (:BOUNDARY "000e0cd1465866ab58047b429eca")
 NIL
 NIL)

Here is the final SFBT:

(defun scan-forward-boundary-tag (in-stream boundary)
  (let ((tag (concatenate 'string "--" boundary))
        (match 0)
        (octets 0)
        (lines 0)
        (line-ending-octets 0))
    (flet ((peek ()
	     (peek-char nil in-stream))
           (skip () (read-char in-stream))
	   (consume ()
	     (prog1
		 (read-char in-stream)
	       (incf octets))))
	     (tagbody
              init (let ((c (peek)))
                     (if (char= c #\-)
                       (go possible-boundary)
                       (go start)))
	      start (let ((c (peek)))
		      (case c
			(#\return (skip) (go cr))
			(#\linefeed (skip) (go lf))
			(otherwise (consume) (go start))))
		
	      lf (setf line-ending-octets 1) (go newline)
		
	      cr 
		(let ((c (peek)))
		  (case c
		    (#\linefeed (setf line-ending-octets 2)
                                (skip) (go newline))
		    (otherwise
                     (setf line-ending-octets 1)
                     (go newline))))
		
	      newline 
                (let ((c (peek)))
                  (case c
                    (#\- (go possible-boundary))
                    (otherwise (incf octets line-ending-octets)
                               (incf lines)
                               (setf line-ending-octets 0)
                               (go start))))

              possible-boundary
                  (if (= match (length tag))
                    (go boundary-matched)
                    (let ((c (peek)))
                      (cond ((char= c (char tag match))
                             (skip) (incf match)(go possible-boundary))
                            (t (incf octets (+ line-ending-octets match))
                               (setf match 0 line-ending-octets 0)
                               (incf lines)
                               (go start)))))
              boundary-matched
                  (let ((c (peek)))
                    (case c
                      (#\- (skip)
                           (case c
                             (#\- (go end-boundary))
                             (otherwise (go boundary))))
                      (otherwise (go boundary))))
             
              boundary
                  (loop until (case (peek) ((#\return #\linefeed :eof) t)
                                (otherwise nil))
                        do (skip))
                  (loop while (case (peek) ((#\return #\linefeed) t)
                                (otherwise nil))
                        do (skip))
                  (return-from scan-forward-boundary-tag
                    (values octets lines nil))
                  
              end-boundary
                   (loop until (case (peek) ((#\return #\linefeed #\newline :eof) t)
                                 (otherwise nil))
                         do (skip))
                  (return-from scan-forward-boundary-tag
                    (values octets lines t))
                   ))))

Does that work for you?

(The EOF handling is still borked, but it should work - I'll fix that tomorrow)


ciao,
Jochen

-- 
Jochen Schmidt 
CRISPYLOGICS
Uhlandstr. 9, 90408 Nuremberg

Fon +49 (0)911 517 999 82
Fax +49 (0)911 517 999 83

mailto:(format nil "~(~36r@~36r.~36r~)" 870180 1680085828711918828 16438) http://www.crispylogics.com





More information about the mel-base-devel mailing list