Browse code
see ChangeLog
dancy authored on 05/01/2007 21:31:25
Showing 2 changed files
Showing 2 changed files
... | ... |
@@ -1,4 +1,4 @@ |
1 |
-;; $Id: mime-transfer-encoding.cl,v 1.5 2006/12/21 18:22:15 layer Exp $ |
|
1 |
+;; $Id: mime-transfer-encoding.cl,v 1.6 2007/01/05 21:31:25 dancy Exp $ |
|
2 | 2 |
|
3 | 3 |
(defpackage :net.post-office |
4 | 4 |
(:use #:lisp #:excl) |
... | ... |
@@ -95,93 +95,101 @@ |
95 | 95 |
|
96 | 96 |
;; Decoding stuff |
97 | 97 |
|
98 |
+ |
|
99 |
+;; Used by qp-decode-stream |
|
100 |
+(defconstant *qp-digit-values* |
|
101 |
+ #.(let ((arr (make-array 257 :element-type 'fixnum))) |
|
102 |
+ (dotimes (n 256) |
|
103 |
+ (setf (aref arr n) |
|
104 |
+ (if* (<= (char-code #\0) n (char-code #\9)) |
|
105 |
+ then (- n (char-code #\0)) |
|
106 |
+ elseif (<= (char-code #\A) n (char-code #\F)) |
|
107 |
+ then (- n (- (char-code #\A) 10)) |
|
108 |
+ else -1))) |
|
109 |
+ (setf (aref arr 256) -2) |
|
110 |
+ arr)) |
|
111 |
+ |
|
112 |
+ |
|
113 |
+(defun qp-decode-stream (instream outstream &key count) |
|
114 |
+ (declare (optimize (speed 3))) |
|
115 |
+ |
|
116 |
+ (let (unread-buf) |
|
117 |
+ |
|
118 |
+ (macrolet ((unread (byte) |
|
119 |
+ `(progn |
|
120 |
+ (setf unread-buf ,byte) |
|
121 |
+ (if count |
|
122 |
+ (incf count)))) |
|
123 |
+ (get-byte (&key eof-value) |
|
124 |
+ `(block get-byte |
|
125 |
+ (if* count |
|
126 |
+ then (if (zerop count) |
|
127 |
+ (return-from get-byte ,eof-value)) |
|
128 |
+ (decf count)) |
|
129 |
+ (if* unread-buf |
|
130 |
+ then (prog1 unread-buf |
|
131 |
+ (setf unread-buf nil)) |
|
132 |
+ else (read-byte instream nil ,eof-value)))) |
|
133 |
+ (out (byte) |
|
134 |
+ `(write-byte ,byte outstream)) |
|
135 |
+ (eol-p (byte) |
|
136 |
+ `(or (eq ,byte 10) (eq ,byte 13)))) |
|
137 |
+ |
|
138 |
+ (let (byte) |
|
139 |
+ (while (setf byte (get-byte)) |
|
140 |
+ (if* (eq byte #.(char-code #\=)) |
|
141 |
+ then (let ((nextbyte (get-byte))) |
|
142 |
+ (if* (null nextbyte) |
|
143 |
+ then ;; stray equal sign. just dump and terminate. |
|
144 |
+ (out byte) |
|
145 |
+ (return)) |
|
146 |
+ (if* (eol-p nextbyte) |
|
147 |
+ then ;; soft line break. |
|
148 |
+ (if (eq nextbyte 13) ;; CR |
|
149 |
+ (setf nextbyte (get-byte))) |
|
150 |
+ (if (not (eq nextbyte 10)) ;; LF |
|
151 |
+ (unread nextbyte)) |
|
152 |
+ else ;; =XY encoding |
|
153 |
+ (let* ((byte3 (get-byte :eof-value 256)) |
|
154 |
+ (high (aref *qp-digit-values* nextbyte)) |
|
155 |
+ (low (aref *qp-digit-values* byte3)) |
|
156 |
+ (value (logior (the fixnum (ash high 4)) low))) |
|
157 |
+ (declare (fixnum byte3 high low value)) |
|
158 |
+ (if* (< value 0) |
|
159 |
+ then ;; Invalid or truncated encoding. just dump it. |
|
160 |
+ (out byte) |
|
161 |
+ (out nextbyte) |
|
162 |
+ (if* (eq low -2) ;; EOF |
|
163 |
+ then (return) |
|
164 |
+ else (out byte3)) |
|
165 |
+ else (out value))))) |
|
166 |
+ else (out byte))) |
|
167 |
+ |
|
168 |
+ t)))) |
|
169 |
+ |
|
98 | 170 |
;; 'instream' must be positioned at the beginning of the part body |
99 | 171 |
;; by the caller beforehand. |
100 | 172 |
(defmacro with-decoded-part-body-stream ((sym part instream) &body body) |
101 |
- (let ((bodystream (gensym)) |
|
102 |
- (p (gensym)) |
|
103 |
- (encoding (gensym))) |
|
173 |
+ (let ((p (gensym)) |
|
174 |
+ (encoding (gensym)) |
|
175 |
+ (count (gensym))) |
|
104 | 176 |
`(let* ((,p ,part) |
105 |
- (,encoding (mime-part-encoding ,p))) |
|
106 |
- (with-part-stream (,bodystream ,p ,instream :header nil) |
|
107 |
- (excl:with-function-input-stream (,sym #'mime-decode-transfer-encoding |
|
108 |
- ,bodystream |
|
109 |
- ,encoding) |
|
110 |
- ,@body))))) |
|
177 |
+ (,encoding (mime-part-encoding ,p)) |
|
178 |
+ (,count (mime-part-body-size ,p))) |
|
179 |
+ (excl:with-function-input-stream (,sym #'mime-decode-transfer-encoding |
|
180 |
+ ,instream |
|
181 |
+ ,encoding |
|
182 |
+ ,count) |
|
183 |
+ ,@body)))) |
|
111 | 184 |
|
112 |
-(defun mime-decode-transfer-encoding (outstream instream encoding) |
|
113 |
- (funcall |
|
114 |
- (cond |
|
115 |
- ((equalp encoding "quoted-printable") |
|
116 |
- #'qp-decode-stream) |
|
117 |
- ((equalp encoding "base64") |
|
118 |
- #'excl::base64-decode-stream) |
|
119 |
- (t |
|
120 |
- #'sys:copy-file)) |
|
121 |
- instream outstream)) |
|
122 |
- |
|
123 |
-(defun qp-decode-stream (instream outstream) |
|
124 |
- (declare (optimize (speed 3))) |
|
125 |
- (let ((linebuf (make-array 4096 :element-type 'character)) |
|
126 |
- pos char char2 softlinebreak) |
|
127 |
- (declare (dynamic-extent linebuf) |
|
128 |
- (fixnum pos)) |
|
185 |
+(defun mime-decode-transfer-encoding (outstream instream encoding count) |
|
186 |
+ (cond |
|
187 |
+ ((equalp encoding "quoted-printable") |
|
188 |
+ (qp-decode-stream instream outstream :count count)) |
|
189 |
+ ((equalp encoding "base64") |
|
190 |
+ (excl:base64-decode-stream instream outstream :count count :error-p nil)) |
|
191 |
+ (t |
|
192 |
+ ;; defined in mime-parse.cl |
|
193 |
+ (stream-to-stream-copy outstream instream count)))) |
|
129 | 194 |
|
130 |
- (loop |
|
131 |
- (multiple-value-bind (line dummy max) |
|
132 |
- (simple-stream-read-line instream nil nil linebuf) |
|
133 |
- (declare (ignore dummy) |
|
134 |
- (fixnum max) |
|
135 |
- (simple-string line)) |
|
136 |
- (if (null line) |
|
137 |
- (return)) |
|
138 |
- |
|
139 |
- (if (null max) |
|
140 |
- (setf max (length line))) |
|
141 |
- |
|
142 |
- (setf pos 0) |
|
143 |
- |
|
144 |
- (macrolet ((getchar () |
|
145 |
- `(if (< pos max) |
|
146 |
- (prog1 (schar line pos) (incf pos)))) |
|
147 |
- (decode-dig (char) |
|
148 |
- `(the (integer 0 256) (decode-qp-hex-digit ,char)))) |
|
149 |
- |
|
150 |
- (while (< pos max) |
|
151 |
- (setf char (getchar)) |
|
152 |
- |
|
153 |
- (if* (eq char #\=) |
|
154 |
- then ;; Check for soft line break. |
|
155 |
- (if* (= pos max) |
|
156 |
- then (setf softlinebreak t) |
|
157 |
- else (setf char (getchar)) |
|
158 |
- (setf char2 (getchar)) |
|
159 |
- |
|
160 |
- (let ((value (logior |
|
161 |
- (ash (decode-dig char) 4) |
|
162 |
- (decode-dig char2)))) |
|
163 |
- (if* (< value 256) |
|
164 |
- then (write-byte value outstream) |
|
165 |
- else ;; We got some bogus input. |
|
166 |
- ;; Leave it untouched |
|
167 |
- (write-char #\= outstream) |
|
168 |
- (if char |
|
169 |
- (write-char char outstream)) |
|
170 |
- (if char2 |
|
171 |
- (write-char char2 outstream))))) |
|
172 |
- else (write-char char outstream))) |
|
173 |
- ;; outside 'while' loop. |
|
174 |
- |
|
175 |
- (if* softlinebreak |
|
176 |
- then (setf softlinebreak nil) |
|
177 |
- else (write-char #\newline outstream))))))) |
|
178 |
- |
|
179 |
- |
|
180 |
-(defun decode-qp-hex-digit (char) |
|
181 |
- (declare (optimize (speed 3) (safety 0) (debug 0))) |
|
182 |
- (if* (char<= #\0 char #\9) |
|
183 |
- then (- (the (integer 0 255) (char-code char)) #.(char-code #\0)) |
|
184 |
- elseif (char<= #\A char #\F) |
|
185 |
- then (- (the (integer 0 255) (char-code char)) #.(- (char-code #\A) 10)) |
|
186 |
- else 256)) |
|
187 | 195 |
|