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    }