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.StringUtil ;
019    import org.opengion.fukurou.util.HybsEntry ;
020    import org.opengion.fukurou.util.LogWriter;
021    
022    import java.util.Properties;
023    import java.util.List;
024    import java.util.ArrayList;
025    
026    import javax.mail.Session;
027    import javax.mail.Store;
028    import javax.mail.Folder;
029    import javax.mail.Message;
030    import javax.mail.Flags;
031    import javax.mail.MessagingException;
032    import javax.mail.NoSuchProviderException;
033    import javax.mail.search.SearchTerm;
034    import javax.mail.search.SubjectTerm;
035    import javax.mail.search.FromStringTerm;
036    import javax.mail.search.BodyTerm;
037    import javax.mail.search.HeaderTerm;
038    import javax.mail.search.AndTerm;
039    
040    /**
041     * MailRX は、POP3プロトコルによるメール受信プログラ?す?
042     *
043     * メールへの接続条件(host,user,passwd など)と?択条件(matchTermなど)を指定し?
044     * MailReceiveListener をセ?して、start() メソ?を呼びます?
045     * 実際のメール処??、MailReceiveListener を介して?メールずつ処?ます?
046     * 添付ファイルを??る?合?、MailAttachFiles クラスを使用します?
047     *
048     *        host          メールサーバ?(??)
049     *        user          メールを取得するログインユーザー(??)
050     *        passwd        メールを取得するログインパスワー???)
051     *        protocol      受信サーバ?のプロトコル[imap/pop3]を指?初期値:pop3)
052     *        port          受信サーバ?のポ?トを??初期値:-1)
053     *        mbox          受信サーバ?のメールボックスを指?初期値:INBOX)
054     *        maxRowCount   受信メールの?取り込み件数(初期値:100)(0:[無制限])
055     *        charset       メールの?ォルトエンコー?初期値:ISO-2022-JP)
056     *        matchTerm     受信メールを選択する条件のMINEntryオブジェク?
057     *        delete        検索後?メールをサーバ?から削除するかど?を?true/falseで??初期値:false)?
058     *
059     * @version  4.0
060     * @author   Kazuhiko Hasegawa
061     * @since    JDK5.0,
062     */
063    public class MailRX {
064    
065            /** 受信メールの?取り込み件数を指定します? {@value}  */
066            public static final int MAX_ROW_COUNT = 100 ;
067    
068            /** 検索後?メールをサーバ?から削除するかど?を?true/falseで?します? {@value}  */
069            public static final boolean DELETE_MESSAGE = false ;
070    
071            /** メールサーバ?の?ォルト?ロトコル {@value}  */
072            public static final String PROTOCOL = "pop3" ;
073    
074            /** メールサーバ?の?ォルト?ート番号 {@value}  */
075            public static final int PORT = -1 ;
076    
077            /** メールサーバ?の?ォルトメールボックス {@value}  */
078            public static final String MBOX = "INBOX" ;
079    
080            /** メールの?ォルトエンコー?{@value}
081             * Windwos-31J , MS932 , ISO-2022-JP を指定します?
082             */
083            public static final String CHARSET = "ISO-2022-JP" ;
084    
085            // メール受信毎に発生するイベントを伝えるリスナ?を登録します?
086            private MailReceiveListener listener = null;
087    
088            private String  host            = null;
089            private String  user            = null;
090            private String  passwd          = null;
091            private String  protocol        = PROTOCOL;
092            private int             port            = PORT;
093            private String  mbox            = MBOX;
094            private boolean deleteFlag      = DELETE_MESSAGE;
095    
096            private String  charset         = CHARSET;
097    
098            private int             maxRowCount     = MAX_ROW_COUNT;
099            private final List<HybsEntry>     matchList       = new ArrayList<HybsEntry>();
100            private boolean debug           = false;
101    
102            /**
103             * レシーバ?を開始します?
104             *
105             */
106            public void start() throws MessagingException,NoSuchProviderException {
107    
108                    // パラメータの解析?取?
109                    debugMsg( "パラメータの解析?取? );
110    
111                    // ??条件にマッチしたメ?ージのみ抜き出す為の、SearchTerm オブジェクト?作?
112                    debugMsg( "??条件にマッチしたメ?ージのみ抜き出す条件を設定します?"  );
113                    HybsEntry[] matchs = matchList.toArray( new HybsEntry[matchList.size()] );
114                    SearchTerm[] term = new SearchTerm[matchs.length];
115                    for( int i=0; i<matchs.length; i++ ) {
116                            String key = matchs[i].getKey();
117                            if( "Subject".equalsIgnoreCase( key ) ) {
118                                    term[i] = new SubjectTerm( matchs[i].getValue() );
119                            }
120                            else if( "From".equalsIgnoreCase( key ) ) {
121                                    term[i] = new FromStringTerm( matchs[i].getValue() );
122                            }
123                            else if( "Body".equalsIgnoreCase( key ) ) {
124                                    term[i] = new BodyTerm( matchs[i].getValue() );
125                            }
126                            else {
127                                    term[i] = new HeaderTerm( key,matchs[i].getValue() );
128                            }
129                    }
130                    SearchTerm srchTerm = new AndTerm( term );
131    
132                    // 空の properties を設定?気休め程度に、?期?を設定しておきます?
133                    debugMsg( "空の properties を設?  );
134                    Properties prop = new Properties();
135                    prop.setProperty("mail.mime.charset", charset);
136                    prop.setProperty("mail.mime.decodetext.strict", "false");
137                    prop.setProperty("mail.mime.address.strict", "false");
138    
139                    // session を取?
140                    debugMsg( "session を取? );
141                    Session session = Session.getInstance(prop, null);
142    
143                    Store store = null;
144                    Folder folder = null;
145                    try {
146                            // store の取?
147                            debugMsg( "store の取?protocol=",protocol );
148                            store = session.getStore( protocol );
149    
150                            // サーバ?と connect します?
151                            debugMsg( "サーバ?と connect します?" );
152                            store.connect(host, port, user, passwd);
153    
154                            // folder の取?
155                            debugMsg( "folder の取? );
156                            folder = store.getFolder( mbox );
157                            if( deleteFlag ) {
158                                    folder.open(Folder.READ_WRITE);
159                            }
160                            else {
161                                    folder.open(Folder.READ_ONLY);
162                            }
163    
164                            // メ?ージ??の取?
165                            debugMsg( "メ?ージ??の取? );
166            //              Message[] message = folder.getMessages();
167                            Message[] message = folder.search( srchTerm );
168    
169                            for(int i=0, n=message.length; i<n && i<maxRowCount; i++) {
170                                    MailMessage mailMessage = new MailMessage( message[i],host,user );
171                                    debugMsg( "[" , String.valueOf(i) , "]" , mailMessage.getMessageID() , " 受信中" );
172    
173                                    // メールの削除[true/false]:先にフラグを立てて?ので、エラーでも削除されます?
174                                    message[i].setFlag(Flags.Flag.DELETED, deleteFlag);
175    
176                                    boolean okFlag = true;
177                                    if( listener != null ) {
178                                            // メール本体?処?
179                                            okFlag = listener.receive( mailMessage );
180                                    }
181    
182                                    // 受?確認?返信メール
183                                    String notifyTo = mailMessage.getNotificationTo() ;
184                                    if( okFlag && notifyTo != null ) {
185                                            MailTX tx = new MailTX( host );
186                                            tx.setFrom( user );
187                                            tx.setTo( StringUtil.csv2Array( notifyTo ) );
188                                            tx.setSubject( "受?:" + mailMessage.getSubject() );
189                                            tx.setMessage( mailMessage.getContent() );
190                                            tx.sendmail();
191                                    }
192                            }
193                    }
194                    finally {
195                            // セ?ョン終?
196                            debugMsg( "セ?ョン終??? );
197                            if( folder != null ) {
198                                    folder.close(deleteFlag);               // true の場合?、終?に実際に削除します?
199                            }
200                            if( store != null ) {
201                                    store.close();
202                            }
203                    }
204            }
205    
206            /**
207             * メールサーバ?をセ?します?
208             *
209             * @param       host メールサーバ?
210             * @throws      IllegalArgumentException 引数?null の場合?
211             */
212            public void setHost( final String host ) {
213                    if( host == null ) {
214                            String errMsg = "host に null はセ?出来ません?;
215                            throw new IllegalArgumentException( errMsg );
216                    }
217    
218                    this.host = host;
219            }
220    
221            /**
222             * 受信ユーザーをセ?します?
223             *
224             * @param       user 受信ユーザー
225             * @throws      IllegalArgumentException 引数?null の場合?
226             */
227            public void setUser( final String user ) {
228                    if( user == null ) {
229                            String errMsg = "user に null はセ?出来ません?;
230                            throw new IllegalArgumentException( errMsg );
231                    }
232                    this.user = user;
233            }
234    
235            /**
236             * パスワードをセ?します?
237             *
238             * @param       passwd パスワー?
239             * @throws      IllegalArgumentException 引数?null の場合?
240             */
241            public void setPasswd( final String passwd ) {
242                    if( passwd == null ) {
243                            String errMsg = "passwd に null はセ?出来ません?;
244                            throw new IllegalArgumentException( errMsg );
245                    }
246                    this.passwd = passwd;
247            }
248    
249            /**
250             * 受信プロトコルをセ?します?
251             *
252             * @param       protocol 受信プロトコル?
253             * @throws      IllegalArgumentException 引数?null の場合?
254             */
255            public void setProtocol( final String protocol ) {
256                    if( protocol == null ) {
257                            String errMsg = "protocol に null はセ?出来ません?;
258                            throw new IllegalArgumentException( errMsg );
259                    }
260                    this.protocol = protocol;
261            }
262    
263            /**
264             * ポ?ト番号をセ?します?
265             *
266             * @param       port ポ?ト番号
267             */
268            public void setPort( final int port ) {
269                    this.port = port;
270            }
271    
272            /**
273             * 受信メイルボックスをセ?します?
274             *
275             * @param       mbox 受信メイルボックス?
276             * @throws      IllegalArgumentException 引数?null の場合?
277             */
278            public void setMbox( final String mbox ) {
279                    if( mbox == null ) {
280                            String errMsg = "mbox に null はセ?出来ません?;
281                            throw new IllegalArgumentException( errMsg );
282                    }
283                    this.mbox = mbox;
284            }
285    
286            /**
287             * メール受信毎に発生するイベントを伝えるリスナ?をセ?します?
288             *
289             * @param       listener MailReceiveリスナ?
290             */
291            public void setMailReceiveListener( final MailReceiveListener listener ) {
292                    this.listener = listener;
293            }
294    
295            /**
296             * メ?ージをメールサーバ?から削除するかど?をセ?します?
297             *
298             * @param       deleteFlag 削除するかど?[true:行う/false:行わない]
299             */
300            public void setDelete( final boolean deleteFlag ) {
301                    this.deleteFlag = deleteFlag;
302            }
303    
304            /**
305             * ?エンコー?ングをセ?します?
306             *
307             * ?エンコー?ングには、Windwos-31J , MS932 , ISO-2022-JP を指定できます?
308             * 初期値は、SystemResource.properties ファイルの MAIL_DEFAULT_CHARSET 属?で
309             * 設定できます?
310             *
311             * @param   charset ?エンコー?ング
312             * @throws      IllegalArgumentException 引数?null の場合?
313             */
314            public void setCharset( final String charset ) {
315                    if( charset == null ) {
316                            String errMsg = "charset に null はセ?出来ません?;
317                            throw new IllegalArgumentException( errMsg );
318                    }
319                    this.charset = charset;
320            }
321    
322            /**
323             * ?取り込み件数をセ?しま?初期値:100)(0:[無制限])?
324             *
325             * @og.rev 5.5.8.5 (2012/11/27) 0を無制限として処?ます?
326             *
327             * @param       maxRowCount ?取り込み件数
328             */
329            public void setMaxRowCount( final int maxRowCount ) {
330    //              this.maxRowCount = maxRowCount;
331                    this.maxRowCount = ( maxRowCount > 0 ) ? maxRowCount : Integer.MAX_VALUE ;
332            }
333    
334            /**
335             * メール検索する場合?マッチ条件のキーと値の HybsEntry をセ?します?
336             * Subject,From,Body,それ以外?、Header ??をキーにします?
337             *
338             * @param       matchTerm HybsEntryオブジェク?
339             */
340            public void addMatchTerm( final HybsEntry matchTerm ) {
341                    matchList.add( matchTerm );
342            }
343    
344            /**
345             * ????の表示を行うかど?をセ?します?
346             *
347             * @param       debug 有無[true/false]
348             */
349            public void setDebug( final boolean debug ) {
350                    this.debug = debug;
351            }
352    
353            /**
354             * ????の表示を行います?
355             * 実際の処??、debug フラグに設定?によります?
356             *
357             * @param       msgs String... 可変長メ?ージ
358             */
359            private void debugMsg( final String... msgs ) {
360                    if( debug ) {
361                            for( String msg : msgs ) {
362                                    System.out.print( msg );
363                            }
364                            System.out.println();
365                    }
366            }
367    
368            /**
369             * コマンドから実行できる、テスト用の main メソ?です?
370             *
371             * java org.opengion.fukurou.mail.MailTX <from> <to> <host> <file> ....
372             * で、?の添付ファイルを?付することができます?
373             *
374             * @param   args 引数配?
375             */
376            public static void main( final String[] args ) throws Exception {
377                    if(args.length < 3) {
378                            LogWriter.log("Usage: java org.opengion.fukurou.mail.MailRX <host> <user> <passwd> [<saveDir>]");
379                            System.exit(1);
380                    }
381                    final String dir = (args.length == 4) ? args[3] : null;
382    
383                    MailRX recive = new MailRX();
384    
385                    recive.setHost( args[0] );
386                    recive.setUser( args[1] );
387                    recive.setPasswd( args[2] );
388                    recive.setCharset( "ISO-2022-JP" );
389    
390                    MailReceiveListener listener = new MailReceiveListener() {
391                            public boolean receive( final MailMessage message ) {
392                                    System.out.println( message.getSimpleMessage() );
393    
394                                    if( dir != null ) {
395                                            message.saveSimpleMessage( dir );
396                                    }
397                                    return true ;
398                            }
399                    };
400                    recive.setMailReceiveListener( listener );
401    
402                    recive.start();
403            }
404    }