1 /*
2 * @(#) $Id: CorrectedContentTypeDataSourceUTF7Support.java,v 1.1.2.1 2004/09/29 00:57:59 otsuka Exp $
3 * $Revision: 1.1.2.1 $
4 * Copyright (c) 2000 Shin Kinoshita All Rights Reserved.
5 */
6 package com.ozacc.mail.fetch.impl.sk_jp;
7
8 import java.io.ByteArrayInputStream;
9 import java.io.ByteArrayOutputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12
13 import javax.activation.DataSource;
14 import javax.mail.MessageAware;
15 import javax.mail.MessagingException;
16 import javax.mail.Part;
17 import javax.mail.internet.ContentType;
18 import javax.mail.internet.MimeBodyPart;
19 import javax.mail.internet.MimeMessage;
20 import javax.mail.internet.ParseException;
21
22 import com.ozacc.mail.fetch.impl.sk_jp.io.ByteToCharUTF7;
23
24 /***
25 * Content-Type:の不適合をISO-2022-JPに補正します。
26 * さらにcharset=UTF-7の場合にUTF-16のストリームに変換してgetContent()を
27 * 無理やり成功させます。<BR>
28 * また、未知のTES(Content-Transfer-Encoding:)だった場合に、"7bit"
29 * と見なしてボディを取得します。
30 * 使用方法は<PRE>
31 * Object o = new DataHandler(
32 * new CorrectedContentTypeDataSourceUTF7Support(part, charset)
33 * ).getContent();
34 * </PRE><P>のようになります。</P><P>
35 * スレッドセーフではありませんので利用者側で排他制御を行ってください。
36 * </P>
37 * @author Shin
38 * @version $Revision: 1.1.2.1 $ $Date: 2004/09/29 00:57:59 $
39 */
40 class CorrectedContentTypeDataSourceUTF7Support extends CorrectedContentTypeDataSource {
41
42 private boolean utf7 = false;
43
44 public CorrectedContentTypeDataSourceUTF7Support() {}
45
46 public CorrectedContentTypeDataSourceUTF7Support(DataSource dataSource, String defaultCharset) {
47 super(dataSource, defaultCharset);
48 }
49
50 public CorrectedContentTypeDataSourceUTF7Support(Part part, String defaultCharset)
51 throws MessagingException {
52 super(part, defaultCharset);
53 }
54
55 public void setDataSource(DataSource newSource) {
56 super.setDataSource(newSource);
57 utf7 = false;
58 }
59
60 public void setDefaultCharset(String defaultCharset) {
61 super.setDefaultCharset(defaultCharset);
62 utf7 = false;
63 }
64
65 public String getContentType() {
66 try {
67 ContentType contentType = new ContentType(super.getContentType());
68 String specifiedCharset = contentType.getParameter("charset");
69 if ("UTF-7".equalsIgnoreCase(specifiedCharset)) {
70 // UTF-7コンバータが存在しない為、
71 // 独自フィルタストリームを用いる。
72 contentType.setParameter("charset", "UTF-16");
73 utf7 = true;
74 }
75 return contentType.toString();
76 } catch (ParseException e) {
77 throw new InternalError();
78 }
79 }
80
81 public InputStream getInputStream() throws IOException {
82 InputStream in = null;
83 if (isInvalidEncodingAsMultipart()) {
84 // multipart/*でありながら、不正なTransfer-Encodingだった場合
85 // 2001/09/01 JPhone(SH07)の送信する画像付きメイルが、
86 // Content-Type: multipart/mixed
87 // Content-Transfer-Encoding: base64
88 // 等というメッセージを送る場合があり、JavaMailが
89 // これをデコードできない問題を回避。
90 // multipart/*の場合のContent-Transfer-Encodingは、
91 // "7bit""8bit""binary"に限られる。
92 // それ以外の場合は生ストリームを返すようにしておく。
93 in = getRawInputStream();
94 }
95 if (in == null) {
96 try {
97 in = super.getInputStream();
98 } catch (IOException e) {
99 // ここでのIOExceptionはエンコーディング不良の可能性が高い。
100 // 生InputStreamを得てリトライ
101 in = getRawInputStream();
102 if (in == null)
103 throw e;
104 }
105 }
106 if (!utf7) {
107 return in;
108 }
109 ByteArrayOutputStream out = new ByteArrayOutputStream();
110 int c;
111
112 while ((c = in.read()) != -1) {
113 out.write(c);
114 }
115
116 ByteToCharUTF7 btc = new ByteToCharUTF7();
117 byte[] bytes = out.toByteArray();
118 char[] chars = new char[bytes.length];
119
120 // Bug fixed. Thanx to MOHI.
121 // http://www.sk-jp.com/cgi-bin/treebbs.cgi?all=1220&s=1220
122 int len = btc.convert(bytes, 0, bytes.length, chars, 0, chars.length);
123 char[] w = new char[len];
124 System.arraycopy(chars, 0, w, 0, len);
125 String string = new String(w);
126 return new ByteArrayInputStream(string.getBytes("UTF-16"));
127 }
128
129 // Transfer-Encodingにしたがったデコードを行う前のストリームを得ます。
130 // sourceがMessageAwareでない場合はnullが返されます。
131 private InputStream getRawInputStream() throws IOException {
132 if (!(source instanceof MessageAware)) {
133 return null;
134 }
135 Part part = ((MessageAware)source).getMessageContext().getPart();
136 try {
137 if (part instanceof MimeMessage) {
138 return ((MimeMessage)part).getRawInputStream();
139 } else if (part instanceof MimeBodyPart) {
140 return ((MimeBodyPart)part).getRawInputStream();
141 } else {
142 return null;
143 }
144 } catch (MessagingException mex) {
145 throw new IOException(mex.toString());
146 }
147 }
148
149 // 不正なContent-Transfer-Encodingの場合にtrueを返します。
150 private boolean isInvalidEncodingAsMultipart() {
151 try {
152 if (!new ContentType(getContentType()).match("multipart/*")) {
153 return false;
154 }
155 if (!(source instanceof MessageAware)) {
156 return false;
157 }
158 Part part = ((MessageAware)source).getMessageContext().getPart();
159 String encoding = ((javax.mail.internet.MimePart)part).getEncoding();
160 if ("7bit".equalsIgnoreCase(encoding) || "8bit".equalsIgnoreCase(encoding)
161 || "binary".equalsIgnoreCase(encoding)) {
162 return false;
163 }
164 } catch (Exception e) {
165 // この場合も不正だ、と。
166 }
167 return true;
168 }
169
170 }