diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
index f9aac6561c..8c6205823f 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
@@ -950,8 +950,10 @@ public class WebMail extends HttpServlet
Debug.debug(Debug.DEBUG, "OFFLINE MODE");
} else {
sessionObject.isFetching = true;
- if (mailbox.connectToServer(new ConnectWaiter(sessionObject)))
+ if (!mailbox.connectToServer(new ConnectWaiter(sessionObject))) {
+ sessionObject.error += _t("Cannot connect") + '\n';
sessionObject.isFetching = false;
+ }
}
// wait a little while so we avoid the loading page if we can
@@ -1430,13 +1432,13 @@ public class WebMail extends HttpServlet
sessionObject.isFetching = true;
ConnectWaiter cw = new ConnectWaiter(sessionObject);
if (mailbox.connectToServer(cw)) {
- // Already connected, start a thread ourselves
- // TODO - But if already connected, we aren't going to find anything new.
- // We used to call refresh() from here, which closes first,
- // but that isn't threaded.
+ // Start a thread to wait for results
Debug.debug(Debug.DEBUG, "Already connected, running CW");
Thread t = new I2PAppThread(cw, "Email fetcher");
t.start();
+ } else {
+ sessionObject.error += _t("Cannot connect") + '\n';
+ sessionObject.isFetching = false;
}
// wait if it's going to be quick
try {
@@ -2240,11 +2242,13 @@ public class WebMail extends HttpServlet
if (showRefresh) {
sessionObject.info += _t("Refresh the page for updates") + '\n';
}
- if (sessionObject.error.length() > 0) {
- out.println( "
" + quoteHTML(sessionObject.error).replace("\n", "
") + "
" );
- }
- if (sessionObject.info.length() > 0) {
- out.println( "" + quoteHTML(sessionObject.info).replace("\n", "
") + "
" );
+ if (sessionObject.error.length() > 0 || sessionObject.info.length() > 0) {
+ out.println("");
+ if (sessionObject.error.length() > 0)
+ out.println("
" + quoteHTML(sessionObject.error).replace("\n", "
") + "
");
+ if (sessionObject.info.length() > 0)
+ out.println("
" + quoteHTML(sessionObject.info).replace("\n", "
") + "
");
+ out.println("
" );
}
/*
* now write body
diff --git a/apps/susimail/src/src/i2p/susi/webmail/pop3/POP3MailBox.java b/apps/susimail/src/src/i2p/susi/webmail/pop3/POP3MailBox.java
index 938abef21e..1bc698a0c1 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/pop3/POP3MailBox.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/pop3/POP3MailBox.java
@@ -36,6 +36,7 @@ import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
+import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -120,7 +121,7 @@ public class POP3MailBox implements NewMailListener {
// we must be connected to know the UIDL to ID mapping
checkConnection();
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error fetching header: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error fetching header", ioe);
return null;
}
int id = getIDfromUIDL(uidl);
@@ -141,6 +142,7 @@ public class POP3MailBox implements NewMailListener {
Debug.debug(Debug.DEBUG, "getHeader(" + id + ")");
Buffer header = null;
if (id >= 1 && id <= mails) {
+ try { socket.setSoTimeout(120*1000); } catch (IOException ioe) {}
/*
* try 'TOP n 0' command
*/
@@ -153,6 +155,7 @@ public class POP3MailBox implements NewMailListener {
if (header == null)
Debug.debug( Debug.DEBUG, "RETR returned null" );
}
+ if (socket != null) try { socket.setSoTimeout(300*1000); } catch (IOException ioe) {}
} else {
lastError = "Message id out of range.";
}
@@ -171,7 +174,7 @@ public class POP3MailBox implements NewMailListener {
// we must be connected to know the UIDL to ID mapping
checkConnection();
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error fetching body: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error fetching body", ioe);
return null;
}
int id = getIDfromUIDL(uidl);
@@ -195,7 +198,7 @@ public class POP3MailBox implements NewMailListener {
// we must be connected to know the UIDL to ID mapping
checkConnection();
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error fetching: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error fetching", ioe);
return;
}
for (FetchRequest fr : requests) {
@@ -217,7 +220,7 @@ public class POP3MailBox implements NewMailListener {
try {
sendCmds(srs);
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error fetching bodies: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error fetching bodies", ioe);
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
@@ -244,7 +247,9 @@ public class POP3MailBox implements NewMailListener {
Buffer body = null;
if (id >= 1 && id <= mails) {
try {
+ try { socket.setSoTimeout(120*1000); } catch (IOException ioe) {}
body = sendCmdN("RETR " + id, buffer);
+ if (socket != null) try { socket.setSoTimeout(300*1000); } catch (IOException ioe) {}
if (body == null)
Debug.debug( Debug.DEBUG, "RETR returned null" );
} catch (OutOfMemoryError oom) {
@@ -322,7 +327,7 @@ public class POP3MailBox implements NewMailListener {
// we must be connected to know the UIDL to ID mapping
checkConnection();
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error deleting: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error deleting", ioe);
return rv;
}
for (String uidl : uidls) {
@@ -363,7 +368,7 @@ public class POP3MailBox implements NewMailListener {
// why reconnect?
//connect();
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error deleting: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error deleting", ioe);
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
@@ -467,7 +472,7 @@ public class POP3MailBox implements NewMailListener {
if (!isConnected()) {
connect();
if (!isConnected())
- throw new IOException("Cannot connect");
+ throw new IOException(_t("Cannot connect"));
}
}
@@ -536,9 +541,9 @@ public class POP3MailBox implements NewMailListener {
String uidl = line.substring(j + 1).trim();
uidlToID.put( uidl, Integer.valueOf( n ) );
} catch (NumberFormatException nfe) {
- Debug.debug(Debug.DEBUG, "UIDL error " + nfe);
+ Debug.debug(Debug.DEBUG, "UIDL error", nfe);
} catch (IndexOutOfBoundsException ioobe) {
- Debug.debug(Debug.DEBUG, "UIDL error " + ioobe);
+ Debug.debug(Debug.DEBUG, "UIDL error", ioobe);
}
}
}
@@ -567,7 +572,7 @@ public class POP3MailBox implements NewMailListener {
int value = Integer.parseInt(line.substring(j + 1).trim());
sizes.put(Integer.valueOf(key), Integer.valueOf(value));
} catch (NumberFormatException nfe) {
- Debug.debug(Debug.DEBUG, "LIST error " + nfe);
+ Debug.debug(Debug.DEBUG, "LIST error", nfe);
}
}
}
@@ -576,17 +581,6 @@ public class POP3MailBox implements NewMailListener {
}
}
- /**
- * Close (why?) and connect to server.
- * Blocking.
- */
- public void refresh() {
- synchronized( synchronizer ) {
- close(true);
- connect();
- }
- }
-
/**
* Caller must sync.
*/
@@ -599,8 +593,8 @@ public class POP3MailBox implements NewMailListener {
/**
* Connect to pop3 server if not connected.
- * Does nothing if already connected.
- * Blocking.
+ * Checks mail if already connected.
+ * Non-Blocking unless an action already in progress.
*
* This will NOT call any configured NewMailListener,
* only the one passed in. It will be called with the value
@@ -614,22 +608,23 @@ public class POP3MailBox implements NewMailListener {
* getHeader(), getBody(), and getBodies().
* Failure info is available via lastError().
*
- * @return true if connected already and nml will NOT be called back, false if nml will be called back
+ * @return true if nml will be called back, false on failure and nml will NOT be called back
* @since 0.9.13
*/
public boolean connectToServer(NewMailListener nml) {
+ Thread t;
synchronized( synchronizer ) {
if (isConnected())
- return true;
+ t = new I2PAppThread(new RecheckRunner(nml), "POP3 Checker");
+ else
+ t = new I2PAppThread(new ConnectRunner(nml), "POP3 Connector");
}
- Thread t = new I2PAppThread(new ConnectRunner(nml), "POP3 Connector");
try {
t.start();
} catch (Throwable e) {
- // not really, but we won't be calling the callback
- return true;
+ return false;
}
- return false;
+ return true;
}
@@ -651,6 +646,58 @@ public class POP3MailBox implements NewMailListener {
}
}
+ /** @since 0.9.34 */
+ private class RecheckRunner implements Runnable {
+ private final NewMailListener _nml;
+
+ public RecheckRunner(NewMailListener nml) {
+ _nml = nml;
+ }
+
+ public void run() {
+ boolean result = false;
+ try {
+ synchronized(synchronizer) {
+ result = check();
+ }
+ } finally {
+ _nml.foundNewMail(result);
+ }
+ }
+
+ private boolean check() {
+ boolean result = false;
+ try {
+ result = doCheckMail();
+ } catch (SocketTimeoutException e1) {
+ lastError = _t("Cannot connect") + ": " + _t("No response from server");
+ if (socket != null) {
+ try { socket.close(); } catch (IOException e) {}
+ socket = null;
+ connected = false;
+ }
+ Debug.debug(Debug.DEBUG, "Error rechecking", e1);
+ } catch (IOException e1) {
+ if (socket != null) {
+ try { socket.close(); } catch (IOException e) {}
+ socket = null;
+ connected = false;
+ }
+ lastError = _t("Cannot connect") + ": " + e1.getLocalizedMessage();
+ Debug.debug(Debug.DEBUG, "Error rechecking", e1);
+ // we probably weren't really connected.
+ // Let's try again from the top.
+ result = blockingConnectToServer();
+ if (socket != null) {
+ try { socket.close(); } catch (IOException e) {}
+ socket = null;
+ connected = false;
+ }
+ }
+ return result;
+ }
+ }
+
/**
* Connect to pop3 server if not connected.
* Does nothing if already connected.
@@ -717,29 +764,7 @@ public class POP3MailBox implements NewMailListener {
}
if (loginOK) {
connected = true;
- List cmds = new ArrayList(4);
- SendRecv stat = new SendRecv("STAT", Mode.A1);
- cmds.add(stat);
- SendRecv uidl = new SendRecv("UIDL", Mode.LS);
- cmds.add(uidl);
- SendRecv list = new SendRecv("LIST", Mode.LS);
- cmds.add(list);
- // check individual responses
- socket.setSoTimeout(120*1000);
- ok = sendCmds(cmds);
- if (stat.result)
- updateMailCount(stat.response);
- else
- Debug.debug(Debug.DEBUG, "STAT failed");
- if (uidl.result)
- updateUIDLs(uidl.ls);
- else
- Debug.debug(Debug.DEBUG, "UIDL failed");
- if (list.result)
- updateSizes(list.ls);
- else
- Debug.debug(Debug.DEBUG, "LIST failed");
- socket.setSoTimeout(300*1000);
+ ok = doCheckMail();
if (ok && backgroundChecker == null &&
Boolean.parseBoolean(Config.getProperty(WebMail.CONFIG_BACKGROUND_CHECK)))
backgroundChecker = new BackgroundChecker(this);
@@ -756,17 +781,22 @@ public class POP3MailBox implements NewMailListener {
}
close();
}
- }
- catch (NumberFormatException e1) {
- lastError = _t("Error opening mailbox") + ": " + e1;
- }
- catch (IOException e1) {
- lastError = _t("Error opening mailbox") + ": " + e1.getLocalizedMessage();
+ } catch (SocketTimeoutException e1) {
+ lastError = _t("Cannot connect") + ": " + _t("No response from server");
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
connected = false;
}
+ Debug.debug(Debug.DEBUG, "Error connecting", e1);
+ } catch (IOException e1) {
+ lastError = _t("Cannot connect") + ": " + e1.getLocalizedMessage();
+ if (socket != null) {
+ try { socket.close(); } catch (IOException e) {}
+ socket = null;
+ connected = false;
+ }
+ Debug.debug(Debug.DEBUG, "Error connecting", e1);
}
}
}
@@ -809,6 +839,44 @@ public class POP3MailBox implements NewMailListener {
}
return rv;
}
+
+ /**
+ * Send STAT, UIDL, LIST. Must be connected.
+ * Caller must sync.
+ * Leaves socket connected. Caller must close on IOE.
+ *
+ * @return success
+ * @throws IOException
+ * @since 0.9.34 pulled out of connect()
+ */
+ private boolean doCheckMail() throws IOException {
+ if (!isConnected())
+ throw new IOException("not connected");
+ List cmds = new ArrayList(4);
+ SendRecv stat = new SendRecv("STAT", Mode.A1);
+ cmds.add(stat);
+ SendRecv uidl = new SendRecv("UIDL", Mode.LS);
+ cmds.add(uidl);
+ SendRecv list = new SendRecv("LIST", Mode.LS);
+ cmds.add(list);
+ // check individual responses
+ socket.setSoTimeout(120*1000);
+ boolean ok = sendCmds(cmds);
+ if (stat.result)
+ updateMailCount(stat.response);
+ else
+ Debug.debug(Debug.DEBUG, "STAT failed");
+ if (uidl.result)
+ updateUIDLs(uidl.ls);
+ else
+ Debug.debug(Debug.DEBUG, "UIDL failed");
+ if (list.result)
+ updateSizes(list.ls);
+ else
+ Debug.debug(Debug.DEBUG, "LIST failed");
+ if (socket != null) try { socket.setSoTimeout(300*1000); } catch (IOException ioe) {}
+ return ok;
+ }
/**
* send command to pop3 server (and expect single line answer)
@@ -906,7 +974,7 @@ public class POP3MailBox implements NewMailListener {
getResultNa(sr.rb);
sr.result = true;
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error getting RB: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error getting RB", ioe);
result = false;
sr.result = false;
if (socket != null) {
@@ -922,7 +990,7 @@ public class POP3MailBox implements NewMailListener {
sr.ls = getResultNl();
sr.result = true;
} catch (IOException ioe) {
- Debug.debug( Debug.DEBUG, "Error getting LS: " + ioe);
+ Debug.debug(Debug.DEBUG, "Error getting LS", ioe);
result = false;
sr.result = false;
if (socket != null) {
@@ -973,7 +1041,7 @@ public class POP3MailBox implements NewMailListener {
return sendCmdNa(cmd, buffer);
} catch (IOException e) {
lastError = e.toString();
- Debug.debug( Debug.DEBUG, "sendCmdNa throws: " + e);
+ Debug.debug(Debug.DEBUG, "sendCmdNa throws", e);
if (socket != null) {
try { socket.close(); } catch (IOException ioe) {}
socket = null;
@@ -986,7 +1054,7 @@ public class POP3MailBox implements NewMailListener {
return sendCmdNa(cmd, buffer);
} catch (IOException e2) {
lastError = e2.toString();
- Debug.debug( Debug.DEBUG, "2nd sendCmdNa throws: " + e2);
+ Debug.debug(Debug.DEBUG, "2nd sendCmdNa throws", e2);
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
@@ -1104,7 +1172,7 @@ public class POP3MailBox implements NewMailListener {
if (len == 2 && buf.charAt(0) == '.' && buf.charAt(1) == '\r')
break;
if( System.currentTimeMillis() - startTime > timeOut )
- throw new IOException( "Timeout while waiting on server response." );
+ throw new IOException(_t("No response from server"));
String line;
// RFC 1939 sec. 3 de-byte-stuffing
if (buf.charAt(0) == '.')
diff --git a/history.txt b/history.txt
index 7ba99fd171..7ca37b74ca 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,8 @@
+2018-02-23 zzz
+ * Getopt: Add new translations, fix tests
+ * i2psnark: Number formatting tweaks (ticket #1913)
+ * SusiMail: Check mail fixes (ticket #2174)
+
2018-02-22 zzz
* Util: Support setSoTimeout() for InternalSockets
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index f2522cd4ed..7ca1a3ec2c 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 9;
+ public final static long BUILD = 10;
/** for example "-test" */
public final static String EXTRA = "";