pjs/grendel/mime/parser/MimeContainer.java

237 строки
8.2 KiB
Java

/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Grendel mail/news client.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1997
* Netscape Communications Corporation. All Rights Reserved.
*
* Created: Jamie Zawinski <jwz@netscape.com>, 21 Aug 1997.
*/
package grendel.mime.parser;
import grendel.mime.IMimeOperator;
import calypso.util.ByteBuf;
import javax.mail.internet.InternetHeaders;
import java.util.Enumeration;
import java.util.Vector;
import java.util.StringTokenizer;
//import java.lang.reflect.Constructor;
//import java.lang.reflect.InvocationTargetException;
/** This abstract class represents the parsers for all MIME objects which can
contain other MIME objects within them.
*/
abstract class MimeContainer extends MimeObject {
Vector kids = null;
MimeObject open_child = null;
public MimeContainer(String content_type, InternetHeaders headers) {
super(content_type, headers);
}
public Enumeration children() { return kids.elements(); }
/** This method creates a new child part, making the decision about which
MIME content-type strings correspond to which subclasses of MimeObject.
It does this by mapping the type name to a class name, and attempting
to load it from the `grendel.mime.parser' package.
*/
public MimeObject makeChild(String child_type,
InternetHeaders child_headers) {
if (child_type == null && child_headers != null) {
String hh[] = child_headers.getHeader("Content-Type");
if (hh != null && hh.length != 0) {
child_type = hh[0];
// #### strip to first token
int i = child_type.indexOf(';');
if (i > 0)
child_type = child_type.substring(0, i);
child_type = child_type.trim();
}
}
if (child_type == null)
return new MimeDwimText(child_type, child_headers);
else if (child_type.equalsIgnoreCase("message/rfc822") ||
child_type.equalsIgnoreCase("message/news"))
return new MimeMessageRFC822(child_type, child_headers);
else if (child_type.equalsIgnoreCase("message/external-body"))
return new MimeMessageExternalBody(child_type, child_headers);
else if (child_type.equalsIgnoreCase("multipart/digest"))
return new MimeMultipartDigest(child_type, child_headers);
else if (child_type.regionMatches(true, 0, "multipart/", 0, 10))
return new MimeMultipart(child_type, child_headers);
else if (child_type.equalsIgnoreCase("x-sun-attachment"))
return new MimeXSunAttachment(child_type, child_headers);
else
return new MimeLeaf(child_type, child_headers);
}
/* This hairy mess does the same thing as the above version, but it
does so by dynamically looking up classes at runtime: if it sees
a MIME type of "multipart/foobar-baz", it would try to instantiate,
in order,
grendel.mime.parser.MimeMultipartFoobarBaz
grendel.mime.parser.MimeMultipart
grendel.mime.parser.Leaf
This is all well and good, but it turns out to be a bit slower, and
I'm not convinced this generality is actually useful here in the
parser, so I'm going to punt on it for now.
*/
// public MimeObject makeChild(String child_type, InternetHeaders child_headers) {
//
// if (child_type == null && child_headers != null)
// child_type = child_headers.getHeaderValue("Content-Type", true, false);
//
// String pkg = "grendel.mime.parser";
// String base_class_name = null;
// String full_class_name = null;
//
// if (child_type == null) {
// full_class_name = "MimeDwimText";
// } else {
//
// if (child_type.equalsIgnoreCase("message/news")) // synonym kludge
// child_type = "message/rfc822";
// else if (child_type.equalsIgnoreCase("multipart/header-set"))
// child_type = "multipart/appledouble";
//
// StringTokenizer st = new StringTokenizer(child_type, " /-_", false);
// while (st.hasMoreTokens()) {
// String t = st.nextToken();
// t = (String.valueOf(Character.toUpperCase(t.charAt(0))) +
// t.substring(1).toLowerCase());
// if (t.equals("Rfc822")) t = "RFC822"; // typographical kludge
// if (base_class_name == null)
// base_class_name = "Mime" + t;
// if (full_class_name == null)
// full_class_name = "Mime";
// full_class_name += t;
// }
// }
//
// if (full_class_name != null)
// full_class_name = pkg + "." + full_class_name;
// if (base_class_name != null)
// base_class_name = pkg + "." + base_class_name;
//
//
// Class types[] = { "".getClass(), child_headers.getClass() };
// Object args[] = { child_type, child_headers };
// MimeObject result;
//
// // First try to find and instantiate the full-class version...
// result = try_class(full_class_name, types, args);
// if (result != null) return result;
//
// // If that failed, try to find and instantiate the base-class version.
// result = try_class(base_class_name, types, args);
// if (result != null) return result;
//
// // If that failed, use the leaf class (this better work.)
// result = try_class(pkg + ".MimeLeaf", types, args);
// if (result == null) throw new Error("internal error: no classes");
// return result;
// }
//
// // Tries to find a class of the given name, and construct an instance
// // with a two-arg constructor (String, InternetHeaders). Returns null if either
// // fails.
// private final MimeObject try_class(String class_name,
// Class[] types, Object[] args) {
// if (class_name == null) return null;
// try {
// Class c = Class.forName(class_name);
//
// Constructor cc = c.getConstructor(types);
// return (MimeObject) cc.newInstance(args);
//
// } catch (ClassNotFoundException c) { // Class.forName
// } catch (NoSuchMethodException c) { // Constructor.getConstructor
// } catch (IllegalAccessException c) { // Constructor.newInstance
// } catch (IllegalArgumentException c) { // Constructor.newInstance
// } catch (InstantiationException c) { // Constructor.newInstance
// } catch (InvocationTargetException c) { // Constructor.newInstance
// }
// return null;
// }
/** This method creates a new child part (via makeChild()), and then
creates an operator for it, and installs it in `kids'.
*/
public MimeObject openChild(String child_type,
InternetHeaders child_headers) {
if (open_child != null)
closeChild();
open_child = makeChild(child_type, child_headers);
if (kids == null)
kids = new Vector();
if (id == null)
open_child.id = String.valueOf(kids.size() + 1);
else
open_child.id = id + "." + String.valueOf(kids.size() + 1);
open_child.setOperator(operator.createChild(open_child));
kids.addElement(open_child);
return open_child;
}
public void closeChild() {
if (open_child != null) {
open_child.pushEOF();
open_child = null;
}
}
public MimeObject openChild(ByteBuf child_type,
InternetHeaders child_headers) {
return openChild((child_type == null
? null
: child_type.toString()),
child_headers);
}
public MimeObject openChild(byte child_type[],
InternetHeaders child_headers) {
return openChild((child_type == null
? null
: new String(child_type)),
child_headers);
}
public void pushEOF() {
closeChild();
super.pushEOF();
}
}