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