001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.mail; 017 018import org.opengion.fukurou.util.Closer ; 019 020import javax.mail.MessagingException; 021import javax.mail.Part; 022import javax.mail.BodyPart; 023import javax.mail.Multipart; 024import java.io.File; 025import java.io.InputStream; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.util.List; 029import java.util.ArrayList; 030import java.util.Set; 031import java.util.HashSet; 032 033/** 034 * メール添付ファイル処理クラス 035 * 036 * このクラスは、添付ファイルを処理するためのクラスです。 037 * 添付ファイルは、マルチパートに含まれている為、再帰的に探す必要があります。 038 * 039 * @version 4.0 040 * @author Kazuhiko Hasegawa 041 * @since JDK5.0, 042 */ 043public class MailAttachFiles { 044 private final List<Part> files ; 045 private final String[] names ; 046 047 /** 048 * デフォルトコンストラクター 049 * 050 * 内部変数の初期化を行います。 051 * 052 * @param part Partオブジェクト 053 */ 054 public MailAttachFiles( final Part part ) { 055 files = new ArrayList<Part>(); 056 names = makeNames( part ); 057 } 058 059 /** 060 * 添付ファイルの名称を文字列配列として求めます。 061 * 062 * @return 添付ファイルの名称を文字列配列 063 */ 064 public String[] getNames() { 065 String[] rtn = null ; 066 067 if( names != null ) { rtn = names.clone(); } 068 069 return rtn ; 070 } 071 072 /** 073 * 添付ファイルの名称を文字列配列として求めます。 074 * 075 * この処理の中で、添付ファイルを持つ Part を見つけて内部配列(List)に登録します。 076 * ファイル名が未指定の場合は、"noNameFile" + i + ".tmp" というファイル名をつけます。 077 * i は、添付ファイルの連番です。 078 * また、同一添付ファイル名が存在する場合は、頭に添付ファイルの連番を付加して、 079 * ファイル名としてユニーク化します。 080 * 081 * @og.rev 4.3.3.5 (2008/11/08) 日本語添付ファイルが処理できるように修正 082 * 083 * @param part Partオブジェクト 084 * 085 * @return 添付ファイルの名称を文字列配列 086 */ 087 private String[] makeNames( final Part part ) { 088 final String[] nms; 089 try { 090 Set<String> set = new HashSet<String>(); 091 092 fileSearch( part ); 093 nms = new String[files.size()]; 094 for( int i=0; i<nms.length; i++ ) { 095 // String name = ((Part)files.get(i)).getFileName(); 096 String name = (files.get(i)).getFileName(); 097 if( name == null ) { // message か、ファイル名未指定のケース 098 nms[i] = "noNameFile" + i + ".tmp" ; 099 } 100// else { 101// // encode-word の =? の前にはスペースが必要。 102// StringBuilder buf = new StringBuilder( name ); 103// int pos = buf.indexOf( "?==?" ); // デコードの終了と開始が連結している箇所 104// // 先頭でなく、かつ開始記号が含まれている。 105// while( pos > 0 ) { 106// buf.insert( pos+2," " ); 107// pos = buf.indexOf( "?==?",pos+4 ); 108// } 109// } 110 // 4.3.3.5 (2008/11/08) 日本語添付ファイルが処理できるように修正 111 else { 112 nms[i] = MailMessage.mimeDecode( name ); 113 } 114 115 // 重複チェック 116 if( !set.add( nms[i] ) ) { 117 nms[i] = i + "_" + nms[i] ; // 重複時に名称変更します。 118 } 119 } 120 } 121 catch( MessagingException ex ) { 122 String errMsg = "メッセージ情報のハンドリングに失敗しました。" 123 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 124 throw new RuntimeException( errMsg,ex ); 125 } 126// catch( UnsupportedEncodingException ex ) { 127// String errMsg = "テキスト情報のデコードに失敗しました。" ; 128// throw new RuntimeException( errMsg,ex ); 129// } 130 catch( IOException ex ) { 131 String errMsg = "テキスト情報の取り出しに失敗しました。" 132 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 133 throw new RuntimeException( errMsg,ex ); 134 } 135 return nms; 136 } 137 138 /** 139 * 添付ファイルが存在するかどうかをサーチします。 140 * 141 * 添付ファイルは、マルチパートで指定されると、再帰的に検索する必要が 142 * 出てきます。このメソッドでは、再帰的にファイルかどうかを検索し、 143 * ファイルであれば、内部変数(List)に追加(add)していきます。 144 * 145 * @param part Partオブジェクト 146 * 147 * @return 再帰検索終了 true 148 * @throws MessagingException javax.mail 関連のエラーが発生したとき 149 * @throws IOException 入出力エラーが発生したとき 150 * 151 */ 152 private boolean fileSearch( final Part part ) throws MessagingException ,IOException { 153 if( part.isMimeType( "multipart/*" ) ) { 154 Multipart mpt = (Multipart)part.getContent(); 155 156 int count = mpt.getCount(); 157 for(int i = 0; i < count; i++) { 158 BodyPart bpt = mpt.getBodyPart(i); 159 fileSearch( bpt ); 160 } 161 } 162 else { 163 if( part.isMimeType( "message/*" ) || 164 part.getFileName() != null || 165 Part.INLINE.equalsIgnoreCase( part.getDisposition() ) ) { 166 files.add( part ); 167 } 168 } 169 return true; 170 } 171 172 /** 173 * 添付ファイルを指定のフォルダにセーブします。 174 * 175 * 内部変数List の 添付ファイルを持つ Part について、ファイルを抜出し、 176 * 指定のディレクトリに保存していきます。 177 * ファイル名は、基本的に添付ファイル名そのものですが、 178 * 同一名称の添付ファイルが複数登録されている場合は、その重複ファイルの番号を 179 * 頭につけ、番号 + "_" + 添付ファイル名 として、ユニーク化します。 180 * 181 * ※ ディレクトリの作成に失敗した場合、RuntimeException が throw されます。 182 * 183 * @param dir セーブするディレクトリ。null の場合は、セーブしない。 184 * @param newNm セーブするファイル名 null の場合は、非重複化された添付ファイル名 185 * @param fno 添付ファイルの番号 186 */ 187 public void saveFileName( final String dir, final String newNm, final int fno ) { 188 if( dir == null ) { return ; } // ファイルをセーブしない。 189 190 File fileDir = new File( dir ); 191 if( !fileDir.exists() ) { 192 boolean isOk = fileDir.mkdirs(); 193 if( ! isOk ) { 194 String errMsg = "ディレクトリの作成に失敗しました。[" + dir + "]"; 195 throw new RuntimeException( errMsg ); 196 } 197 } 198 199 String newName = ( newNm != null ) ? newNm : names[fno] ; 200 201 InputStream input = null; 202 FileOutputStream output = null; 203 204 try { 205 Part prt = files.get( fno ); 206 input = prt.getInputStream(); 207 output = new FileOutputStream( new File( fileDir,newName ) ); 208 byte[] buf = new byte[1024]; 209 int len; 210 while( (len = input.read(buf)) != -1 ) { 211 output.write( buf,0,len ); 212 } 213 } 214 catch( MessagingException ex ) { 215 String errMsg = "メッセージオブジェクトの操作中にエラーが発生しました。" 216 + "dir=[" + dir + "], file=[" + newName + "], No=[" + fno + "]" 217 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 218 throw new RuntimeException( errMsg,ex ); 219 } 220 catch( IOException ex ) { 221 String errMsg = "添付ファイルの取り扱い中にエラーが発生しました。" 222 + "dir=[" + dir + "], file=[" + newName + "], No=[" + fno + "]" 223 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 224 throw new RuntimeException( errMsg,ex ); 225 } 226 finally { 227 Closer.ioClose( output ); 228 Closer.ioClose( input ); 229 } 230 } 231}