X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fmail%2FMIME.java;h=477ce639049228da8e82b67d0993918946a755c8;hb=43b53fd9e204f99ff18101c029e8c3a3a7cf5763;hp=58d06218947407f7e0b4a686d78120bed73dfdbb;hpb=1c969016351982fef3fc1539ab6d494592da1f3d;p=org.ibex.mail.git diff --git a/src/org/ibex/mail/MIME.java b/src/org/ibex/mail/MIME.java index 58d0621..477ce63 100644 --- a/src/org/ibex/mail/MIME.java +++ b/src/org/ibex/mail/MIME.java @@ -1,23 +1,117 @@ +// Copyright 2000-2005 the Contributors, as shown in the revision logs. +// Licensed under the Apache Public Source License 2.0 ("the License"). +// You may not use this file except in compliance with the License. + package org.ibex.mail; +import static org.ibex.mail.MailException.*; +import org.ibex.crypto.*; +import org.ibex.util.*; +import org.ibex.mail.protocol.*; +import org.ibex.js.*; +import org.ibex.io.*; +import org.ibex.io.Fountain; +import java.util.*; +import java.net.*; +import java.io.*; // FEATURE: MIME RFC2045, 2046, 2049 /** This class contains logic for encoding and decoding MIME multipart messages */ public class MIME { - public static class QuotedPrintable { - - public static String decode(String s, boolean lax) { - // - // =XX -> hex representation, must be uppercase - // 9, 32, 33-60, 62-126 can be literal - // 9, 32 at end-of-line must get encoded - // trailing whitespace must be deleted when decoding - // =\n = soft line break - // lines cannot be more than 76 chars long - // - - // lax is used for RFC2047 headers; removes restrictions on which chars you can encode - return s; + + /** Part = Headers+Body */ + public static class Part extends JSReflection implements Fountain { + public final Headers headers; + public final ContentType contentType; + private final String encoding; + + private final Fountain all; + private final Fountain body; + + public Stream getStream() { return all.getStream(); } + public int getNumLines() { return all.getNumLines(); } + public long getLength() { return all.getLength(); } + public Fountain getBody() { return body; } + + public JS get(JS key) throws JSExn { + String k = JSU.toString(key); + if ("body".equals(k)) { + StringBuffer sb = new StringBuffer(); + getBody().getStream().transcribe(sb); + return JSU.S(sb.toString()); + } + return super.get(key); + } + + public Part(final Fountain fount, String[] keyval) { + Headers h = new Headers(fount); + this.headers = keyval==null ? h : new Headers(h, keyval); + String ctype = headers.get("content-type"); + this.encoding = headers.get("content-transfer-encoding"); + String enc = this.encoding; + if (enc!=null) enc = enc.toLowerCase(); + if (!(enc == null || enc.equals("7bit") || enc.equals("8bit") || enc.equals("binary") || + enc.equals("quoted-printable") || enc.equals("base64"))) { + Log.warn(MIME.class, "unknown TransferEncoding \"" + encoding + "\""); + ctype = "application/octet-stream"; + } + this.contentType = new ContentType(ctype, headers.get("content-description"), headers.get("content-id"), encoding); + // FIXME: this is a horrible, tangled mess. + this.body = new Fountain() { + public int getNumLines() { return Stream.countLines(this.getStream()); } + public long getLength() { return Stream.countBytes(this.getStream()); } + public Stream getStream() { return transformBodyStream(Headers.skip(fount.getStream())); } + }; + this.all = + keyval==null + ? fount + : Fountain.Util.concat(this.headers, Fountain.Util.create("\r\n"), this.body); + } + + private Stream transformBodyStream(Stream body) { + //"quoted-printable".equals(encoding) ? Encode.QuotedPrintable.decode(body.toString(),false) : + //"base64".equals(encoding) ? Encode.fromBase64(body.toString()) : + return body; + } + + /* + public Part getPart(int i) { + Stream stream = body.getStream(); + Vec v = new Vec(); + // first part begins with a boundary delimiter + for(String s = stream.readln(); s != null; s = stream.readln()) + if (s.equals("--" + contentType.parameters.get("boundary"))) break; + while(true) { + Stream substream = new BoundaryStream(stream, (String)contentType.parameters.get("boundary")); + Part p = new Part(substream, true, null); // FIXME split off headers + v.addElement(p); + if (substream.isLast()) break; + } + return parts = (Part[])v.copyInto(new Part[v.size()]); + } + */ + } + + /* + public static class Boundary implements Stream.Transformer { + private final String boundary; + private boolean done = false; + private boolean last = false; + public Boundary(String bounardy) { this.boundary = boundary; } + public boolean isLast() { while(!done) readln(); return last; } + public Stream transform(Stream stream) { + for(String s = stream.readln(); s != null; s = stream.readln()) { + if (boundary != null && (s.equals(boundary) || s.equals(boundary + "--"))) { + body.setLength(body.length() - 2); // preceeding CRLF is part of delimiter + last = s.equals(boundary + "--"); + done = true; + break; + } + body.append(s); + body.append("\r\n"); + //lines++; + } } } + */ }