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     */
016    package org.opengion.fukurou.mail;
017    
018    import org.opengion.fukurou.util.Closer ;
019    
020    import javax.mail.MessagingException;
021    import javax.mail.Part;
022    import javax.mail.BodyPart;
023    import javax.mail.Multipart;
024    import java.io.File;
025    import java.io.InputStream;
026    import java.io.FileOutputStream;
027    import java.io.IOException;
028    import java.util.List;
029    import java.util.ArrayList;
030    import java.util.Set;
031    import java.util.HashSet;
032    
033    /**
034     * メール添付ファイル処?ラス
035     *
036     * こ?クラスは、添付ファイルを??るため?クラスです?
037     * 添付ファイルは、?ルチパートに含まれて?為、?帰?探す?があります?
038     *
039     * @version  4.0
040     * @author   Kazuhiko Hasegawa
041     * @since    JDK5.0,
042     */
043    public 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
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             * @param       dir     セーブするディレクトリ。null の場合?、セーブしな??
182             * @param       newNm   セーブするファイル?null の場合??重?された添付ファイル?
183             * @param       fno     添付ファイルの番号
184             *
185             * @throws RuntimeException
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    }