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

Fred Gibson fred at streamfocus.com
Sat Jan 23 09:44:01 UTC 2010


I had to rewrite a good portion of read-multipart-body-1 to get the
parts to parse correctly.  I've tested this with text/plain,
multipart/alternative and multipart/mixed, and all parsed correctly.
Here is the diff from my git commit:

commit 87842c16b7021a28f776fb952535c43426ba55d6
Author: Fred Gibson <fred at streamfocus.com>
Date:   Sat Jan 23 01:28:13 2010 -0800

    revised mel-base read-multipart-body-1 to work with alternative
and mixed multipart mime types

diff --git a/lib/mel-base_0.9-2/multiparts.lisp
b/lib/mel-base_0.9-2/multiparts.lisp
index 7c1e7f1..ee30f88 100644
--- a/lib/mel-base_0.9-2/multiparts.lisp
+++ b/lib/mel-base_0.9-2/multiparts.lisp
@@ -286,41 +286,58 @@
 (defun compute-bodystructure (message)
   (compute-bodystructure-using-folder (folder message) message))

-(defun read-multipart-body-1 (part stream)
-  (let ((boundary (boundary-tag part)))
-    (let (parts
-	  last-part)
-      (loop
-       (multiple-value-bind (octets lines endp)
-	   (scan-forward-boundary-tag stream boundary)
-	 (when last-part
-	   #+nil (incf (seventh last-part) octets)
-	   (setf (seventh last-part) octets)
-	   (setf (eighth last-part) lines)
-	   (setf last-part nil))
-	 (cond (endp
-		; (format t "End tag of boundary=~A~%" boundary)
-		(multiple-value-bind (super sub params)
-		    (content-type part)
-		  (declare (ignore super))
-		  (let ((result `(,@(nreverse parts) ,sub ,params nil nil)))
-		    ; (format t "Multipart-Structure: ~A~%" result)
-		    (return result))))
-	       (t
-		(multiple-value-bind (headers hoctets) (read-rfc2822-header stream)
-		 ; (format t "Headers read ~A" hoctets)
-		  (let ((content-type (or (cdr (assoc :content-type headers))
-					  "text/plain")))
-		    (multiple-value-bind (super sub params) (parse-content-type content-type)
-		      (declare (ignore params))
-		    (let ((next-part (make-instance (if (eq super :multipart)
-							(multipart-type-class sub)
-							'simple-part)
-						    :header-fields (or headers
-								       '((:content-type . "text/plain"))))))
-		    (if (eq super :multipart)
-			(push (read-multipart-body-1 next-part stream) parts)
-			(push (setf last-part (read-simple-body next-part)) parts)))))))))))))
+(defun read-multipart-body-1 (part stream &key recurse?)
+  (multiple-value-bind (p-super p-sub p-params)(content-type part)
+    (declare (ignore p-super))
+    (flet ((build-return (parts)
+             `(,@(nreverse parts) ,p-sub ,p-params nil nil)))
+      (let (parts
+            last-part
+            boundary)
+        (loop
+           (multiple-value-bind (headers hoctets) (read-rfc2822-header stream)
+             (declare (ignore hoctets))
+             (let ((content-type (or (cdr (assoc :content-type headers))
+                                     "text/plain"))
+                   (boundary-read
+                    (let ((assoc-hdr
+                           (assoc "--" headers
+                                  :test #'string=
+                                  :key (lambda (x) (let ((nm (symbol-name x)))
+                                                     (when (> (length nm) 2)
+                                                       (let ((a (char nm 0))
+                                                             (b (char nm 1)))
+                                                         (concatenate
'string (list a b)))))))))
+                      (when assoc-hdr
+                        (string-downcase (string-left-trim "-" (car
assoc-hdr)))))))
+               (setf boundary (or boundary-read boundary))
+               (multiple-value-bind (super sub params)
(parse-content-type content-type)
+                 (declare (ignore params))
+                 (when (and (eq p-sub :mixed) (not recurse?))
+                   (return (append (read-multipart-body-1 part stream
:recurse? t)
+                                   (build-return
(read-multipart-body-1 part stream :recurse? t)))))
+                 (let ((next-part (make-instance
+                                   (if (eq super :multipart)
+                                       (multipart-type-class sub)
+                                       'simple-part)
+                                   :header-fields (or headers
'((:content-type . "text/plain"))))))
+                   (if (eq super :multipart)
+                       (progn
+                         (setf last-part (read-simple-body next-part))
+                         (push (read-multipart-body-1 next-part stream) parts))
+                       (push (setf last-part (read-simple-body
next-part)) parts))
+                   (multiple-value-bind (octets lines endp)
+                       (scan-forward-boundary-tag stream boundary)
+                     (when last-part
+                       #+nil (incf (seventh last-part) octets)
+                       (setf (seventh last-part) octets)
+                       (setf (eighth last-part) lines)
+                       (setf last-part nil))
+                     (when endp ; (format t "End tag of
boundary=~A~%" boundary)
+                       (if recurse?
+                           (return (nreverse parts))
+                           (return (build-return parts))))
+                     ))))))))))

 (defun read-simple-body (part)
   (multiple-value-bind (super sub params)


On Thu, Jan 21, 2010 at 10:36 PM, Fred Gibson <fred at streamfocus.com> wrote:
> I've been working with reading in an rfc 2822 file, and the parts
> method returns only 1 large part for the whole message rather than
> breaking it into smaller parts.  It looks like the
> mel.mime:read-multipart-body-1 function starts off from
> mel.mime:compute-bodystructure-using-folder with the whole message and
> then is sent to scan-forward-boundary-tag with the boundary tag for
> the overall message, which then only matches at the end of the file
> and so only 1 big part is returned.  I'm troubleshooting this problem
> now.
>
> Fred Gibson
>
> Founder / Software Developer
> http://www.streamfocus.com
>
> (c)2010 Organon Technologies LLC
>

-- 
Fred Gibson

Founder / Software Developer
http://www.streamfocus.com

(c)2010 Organon Technologies LLC




More information about the mel-base-devel mailing list