📄 mailsource.java
字号:
/*
Jacson
Copyright (C) 2003 Patrick Carl, patrick.carl@web.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package de.spieleck.app.jacson.source;
import de.spieleck.app.jacson.JacsonException;
import de.spieleck.app.jacson.JacsonReport;
import de.spieleck.app.jacson.JacsonState;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Properties;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Flags.Flag;
import javax.mail.search.FlagTerm;
import javax.mail.search.SearchTerm;
/**
* This class implements a JacsonChunkSource for emails using.<br>
* It supports the POP3 and the IMAP protocolls. When using IMAP processed
* mails are marked as being seen and at default only unseen mails are
* processed. So you can avoid double processing by using IMAP. If you have to
* use POP3 and have to avoid double processing - :( Not possible at the
* moment. But remember, it's open source :-) <br>
* This class needs the JavaMail and the Java activation framework.<br>
* Notice that a mail consists of an header and a body. The header contains
* information like subject, sender or receiver. The body contains the actual
* text of the mail. To indicate to which part a chunk belongs, the name of
* the header field or the value of the constant @link MailSouce#BODY is stored
* within the JacsonState connected to @link MailSource#JACSON_STATE_CHUNK_TYPE.
* <br>Furthermore a mail starts with a header so whenever you get a header
* chunk and the last was a body chunk a new mail began.<br>
* For details see
* <a href="http://www.faqs.org/ftp/rfc/rfc822.txt">RFC 822</a>.
*
* @author Patrick Carl
* @author fsn
* @version 0.71
*/
public class MailSource
extends ChunkSourceBase {
/**
* indicates that the current chunk is part of the mail's body
*/
public static final String BODY = "Body";
/**
* name of the parameter used to indicate the chunk type within JacsonState
*/
public static final String JACSON_STATE_CHUNK_TYPE =
"de.spieleck.app.source.MailSource.ChunkType";
/**
* String constant used to say that MailSource that it should use the
* IMAP protocoll for receiving mails
*/
public static final String IMAP = "imap";
/**
* String constant used to say that MailSource that it should use the
* POP3 protocoll for receiving mails
*/
public static final String POP3 = "pop3";
/**
* some things for the mail stuff
*/
private String user;
private String password;
private String mailServer;
private String protocoll;
private Folder folder;
private Message[] messages;
private SearchTerm searchTerm;
/**
* this thread is used to read in the mails in an own thread
*/
private Thread messageParserThread;
/**
* this is where the thread puts its chunks
*/
private LinkedList chunks;
/**
* Creates a new instance of Pop3Source with the given settings. Only those
* mails are processed which have not set the SEEN flag (does not work
* with POP3)
* @param user user of the mailbox read
* @param password users password at the mailbox read
* @param mailServer server of the mailbox read
*/
public MailSource(String user, String password, String mailServer)
throws JacsonException {
this(user, password, mailServer,
new FlagTerm(new Flags(Flag.SEEN), false));
}
/**
* A using the given settings but only receives
* messages that match the given SearchTerm
* @param user user of the mailbox read
* @param password users password at the mailbox read
* @param mailServer server of the mailbox read
* @param searchTerm a SearchTerm to select messages to read
*/
public MailSource(String user, String password, String mailServer,
SearchTerm searchTerm) throws JacsonException {
this.user = user;
this.password = password;
this.mailServer = mailServer;
chunks = new LinkedList();
this.searchTerm = searchTerm;
}
protected void finalize() throws Throwable {
cleanUp();
super.finalize();
}
/**
* Cleaning up resources
*/
protected void cleanUp() throws JacsonException {
try{
if (protocoll.equals(IMAP))
folder.setFlags(messages, new Flags(Flag.SEEN), true);
folder.close(true);
} catch(Exception e){
e.printStackTrace();
throw new JacsonException("Exception during cleanUp", e);
}
}
/**
* sets the protocoll used to retrieve emails. It the given parameter is
* not a known protocoll, IMAP will be used instead.
*/
public void setProtocoll(String protocoll) {
// we need always a lowercase protocoll, if user provides Pop3 we can
// assume he wants to use pop3
if (protocoll == null){
this.protocoll = IMAP;
}
protocoll = protocoll.toLowerCase();
if (POP3.equals(protocoll) || IMAP.equals(protocoll))
this.protocoll = protocoll;
else{
System.out.println("MailSource can only use " + IMAP + " or " + POP3
+ " to receive mails. You provided an unknown protocoll. MailSource "
+ "will use " + IMAP + " as default.");
this.protocoll = IMAP;
}
}
/**
* receives the message, filters them and starts a new Thread to
* parse the Messages
*/
public synchronized void startMessageFetching()
throws JacsonException {
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
try{
if (protocoll == null)
protocoll = IMAP;
Store store = session.getStore(protocoll);
store.connect(mailServer, user, password);
folder = store.getFolder("INBOX");
if (folder == null)
throw new JacsonException("INBOX could not be opened for "
+ user + "@" + mailServer);
if (protocoll.equals(POP3))
folder.open(folder.READ_ONLY);
else if (protocoll.equals(IMAP))
folder.open(folder.READ_WRITE);
// if a SearchTerm is defined we only want the matching messages
if (searchTerm != null)
messages = folder.search(searchTerm);
else
messages = folder.getMessages();
messageParserThread = new MailSource.MessageParserThread(messages);
messageParserThread.start();
} catch(Exception e){
e.printStackTrace();
throw new JacsonException(e.getMessage());
}
}
/**
* implementation analog to LineChunkSource
*/
public String message() {
JacsonReport jr = getRegReport();
jr.begin("mail");
jr.report("protocoll", protocoll);
jr.report("server", mailServer);
jr.report("user", user);
if ( messages != null )
jr.report("mails", "" + messages.length);
return "mail";
}
/**
* implementation analog to LineChunkSource
*/
public void summary() {
getRegReport().end();
}
/** Deliver a sequence of chunks (that is Strings).
* The delievered chunks are in the same
* format which the Message.writeTo(OutputStream os) provides.
* To indicate the type of the current chunk the JacsonState parameter
* de.spieleck.app.source.MailSource.ChunkType is set to one of the
* following values:<ul>
* <li>@link
* Before
* returning null and by that indicating the end of the sequence, cleanUp
* is called to clean up resources.
* @return The next String if available, null if sequence is finished.
*/
public String nextChunk()
throws JacsonException {
// if not yet started we will start the MessageParser
if (messageParserThread == null){
startMessageFetching();
}
MarkedChunk chunk = null;
synchronized( chunks ) {
while ( chunks.isEmpty() && messageParserThread.isAlive() ) {
try {
chunks.wait();
}
catch(InterruptedException e) {
e.printStackTrace();
break;
}
}
chunk = (MarkedChunk) chunks.removeFirst();
}
if ( chunk == null ) {
cleanUp();
return null;
}
else {
getRegState().put(JACSON_STATE_CHUNK_TYPE, chunk.getExtra());
return chunk.getChunk();
}
}
/**
* main method for testing functionality
*/
public static void main(String[] args)
throws Exception {
if (args.length < 3) {
System.out.print("Usage java de.spieleck.apps." +
"jacson.source.MailSource [-p <protocoll] [-f file] <user> " +
"<password> <server>\n");
System.out.print("Example java de.spieleck.apps.jacson.source." +
" MailSource -p pop3 -f out.txt myuser mypassword myserver\n");
System.out.println("-p specifies the used protocoll, default IMAP");
System.out.println("-f specifies the file to write chunks in");
System.out.println("If no file is given chunks are written to " +
"standard out");
}
PrintWriter pw;
// check if file param was given
if (args[0].equals("-f"))
pw = new PrintWriter(new FileWriter(args[1]));
else if (args[2].equals("-f"))
pw = new PrintWriter(new FileWriter(args[2]));
else
pw = new PrintWriter(System.out);
int l = args.length;
MailSource me = new MailSource(args[l-3], args[l-2], args[l-1]);
// check if protocoll was given
if (args[0].equals("-p"))
me.setProtocoll(args[1]);
else if (args[2].equals("-p"))
me.setProtocoll(args[3]);
// now we can start the MessageFetching
me.startMessageFetching();
//Thread.sleep(1000 * 5);
JacsonState state = new JacsonState();
String line = me.nextChunk();
while(line != null){
pw.println((String) state.get(JACSON_STATE_CHUNK_TYPE)
+ "<" + line + ">");
line = me.nextChunk();
}
pw.flush();
pw.close();
}
/**
* threaded class for parsing the messages and writing the single lines
* in a Stack
*/
public class MessageParserThread
extends Thread {
private Message[] messages;
/**
* Constructs a MessageParserThread which will parse the given
* messages
*/
public MessageParserThread(Message[] messages) {
this.messages = messages;
}
/**
* parses the messages and writes the chunks to the chunk storage of
* MailSource
*/
public void run() {
for(int i=0; i < messages.length; i++) {
try {
Enumeration headers = messages[i].getAllHeaders();
Header header;
while(headers.hasMoreElements()){
header = (Header) headers.nextElement();
synchronized(chunks) {
chunks.add(new MarkedChunk(header.getName() + ": " +
header.getValue(),
header.getName()));
chunks.notify();
}
}
BufferedReader br = new BufferedReader(
new InputStreamReader(messages[i].getInputStream()));
String line = null;
while((line = br.readLine()) != null) {
synchronized(chunks) {
chunks.add(new MarkedChunk(line, BODY));
chunks.notify();
}
}
br.close();
}
catch(Exception e) {
e.printStackTrace();
}
}
synchronized(chunks) {
chunks.notify();
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -