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 = files.get(i).getFileName(); 096 if( name == null ) { // message か、ファイル名未指定のケース 097 nms[i] = "noNameFile" + i + ".tmp" ; 098 } 099 // 4.3.3.5 (2008/11/08) 日本語添付ファイルが処理できるように修正 100 else { 101 nms[i] = MailMessage.mimeDecode( name ); 102 } 103 104 // 重複チェック 105 if( !set.add( nms[i] ) ) { 106 nms[i] = i + "_" + nms[i] ; // 重複時に名称変更します。 107 } 108 } 109 } 110 catch( MessagingException ex ) { 111 String errMsg = "メッセージ情報のハンドリングに失敗しました。" 112 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 113 throw new RuntimeException( errMsg,ex ); 114 } 115 catch( IOException ex ) { 116 String errMsg = "テキスト情報の取り出しに失敗しました。" 117 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 118 throw new RuntimeException( errMsg,ex ); 119 } 120 return nms; 121 } 122 123 /** 124 * 添付ファイルが存在するかどうかをサーチします。 125 * 126 * 添付ファイルは、マルチパートで指定されると、再帰的に検索する必要が 127 * 出てきます。このメソッドでは、再帰的にファイルかどうかを検索し、 128 * ファイルであれば、内部変数(List)に追加(add)していきます。 129 * 130 * @param part Partオブジェクト 131 * 132 * @return 再帰検索終了 true 133 * @throws MessagingException javax.mail 関連のエラーが発生したとき 134 * @throws IOException 入出力エラーが発生したとき 135 * 136 */ 137 private boolean fileSearch( final Part part ) throws MessagingException ,IOException { 138 if( part.isMimeType( "multipart/*" ) ) { 139 Multipart mpt = (Multipart)part.getContent(); 140 141 int count = mpt.getCount(); 142 for(int i = 0; i < count; i++) { 143 BodyPart bpt = mpt.getBodyPart(i); 144 fileSearch( bpt ); 145 } 146 } 147 else { 148 if( part.isMimeType( "message/*" ) || 149 part.getFileName() != null || 150 Part.INLINE.equalsIgnoreCase( part.getDisposition() ) ) { 151 files.add( part ); 152 } 153 } 154 return true; 155 } 156 157 /** 158 * 添付ファイルを指定のフォルダにセーブします。 159 * 160 * 内部変数List の 添付ファイルを持つ Part について、ファイルを抜出し、 161 * 指定のディレクトリに保存していきます。 162 * ファイル名は、基本的に添付ファイル名そのものですが、 163 * 同一名称の添付ファイルが複数登録されている場合は、その重複ファイルの番号を 164 * 頭につけ、番号 + "_" + 添付ファイル名 として、ユニーク化します。 165 * 166 * ※ ディレクトリの作成に失敗した場合、RuntimeException が throw されます。 167 * 168 * @param dir セーブするディレクトリ。null の場合は、セーブしない。 169 * @param newNm セーブするファイル名 null の場合は、非重複化された添付ファイル名 170 * @param fno 添付ファイルの番号 171 */ 172 public void saveFileName( final String dir, final String newNm, final int fno ) { 173 if( dir == null ) { return ; } // ファイルをセーブしない。 174 175 File fileDir = new File( dir ); 176 if( !fileDir.exists() ) { 177 boolean isOk = fileDir.mkdirs(); 178 if( ! isOk ) { 179 String errMsg = "ディレクトリの作成に失敗しました。[" + dir + "]"; 180 throw new RuntimeException( errMsg ); 181 } 182 } 183 184 String newName = ( newNm != null ) ? newNm : names[fno] ; 185 186 InputStream input = null; 187 FileOutputStream output = null; 188 189 try { 190 Part prt = files.get( fno ); 191 input = prt.getInputStream(); 192 output = new FileOutputStream( new File( fileDir,newName ) ); 193 byte[] buf = new byte[1024]; 194 int len; 195 while( (len = input.read(buf)) != -1 ) { 196 output.write( buf,0,len ); 197 } 198 } 199 catch( MessagingException ex ) { 200 String errMsg = "メッセージオブジェクトの操作中にエラーが発生しました。" 201 + "dir=[" + dir + "], file=[" + newName + "], No=[" + fno + "]" 202 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 203 throw new RuntimeException( errMsg,ex ); 204 } 205 catch( IOException ex ) { 206 String errMsg = "添付ファイルの取り扱い中にエラーが発生しました。" 207 + "dir=[" + dir + "], file=[" + newName + "], No=[" + fno + "]" 208 + ex.getMessage(); // 5.1.8.0 (2010/07/01) errMsg 修正 209 throw new RuntimeException( errMsg,ex ); 210 } 211 finally { 212 Closer.ioClose( output ); 213 Closer.ioClose( input ); 214 } 215 } 216}