001: package org.bouncycastle.mail.smime.handlers;
002:
003: import org.bouncycastle.mail.smime.SMIMEStreamingProcessor;
004:
005: import javax.activation.ActivationDataFlavor;
006: import javax.activation.DataContentHandler;
007: import javax.activation.DataSource;
008: import javax.mail.MessagingException;
009: import javax.mail.Multipart;
010: import javax.mail.internet.ContentType;
011: import javax.mail.internet.MimeBodyPart;
012: import javax.mail.internet.MimeMultipart;
013: import java.awt.datatransfer.DataFlavor;
014: import java.io.BufferedInputStream;
015: import java.io.FilterOutputStream;
016: import java.io.IOException;
017: import java.io.InputStream;
018: import java.io.OutputStream;
019: import java.util.Enumeration;
020:
021: public class multipart_signed implements DataContentHandler {
022: private static final ActivationDataFlavor ADF = new ActivationDataFlavor(
023: MimeMultipart.class, "multipart/signed", "Multipart Signed");
024: private static final DataFlavor[] DFS = new DataFlavor[] { ADF };
025:
026: public Object getContent(DataSource ds) throws IOException {
027: try {
028: return new MimeMultipart(ds);
029: } catch (MessagingException ex) {
030: return null;
031: }
032: }
033:
034: public Object getTransferData(DataFlavor df, DataSource ds)
035: throws IOException {
036: if (ADF.equals(df)) {
037: return getContent(ds);
038: } else {
039: return null;
040: }
041: }
042:
043: public DataFlavor[] getTransferDataFlavors() {
044: return DFS;
045: }
046:
047: public void writeTo(Object obj, String _mimeType, OutputStream os)
048: throws IOException {
049:
050: if (obj instanceof MimeMultipart) {
051: try {
052: outputBodyPart(os, obj);
053: } catch (MessagingException ex) {
054: throw new IOException(ex.getMessage());
055: }
056: } else if (obj instanceof byte[]) {
057: os.write((byte[]) obj);
058: } else if (obj instanceof InputStream) {
059: int b;
060: InputStream in = (InputStream) obj;
061:
062: if (!(in instanceof BufferedInputStream)) {
063: in = new BufferedInputStream(in);
064: }
065:
066: while ((b = in.read()) >= 0) {
067: os.write(b);
068: }
069: } else if (obj instanceof SMIMEStreamingProcessor) {
070: SMIMEStreamingProcessor processor = (SMIMEStreamingProcessor) obj;
071:
072: processor.write(os);
073: } else {
074: throw new IOException("unknown object in writeTo " + obj);
075: }
076: }
077:
078: /*
079: * Output the mulitpart as a collection of leaves to make sure preamble text is not included.
080: */
081: private void outputBodyPart(OutputStream out, Object bodyPart)
082: throws MessagingException, IOException {
083: if (bodyPart instanceof Multipart) {
084: Multipart mp = (Multipart) bodyPart;
085: ContentType contentType = new ContentType(mp
086: .getContentType());
087: String boundary = "--"
088: + contentType.getParameter("boundary");
089:
090: LineOutputStream lOut = new LineOutputStream(out);
091:
092: for (int i = 0; i < mp.getCount(); i++) {
093: lOut.writeln(boundary);
094: outputBodyPart(out, mp.getBodyPart(i));
095: lOut.writeln(); // CRLF terminator
096: }
097:
098: lOut.writeln(boundary + "--");
099: return;
100: }
101:
102: MimeBodyPart mimePart = (MimeBodyPart) bodyPart;
103:
104: if (mimePart.getContent() instanceof Multipart) {
105: Multipart mp = (Multipart) mimePart.getContent();
106: ContentType contentType = new ContentType(mp
107: .getContentType());
108: String boundary = "--"
109: + contentType.getParameter("boundary");
110:
111: LineOutputStream lOut = new LineOutputStream(out);
112:
113: Enumeration headers = mimePart.getAllHeaderLines();
114: while (headers.hasMoreElements()) {
115: lOut.writeln((String) headers.nextElement());
116: }
117:
118: lOut.writeln(); // CRLF separator
119:
120: outputPreamble(lOut, mimePart, boundary);
121:
122: outputBodyPart(out, mp);
123: return;
124: }
125:
126: mimePart.writeTo(out);
127: }
128:
129: /**
130: * internal preamble is generally included in signatures, while this is technically wrong,
131: * if we find internal preamble we include it by default.
132: */
133: static void outputPreamble(LineOutputStream lOut,
134: MimeBodyPart part, String boundary)
135: throws MessagingException, IOException {
136: InputStream in;
137:
138: try {
139: in = part.getRawInputStream();
140: } catch (MessagingException e) {
141: return; // no underlying content, rely on default generation
142: }
143:
144: String line;
145:
146: while ((line = readLine(in)) != null) {
147: if (line.equals(boundary)) {
148: break;
149: }
150:
151: lOut.writeln(line);
152: }
153:
154: in.close();
155:
156: if (line == null) {
157: throw new MessagingException("no boundary found");
158: }
159: }
160:
161: /*
162: * read a line of input stripping of the tailing \r\n
163: */
164: private static String readLine(InputStream in) throws IOException {
165: StringBuffer b = new StringBuffer();
166:
167: int ch;
168: while ((ch = in.read()) >= 0 && ch != '\n') {
169: if (ch != '\r') {
170: b.append((char) ch);
171: }
172: }
173:
174: if (ch < 0) {
175: return null;
176: }
177:
178: return b.toString();
179: }
180:
181: private static class LineOutputStream extends FilterOutputStream {
182: private static byte newline[];
183:
184: public LineOutputStream(OutputStream outputstream) {
185: super (outputstream);
186: }
187:
188: public void writeln(String s) throws MessagingException {
189: try {
190: byte abyte0[] = getBytes(s);
191: super .out.write(abyte0);
192: super .out.write(newline);
193: } catch (Exception exception) {
194: throw new MessagingException("IOException", exception);
195: }
196: }
197:
198: public void writeln() throws MessagingException {
199: try {
200: super .out.write(newline);
201: } catch (Exception exception) {
202: throw new MessagingException("IOException", exception);
203: }
204: }
205:
206: static {
207: newline = new byte[2];
208: newline[0] = 13;
209: newline[1] = 10;
210: }
211:
212: private static byte[] getBytes(String s) {
213: char ac[] = s.toCharArray();
214: int i = ac.length;
215: byte abyte0[] = new byte[i];
216: int j = 0;
217:
218: while (j < i) {
219: abyte0[j] = (byte) ac[j++];
220: }
221:
222: return abyte0;
223: }
224: }
225: }
|