Author: sebb
Date: Mon Sep 23 00:48:46 2013
New Revision: 1525483
URL: http://svn.apache.org/r1525483
Log:
Use IMAP URL to simplify command line
Add selector support
Modified:
commons/proper/net/trunk/src/main/java/examples/mail/IMAPImportMbox.java
Modified:
commons/proper/net/trunk/src/main/java/examples/mail/IMAPImportMbox.java
URL:
http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/examples/mail/IMAPImportMbox.java?rev=1525483&r1=1525482&r2=1525483&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/examples/mail/IMAPImportMbox.java
(original)
+++ commons/proper/net/trunk/src/main/java/examples/mail/IMAPImportMbox.java
Mon Sep 23 00:48:46 2013
@@ -21,6 +21,10 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
import org.apache.commons.net.imap.IMAPClient;
import org.apache.commons.net.imap.IMAPSClient;
@@ -29,8 +33,13 @@ import org.apache.commons.net.imap.IMAPS
* This is an example program demonstrating how to use the IMAP[S]Client class.
* This program connects to a IMAP[S] server and imports messages into the
folder from an mbox file.
* <p>
- * Usage: IMAPMail <imap[s] server hostname> <folder> <username> <password>
<mboxfile> [secure protocol, e.g. TLS]
+ * Usage: IMAPImportMbox imap[s]://user:password@host[:port]/folder/path
<mboxfile> [selectors]
* <p>
+ * An example selector might be:
+ * <ul>
+ * <li>1,2,3,7-10</li>
+ * <li>-142986- : this is useful for retrieving messages by apmail number,
which appears as From xyz-return-142986-apmail-...</li>
+ * <ul>
*/
public final class IMAPImportMbox
{
@@ -39,33 +48,93 @@ public final class IMAPImportMbox
public static void main(String[] args) throws IOException
{
- if (args.length < 5)
+ if (args.length < 2)
{
- System.err.println(
- "Usage: IMAPImportMbox <imap server hostname> <folder>
<username> <password> <mboxfile> [TLS]");
+ System.err.println("Usage: IMAPImportMbox
imap[s]://user:password@host[:port]/folder/path <mboxfile> [selectors]");
+ System.err.println("\tWhere: a selector is a list of
numbers/number ranges - 1,2,3-10 - or a list of strings to match in the initial
From line");
System.exit(1);
}
- final String server = args[0];
- final String folder = args[1];
- final String username = args[2];
- final String password = args[3];
- final String file = args[4];
- final String proto = (args.length > 5) ? args[5] : null;
+ final URI uri = URI.create(args[0]);
+ final String file = args[1];
final File mbox = new File(file);
if (!mbox.isFile() || !mbox.canRead()) {
throw new IOException("Cannot read mailbox file: " + mbox);
}
- IMAPClient imap;
+ final String userInfo = uri.getUserInfo();
+ if (userInfo == null) {
+ throw new IllegalArgumentException("Missing userInfo details");
+ }
+
+ String []userpass = userInfo.split(":");
+ if (userpass.length != 2) {
+ throw new IllegalArgumentException("Invalid userInfo details: '" +
userpass + "'");
+ }
+
+ String username = userpass[0];
+ String password = userpass[1];
+
+ String path = uri.getPath();
+ if (path == null || path.length() < 1) {
+ throw new IllegalArgumentException("Invalid folderPath: '" + path
+ "'");
+ }
+ String folder = path.substring(1); // skip the leading /
+
+ List<String> contains = new ArrayList<String>(); // list of strings to
find
+ BitSet msgNums = new BitSet(); // list of message numbers
+
+ for(int i = 2; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.matches("\\d+(-\\d+)(,\\d+(-\\d+))*")) { // number,m-n
+ for(String entry :arg.split(",")) {
+ String []parts = entry.split("-");
+ if (parts.length == 2) { // m-n
+ int low = Integer.parseInt(parts[0]);
+ int high = Integer.parseInt(parts[1]);
+ for(int j=low; j <= high; j++) {
+ msgNums.set(j);
+ }
+ } else {
+ msgNums.set(Integer.parseInt(entry));
+ }
+ }
+ } else {
+ contains.add(arg); // not a number/number range
+ }
+ }
+
+ final IMAPClient imap;
- if (proto != null) {
- System.out.println("Using secure protocol: " + proto);
- imap = new IMAPSClient(proto, true); // implicit
+ if ("imaps".equalsIgnoreCase(uri.getScheme())) {
+ System.out.println("Using secure protocol");
+ imap = new IMAPSClient(true); // implicit
+// } else if ("null".equals(uri.getScheme())) {
+// imap = new IMAPClient(){
+// @Override
+// public void connect(String host){ }
+// @Override
+// public boolean login(String user, String pass) {return true;}
+// @Override
+// public boolean logout() {return true;}
+// @Override
+// public void disconnect() {}
+// @Override
+// public void setSoTimeout(int t) {}
+// @Override
+// public boolean append(String mailboxName, String flags,
String datetime, String message) {return true;}
+// };
} else {
imap = new IMAPClient();
}
+
+ String server = uri.getHost();
+ int port = uri.getPort();
+ if (port != -1) {
+ imap.setDefaultPort(port);
+ }
+
System.out.println("Connecting to server " + server + " on " +
imap.getDefaultPort());
// We want to timeout if a response takes longer than 60 seconds
@@ -77,6 +146,8 @@ public final class IMAPImportMbox
throw new RuntimeException("Could not connect to server.", e);
}
+ int total = 0;
+ int loaded = 0;
try {
if (!imap.login(username, password)) {
System.err.println("Could not login to server. Check
password.");
@@ -90,19 +161,28 @@ public final class IMAPImportMbox
String line;
StringBuilder sb = new StringBuilder();
+ boolean wanted = false; // Skip any leading rubbish
while((line=br.readLine())!=null) {
if (line.startsWith("From ")) { // start of message; i.e. end
of previous (if any)
- process(sb, imap, folder);
+ if (process(sb, imap, folder)) { // process previous
message (if any)
+ loaded++;
+ }
+ wanted = wanted(total, line, msgNums, contains);
+ total ++;
sb.setLength(0);
} else if (line.startsWith(">From ")) { // Unescape "From " in
body text
line = line.substring(1);
}
// TODO process first Received: line to determine arrival date?
- sb.append(line);
- sb.append(CRLF);
+ if (wanted) {
+ sb.append(line);
+ sb.append(CRLF);
+ }
}
br.close();
- process(sb, imap, folder); // end of last message (if any)
+ if (wanted && process(sb, imap, folder)) { // last message (if any)
+ loaded++;
+ }
} catch (IOException e) {
System.out.println(imap.getReplyString());
e.printStackTrace();
@@ -112,11 +192,13 @@ public final class IMAPImportMbox
imap.logout();
imap.disconnect();
}
+ System.out.println("Processed " + total + " messages, loaded " +
loaded);
}
- private static void process(final StringBuilder sb, final IMAPClient imap,
final String folder) throws IOException {
+ private static boolean process(final StringBuilder sb, final IMAPClient
imap, final String folder) throws IOException {
final int length = sb.length();
- if (length > 2) {
+ boolean haveMessage = length > 2;
+ if (haveMessage) {
System.out.println("Length " + length);
sb.setLength(length-2); // drop trailing CRLF
String msg = sb.toString();
@@ -124,5 +206,37 @@ public final class IMAPImportMbox
throw new IOException("Failed to import message: " +
imap.getReplyString());
}
}
+ return haveMessage;
+ }
+
+ /**
+ * Is the message wanted?
+ *
+ * @param msgNum the message number
+ * @param line the From line
+ * @param msgNums the list of wanted message numbers
+ * @param contains the list of strings to be contained
+ * @return true if the message is wanted
+ */
+ private static boolean wanted(int msgNum, String line, BitSet msgNums,
List<String> contains) {
+ return (msgNums.isEmpty() && contains.isEmpty()) // no selectors
+ || msgNums.get(msgNum) // matches message number
+ || listContains(contains, line); // contains string
+ }
+
+ /**
+ * Is at least one entry in the list contained in the string?
+ * @param contains the list of strings to look for
+ * @param string the String to check against
+ * @return true if at least one entry in the contains list is contained in
the string
+ */
+ private static boolean listContains(List<String> contains, String string) {
+ for(String entry : contains) {
+ if (string.contains(entry)) {
+ return true;
+ }
+ }
+ return false;
}
+
}