View Javadoc

    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 }