source: project/release/3/mime/tags/1.3.1/mime.html @ 9962

Last change on this file since 9962 was 5248, checked in by hans, 14 years ago

version 1.3: factored out mime-get-attributes from mime-parse-content-type, added a missing backslash in mime-parse-version regexp

File size: 20.3 KB
Line 
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2<!-- Generated by eggdoc Revision: 1.20  -->
3<html>
4<head>
5<title>Eggs Unlimited - mime</title><style type="text/css"> <!--
6      CODE {
7            color: #666666;
8          }
9/*   DT.definition EM { font-weight: bold; font-style: normal; } */
10
11     DT.definition { 
12                   background: #eee;
13                   color: black;
14                   padding: 0.2em 1em 0.2em 0.7em;
15                   margin-left: 0.2em;
16border: 1px solid #bbc;
17                   font-family: "Andale Mono", monospace;
18                   /* font-size: 1.2em; */
19                   
20                 }
21     DD {
22                   margin-top: 0.8em;
23                   margin-bottom: 0.8em;
24     }
25     DIV.subsection {
26                    border-top: 1px solid #448;
27                    padding-left: 1em;
28                    margin-bottom: 1.2em;
29     }
30     DIV.subsubsection {
31                    border-top: 1px dotted #99c;
32                    /* border-left: 1px solid #99c; */
33                    padding-left: 1em;
34                    margin-bottom: 1.2em;
35     }
36     DIV.subsubsubsection {
37                    border-top: 1px solid #ddf;
38                    padding-left: 1em;
39                    margin-bottom: 1.2em;
40     }
41
42         DIV.section {
43                 margin-bottom: 1.5em;
44         }
45         a:link {
46                 color: #336;
47         }
48         a:visited { color: #666; }
49         a:active  { color: #966; }
50         a:hover   { color: #669; }
51         body { margin: 0; padding: 0; background: #fff; color: #000; font: 9pt "Lucida Grande", "Verdana", sans-serif; }
52         H2 {
53                 background: #336;
54                 color: #fff;
55                 padding-top: 0.5em;
56                 padding-bottom: 0.5em;
57                 padding-left: 16px;
58                 margin: 0 0 1em 0;
59        }
60        UL LI {
61                list-style: none;
62        }
63        TT {
64                font-family: "Andale Mono", monospace;
65                /* font-size: 1.2em; */
66        }
67        H3 {
68                color: #113;
69                margin-bottom: 0.5em;
70        }
71        H4, H5, H6 {
72                color: #113;
73                margin-bottom: 1.0em;
74        }
75        H5 {
76                font-weight: normal;
77                font-style: italic;
78                font-size: 100%;
79                margin-top: 1.2em;
80        }
81        H6 {
82                font-weight: bold;
83                font-size: 85%;
84                margin-top: 1.2em;
85        }
86     DIV#eggheader {
87         text-align: center;
88                 float: right;
89                 margin-right: 2em;
90     }
91     DIV#header IMG {
92            /* display: block; margin-left: auto; margin-right: auto;  */
93            /* float: right; */
94            border: none;  /* firefox */
95     }
96     DIV#footer {
97                background: #bbd;
98                padding: 0.7em ;
99                border-top: 1px solid #cce;
100     }
101     DIV#footer hr {
102                display: none;
103     }
104     DIV#footer a {
105                float: left;
106     }
107     DIV#revision-history {
108         float: right;
109     }
110     
111     DIV#body {
112                 margin: 1em 1em 1em 16px;
113         }
114
115     DIV#examples PRE {
116       background: #eef;
117       padding: 0.1em;
118       border: 1px solid #aac;
119     }
120     PRE#license, DIV#examples PRE {
121       padding: 0.5em;
122     }
123     DIV#examples PRE {
124       /* font-size: 85%; */
125     }
126     PRE { font-family: "Andale Mono", monospace; }
127     TABLE {
128       background: #eef;
129       padding: 0.2em;
130       border: 1px solid #aac;
131       border-collapse: collapse;
132       width: 100%;
133     }
134     TABLE.symbol-table TD.symbol {
135          width: 15em;
136          font-family: "Andale Mono", monospace;
137          /* font-size: 1.2em; */
138     }
139     TH {
140       text-align: left;
141       border-bottom: 1px solid #aac;
142       padding: 0.25em 0.5em 0.25em 0.5em;
143     } 
144     TD { padding: 0.25em 0.5em 0.25em 0.5em; }
145     --></style></head>
146<body>
147<div id="header">
148<h2>mime</h2>
149<div id="eggheader"><a href="index.html">
150<img src="egg.jpg" alt="[Picture of an egg]" /></a></div></div>
151<div id="body">
152<div class="section">
153<h3>Description</h3>Parse MIME Messages.</div>
154<div class="section">
155<h3>Author</h3>Shiro Kawai, Chicken-port and some additions by Hans Bulfone</div>
156<div class="section">
157<h3>Version</h3>
158<ul>
159<li>1.0 Initial release</li>
160<li>1.1 Generating MIME messages</li>
161<li>1.2 fixed .setup script to handle change in argument processing of csc</li>
162<li>1.3 Added mime-get-attributes (suggested by Moe Aboulkheir)</li></ul></div>
163<div class="section">
164<h3>Requires</h3>
165<ul>
166<li>rfc822</li>
167<li>base64</li>
168<li>iconv</li></ul></div>
169<div class="section">
170<h3>Usage</h3><tt>(require-extension mime)</tt></div>
171<div class="section">
172<h3>Download</h3><a href="mime.egg">mime.egg</a></div>
173<div class="section">
174<h3>Documentation</h3>
175<p>This documentation is based on Gauches <tt>rfc.mime</tt> and <tt>rfc.quoted-printable</tt> documentation with some changes where the Chicken version differs.</p>
176<p>This egg provides utility procedures to handle Multipurpose Internet Mail Extensions (MIME) messages, defined in RFC2045 through RFC2049. This egg is supposed to be used with the <tt>rfc822</tt> egg.</p>
177<div class="subsection">
178<h4>Quoted-printable encoding/decoding</h4>
179<p>A few functions to encode/decode Quoted-printable format, defined in RFC2045, section 6.7.</p>
180<dl>
181<dt class="definition"><strong>procedure:</strong> (quoted-printable-encode)</dt>
182<dd>Reads a byte stream from the current input port, encodes it in Quoted-printable format and writes the result character stream to the current output port. The conversion ends when it reads <tt>#!eof</tt> from the current input port.</dd>
183<dt class="definition"><strong>procedure:</strong> (quoted-printable-encode-string STRING)</dt>
184<dd>Converts the contents of <tt>STRING</tt> to Quoted-printable encoded format. The input string can be either a complete or incomplete string; it is always interpreted as a byte sequence.</dd>
185<dt class="definition"><strong>procedure:</strong> (quoted-printable-decode)</dt>
186<dd>Reads characters from the current input port, decodes them from Quoted-printable format and writes the result byte stream to the current output port. The conversion ends when it reads <tt>#!eof</tt>. If it encounters illegal character sequences (such as <tt>#\=</tt> followed by non-hexadecimal characters), it copies them literally to the output.</dd>
187<dt class="definition"><strong>procedure:</strong> (quoted-printable-decode-string STRING)</dt>
188<dd>Decodes a Quoted-printable encoded string <tt>STRING</tt> and returns the result as a string.</dd></dl></div>
189<div class="subsection">
190<h4>Utilities for header fields</h4>
191<p>A few utility procedures to parse MIME-specific header fields.</p>
192<dl>
193<dt class="definition"><strong>procedure:</strong> (mime-parse-version FIELD)</dt>
194<dd>If <tt>FIELD</tt> is a valid header field for MIME-Version, returns its major and minor versions in a list. Otherwise, returns <tt>#f</tt>. It is allowed to pass <tt>#f</tt> to <tt>FIELD</tt>, so that you can directly pass the result of <tt>rfc822-header-ref</tt> to it. Given a parsed header list from <tt>rfc822-header-&gt;list</tt>, you can get the MIME version (currently, it should be <tt>(1 0)</tt>) by the following code:
195<pre>(mime-parse-version (rfc822-header-ref headers &quot;mime-version&quot;))</pre>Note: simple regexp such as <tt>&quot;\d+\.\d+&quot;</tt> doesn't do this job, for <tt>FIELD</tt> may contain comments between tokens.</dd>
196<dt class="definition"><strong>procedure:</strong> (mime-get-attributes INPUT)</dt>
197<dd>Reads an attribute/value list in the form <tt>;attr1=value1;attr2=value2</tt> from <tt>INPUT</tt> (which should be an open input-port) and returns it as an alist.</dd>
198<dt class="definition"><strong>procedure:</strong> (mime-parse-content-type FIELD)</dt>
199<dd>Parses the &quot;content-type&quot; header field, and returns a list such as:
200<pre>(type subtype (attribute . value) ...)</pre>where <tt>type</tt> and <tt>subtype</tt> are MIME media type and subtype in a string, respectively.
201<pre>(mime-parse-content-type &quot;text/html; charset=iso-2022-jp&quot;)
202=&gt; (&quot;text&quot; &quot;html&quot; (&quot;charset&quot; . &quot;iso-2022-jp&quot;))</pre>If <tt>FIELD</tt> is not a valid content-type field, <tt>#f</tt> is returned.</dd>
203<dt class="definition"><strong>procedure:</strong> (mime-decode-word WORD)</dt>
204<dd>Decodes RFC2047-encoded word. If <tt>WORD</tt> isn't an encoded word, it is returned as is.
205<pre>(mime-decode-word &quot;=?iso-8859-1?q?this=20is=20some=20text?=&quot;)
206=&gt; &quot;this is some text&quot;</pre></dd></dl></div>
207<div class="subsection">
208<h4>Streaming parser</h4>
209<p>The streaming parser is designed so that you can decide how to do with the message body before the entire message is read.</p>
210<dl>
211<dt class="definition"><strong>procedure:</strong> (mime-parse-message PORT HEADERS HANDLER)</dt>
212<dd>
213<p>The fundamental streaming parser. <tt>PORT</tt> is an input port from where the mssage is read. <tt>HEADERS</tt> is a list of headers parsed by <tt>rfc822-header-&gt;list</tt>; that is, this procedure is supposed to be called after the header part of the message is parsed from port:</p>
214<pre>(let* ((headers (rfc822-header-&gt;list port)))
215  (if (mime-parse-version (rfc822-header-ref headers &quot;mime-version&quot;))
216     ;; parse MIME message
217     (mime-parse-message port headers handler)
218     ;; retrieve a non-MIME body
219     ...))</pre>
220<p><tt>mime-parse-message</tt> analyzes headers, and calls <tt>HANDLER</tt> on each message body with two arguments:</p>
221<pre>(HANDLER PART-INFO XPORT)</pre>
222<p><tt>PART-INFO</tt> is a <tt>:mime-part</tt> record described below that encapsulates the information of this part of the message. <tt>XPORT</tt> is an input port, initially points to the beginning of the body of message. The handler can read from the port as if it is reading from the original port. However, <tt>XPORT</tt> recognizes MIME boundary internally, and returns <tt>#!eof</tt> when it reaches the end of the part. (Do not read from the original port directly, or it will mess up the internal state of <tt>XPORT</tt>).</p>
223<p><tt>HANDLER</tt> can read the part into the memory, or save it to the disk, or even discard the part. Whatever it does, it has to read from <tt>XPORT</tt> until it returns <tt>#!eof</tt>.</p>
224<p>The return value of handler will be set in the content slot of <tt>PART-INFO</tt>. If the message has nested multipart messages, <tt>HANDLER</tt> is called for each &quot;leaf&quot; part, in depth-first order. <tt>HANDLER</tt> can know its nesting level by examining <tt>PART-INFO</tt> record. The message doesn't need to be a multipart type; if it is a MIME message type, <tt>HANDLER</tt> is called on the body of enclosed message. If it is other media types such as <tt>text</tt> or <tt>application</tt>, <tt>HANDLER</tt> is called on the (only) message body.</p></dd>
225<dt class="definition"><strong>record:</strong> :mime-part</dt>
226<dd>
227<p>A SRFI-9 record that encloses metainformation about a MIME part. It is constructed when the header of the part is read, and passed to the handler that reads the body of the part.</p>
228<p>The following procedures for manipulating <tt>:mime-part</tt>-records exist:</p>
229<dl>
230<dt class="definition"><strong>procedure:</strong> (make-mime-part #:type TYPE #:subtype STYPE #:parameters PARAMS #:transfer-encoding TENC #:parent P #:index I #:headers HDRS #:content C #:attrs ATTRS</dt>
231<dd>Create a <tt>:mime-part</tt>-record.  The arguments default to <tt>&quot;text&quot;</tt>, <tt>&quot;plain&quot;</tt>, <tt>'()</tt>, <tt>&quot;7bit&quot;</tt>, <tt>#f</tt>, <tt>0</tt>, <tt>'()</tt>, <tt>#f</tt>, and <tt>'()</tt>.</dd>
232<dt class="definition"><strong>procedure:</strong> (mime-part:type PART-INFO)</dt>
233<dd></dd>
234<dt class="definition"><strong>procedure:</strong> (mime-part:type-set! PART-INFO TYPE)</dt>
235<dd>MIME media type string. If <tt>content-type</tt> header is omitted to the part, an appropriate default value is set.</dd>
236<dt class="definition"><strong>procedure:</strong> (mime-part:subtype PART-INFO)</dt>
237<dd></dd>
238<dt class="definition"><strong>procedure:</strong> (mime-part:subtype-set! PART-INFO SUBTYPE)</dt>
239<dd>MIME media subtype string. If <tt>content-type</tt> header is omitted to the part, an appropriate default value is set.</dd>
240<dt class="definition"><strong>procedure:</strong> (mime-part:parameters PART-INFO)</dt>
241<dd></dd>
242<dt class="definition"><strong>procedure:</strong> (mime-part:parameters-set! PART-INFO PARAMETERS)</dt>
243<dd>Associative list of parameters given to <tt>content-type</tt> header field.</dd>
244<dt class="definition"><strong>procedure:</strong> (mime-part:transfer-encoding PART-INFO)</dt>
245<dd></dd>
246<dt class="definition"><strong>procedure:</strong> (mime-part:transfer-encoding-set! PART-INFO TRANSFER-ENCODING)</dt>
247<dd>The value of the <tt>content-transfer-encoding</tt> header field. If the header field is omitted, an appropriate default value is set.</dd>
248<dt class="definition"><strong>procedure:</strong> (mime-part:parent PART-INFO)</dt>
249<dd></dd>
250<dt class="definition"><strong>procedure:</strong> (mime-part:parent-set! PART-INFO PARENT)</dt>
251<dd>If this is a part of multipart message or encapsulated message, points to the enclosing part's <tt>:mime-part</tt> record. Otherwise <tt>#f</tt>.</dd>
252<dt class="definition"><strong>procedure:</strong> (mime-part:index PART-INFO)</dt>
253<dd></dd>
254<dt class="definition"><strong>procedure:</strong> (mime-part:index-set! PART-INFO INDEX)</dt>
255<dd>Sequence number of this part within the same parent.</dd>
256<dt class="definition"><strong>procedure:</strong> (mime-part:headers PART-INFO)</dt>
257<dd></dd>
258<dt class="definition"><strong>procedure:</strong> (mime-part:headers-set! PART-INFO HEADERS)</dt>
259<dd>The list of header fields, as parsed by <tt>rfc822-header-&gt;list</tt>.</dd>
260<dt class="definition"><strong>procedure:</strong> (mime-part:content PART-INFO)</dt>
261<dd></dd>
262<dt class="definition"><strong>procedure:</strong> (mime-part:content-set! PART-INFO CONTENT)</dt>
263<dd>If this part is <tt>multipart/*</tt> or <tt>message/*</tt> media type, this slot contains a list of parts within it. Otherwise, the return value of handler is stored.</dd>
264<dt class="definition"><strong>procedure:</strong> (mime-part:attrs PART-INFO)</dt>
265<dd></dd>
266<dt class="definition"><strong>procedure:</strong> (mime-part:attrs-set! PART-INFO ATTRS)</dt>
267<dd>This alist provides a place for the message parser/generator or the application to store additional information. At the moment, only the <tt>'qp-encode-binary?</tt> attribute is used by the quoted-printable encoder to decide if the content should be treated as binary.</dd></dl></dd>
268<dt class="definition"><strong>procedure:</strong> (mime-retrieve-body PART-INFO XPORT OUTP)</dt>
269<dd>
270<p>A procedure to retrieve a message body. It is intended to be a building block for a handler to be passed to <tt>mime-parse-message</tt>.</p>
271<p><tt>PART-INFO</tt> is a <tt>:mime-part</tt> record. <tt>XPORT</tt> is an input port passed to the handler, from which the MIME part can be read. This procedure reads from <tt>XPORT</tt> until it returns <tt>#!eof</tt>. It also looks at the <tt>transfer-encoding</tt> of <tt>PART-INFO</tt>, and decodes the body accordingly; that is, base64 encoding and quoted-printable encoding is handled. The result is written out to an output port <tt>OUTP</tt>.</p>
272<p>This procedure does not handle charset conversion. The caller can use facilities from the <tt>charconv</tt> and/or <tt>iconv</tt> modules if conversion is desired.</p></dd></dl>
273<p>A couple of convenience procedures are defined for typical cases on top of <tt>mime-retrieve-body</tt>.</p>
274<dl>
275<dt class="definition"><strong>procedure:</strong> (mime-body-&gt;string PART-INFO XPORT)</dt>
276<dd></dd>
277<dt class="definition"><strong>procedure:</strong> (mime-body-&gt;file PART-INFO XPORT FILENAME)</dt>
278<dd>Reads in the body of mime message, decoding transfer encoding, and returns it as a string or writes it to a file, respectively.</dd></dl></div>
279<div class="subsection">
280<h4>Message generator</h4>
281<p>The message generator generates a RFC822/MIME message out of <tt>:mime-part</tt> objects.</p>
282<dl>
283<dt class="definition"><strong>procedure:</strong> (mime-part-write PART-INFO)</dt>
284<dd>
285<p>Formats <tt>PART-INFO</tt> as a MIME message and writes the result to the current output port.</p>
286<p><tt>PART-INFO</tt> may describe a single mail body or a <tt>multipart/*</tt> or <tt>message/*</tt> hierarchy.</p>
287<p>For multipart messages a boundary may be given in <tt>(mime-part:parameters PART-INFO)</tt> which will be used as a base for the message boundary (but modified if needed).</p>
288<p>If <tt>(mime-part:transfer-encoding PART-INFO)</tt> specifies <tt>&quot;base64&quot;</tt> or <tt>&quot;quoted-printable&quot;</tt> the body is encoded accordingly; else it is put into the message literally.</p></dd>
289<dt class="definition"><strong>procedure:</strong> (mime-part-&gt;string PART-INFO)</dt>
290<dd>
291<p>Like <tt>(mime-part-write)</tt> but returns the message as a string.</p></dd></dl></div></div>
292<div class="section">
293<h3>Examples</h3>
294<div id="examples">
295<p>The simplest form of MIME message parser would be like this:</p>
296<pre>(let ((headers (rfc822-header-&gt;list port)))
297  (mime-parse-message port headers
298                      (cut mime-body-&gt;string &lt;&gt; &lt;&gt;)))
299</pre>
300<p>This reads all the message on memory (i.e. the &quot;leaf&quot; <tt>:mime-part</tt> records' content fields would hold the part's body as a string), and returns the top <tt>:mime-part</tt> record. Content transfer encoding is recognized and handled, but character set conversion isn't done.</p>
301<p>You may want to feed the message body to a file directly, or even want to skip some body according to mime media types and/or other header information. Then you can put the logic in the handler closure. That's the reason that this module provides building blocks, instead of all-in-one procedure.</p>
302<p>A simple MIME-Message could be generated as follows:</p>
303<pre>(mime-part-write
304 (make-mime-part
305  #:type &quot;multipart&quot;
306  #:subtype &quot;mixed&quot;
307  #:headers
308  '((&quot;from&quot; &quot;test &lt;test@test.com&gt;&quot;)
309    (&quot;to&quot;   &quot;foo &lt;foo@bar.com&gt;&quot;)
310    (&quot;mime-version&quot; &quot;1.0&quot;)
311    (&quot;subject&quot; &quot;a test&quot;)
312    (&quot;message-id&quot; &quot;&lt;test123@test.com&gt;&quot;))
313  #:content
314  (list
315   (make-mime-part
316    #:transfer-encoding &quot;quoted-printable&quot;
317    #:content
318    &quot;This = a simple test.&quot;)
319   (make-mime-part
320    #:type &quot;application&quot; #:subtype &quot;octet-stream&quot;
321    #:transfer-encoding &quot;base64&quot;
322    #:content &quot;a simple test&quot;))))</pre>
323<pre>From: test &lt;test@test.com&gt;
324To: foo &lt;foo@bar.com&gt;
325Mime-Version: 1.0
326Subject: a test
327Message-Id: &lt;test123@test.com&gt;
328Content-Type: multipart/mixed;boundary=&quot;MIME-Message-Boundary-&quot;
329Content-Transfer-Encoding: 7bit
330
331This message is in MIME format.
332
333--MIME-Message-Boundary-
334Content-Type: text/plain
335Content-Transfer-Encoding: quoted-printable
336
337This =3D a simple test.
338--MIME-Message-Boundary-
339Content-Type: application/octet-stream
340Content-Transfer-Encoding: base64
341
342YSBzaW1wbGUgdGVzdA==
343
344--MIME-Message-Boundary---</pre></div></div>
345<div class="section">
346<h3>License</h3>
347<pre>Copyright (c) 2000-2004 Shiro Kawai, All rights reserved.
348
349Redistribution and use in source and binary forms, with or without
350modification, are permitted provided that the following conditions
351are met:
352
3531. Redistributions of source code must retain the above copyright
354   notice, this list of conditions and the following disclaimer.
355
3562. Redistributions in binary form must reproduce the above copyright
357   notice, this list of conditions and the following disclaimer in the
358   documentation and/or other materials provided with the distribution.
359
3603. Neither the name of the authors nor the names of its contributors
361   may be used to endorse or promote products derived from this
362   software without specific prior written permission.
363
364THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
365&quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
366LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
367A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
368OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
369SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
370TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
371PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
372LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
373NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
374SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</pre></div></div>
375<div id="footer">
376<hr /><a href="index.html">&lt; Egg index</a>
377<div id="revision-history">$Revision$ $Date$</div>&nbsp;</div></body></html>
Note: See TracBrowser for help on using the repository browser.