SusiMail: Send deletions after connect so emails don't come back after a move (ticket #2087)

Refactor/consolidate pop3 deletion code
Fix loading mails in checker
Fix checker thread name
Return to inbox, not drafts, after sending draft
CSS for select
This commit is contained in:
zzz
2018-05-28 14:18:23 +00:00
parent 550ef2ae9c
commit d128bab2fa
8 changed files with 100 additions and 87 deletions

View File

@@ -893,7 +893,6 @@ public class WebMail extends HttpServlet
/** @param connected are we? */
public void foundNewMail(boolean connected) {
MailCache mc = null;
Folder<String> f = null;
boolean found = false;
Log log = _so.log;
if (connected) {
@@ -931,7 +930,7 @@ public class WebMail extends HttpServlet
if (log.shouldDebug()) log.debug("No new emails");
_so.newMails = 0;
_so.connectError = null;
} else if (mc != null && f != null) {
} else if (mc != null) {
String[] uidls = mc.getUIDLs();
int added = mc.getFolder().addElements(Arrays.asList(uidls));
if (added > 0)
@@ -940,7 +939,7 @@ public class WebMail extends HttpServlet
_so.connectError = null;
if (log.shouldDebug()) log.debug("Added " + added + " new emails");
} else {
if (log.shouldDebug()) log.debug("MailCache/folder vanished?");
if (log.shouldDebug()) log.debug("MailCache vanished?");
}
_mb.setNewMailListener(_so);
_so.isFetching = false;
@@ -2092,7 +2091,8 @@ public class WebMail extends HttpServlet
str = request.getParameter(NEW_FOLDER);
if (str == null)
str = request.getParameter(CURRENT_FOLDER);
if (str != null && !str.equals(DIR_FOLDER))
// always go to inbox after SEND
if (str != null && !str.equals(DIR_FOLDER) && !buttonPressed(request, SEND))
q += '&' + CURRENT_FOLDER + '=' + str;
sendRedirect(httpRequest, response, q);
return;
@@ -2790,7 +2790,7 @@ public class WebMail extends HttpServlet
Runnable es = new EmailSender(sessionObject, draft, sender,
recipients.toArray(new String[recipients.size()]),
body, attachments, boundary);
Thread t = new I2PAppThread(es, "Email fetcher");
Thread t = new I2PAppThread(es, "Email sender");
sessionObject.info += _t("Sending mail.") + '\n';
t.start();
}
@@ -3244,6 +3244,7 @@ public class WebMail extends HttpServlet
out.println(_t("Folder") + ": " + _t(name) + "&nbsp;&nbsp;&nbsp;&nbsp;"); // TODO css to center it
out.println(button(SWITCH_TO, _t("Change to Folder") + ':'));
showFolderSelect(out, folderName, false);
out.println("</td><td>");
if (pages > 1) {
if (outputHidden)
out.println("<input type=\"hidden\" name=\"" + CUR_PAGE + "\" value=\"" + page + "\">");

View File

@@ -92,10 +92,10 @@ class DelayedDeleter {
public void run() {
try {
List<String> uidls = new ArrayList<String>(toDelete);
Collection<String> deleted = mailbox.delete(uidls);
if (_log.shouldDebug()) _log.debug("Deleted " + deleted.size() + " of " + toDelete.size() + " mails");
toDelete.removeAll(deleted);
int origSize = toDelete.size();
mailbox.deletePending(false);
int delSize = origSize - toDelete.size();
if (_log.shouldDebug()) _log.debug("Deleted " + delSize + " of " + origSize + " mails");
} finally {
isDeleting = false;
if (!isDead)

View File

@@ -315,60 +315,31 @@ public class POP3MailBox implements NewMailListener {
}
/**
* Delete all at once and close. Does not reconnect.
* Do NOT call performDelete() after this.
* Returns all UIDLs successfully deleted OR were not known by the server.
* Delete all pending deletions at once.
* If previously connected, leaves connected.
* If not previously connected, closes connection when done.
*
* @param noWait fire-and-forget mode, only if connected
* @since 0.9.13
*/
Collection<String> delete(Collection<String> uidls) {
List<String> rv = new ArrayList<String>(uidls.size());
List<SendRecv> srs = new ArrayList<SendRecv>(uidls.size() + 1);
void deletePending(boolean noWait) {
Collection<String> uidls = delayedDeleter.getQueued();
if (uidls.isEmpty())
return;
synchronized( synchronizer ) {
try {
// we must be connected to know the UIDL to ID mapping
checkConnection();
} catch (IOException ioe) {
if (_log.shouldDebug()) _log.debug("Error deleting", ioe);
return rv;
}
for (String uidl : uidls) {
int id = getIDfromUIDL(uidl);
if (id < 0) {
// presumed already deleted
rv.add(uidl);
continue;
}
SendRecv sr = new SendRecv("DELE " + id, Mode.A1);
sr.savedObject = uidl;
srs.add(sr);
}
if (srs.isEmpty())
return rv;
// TODO don't quit now, just set timer to quit later
SendRecv quit = new SendRecv("QUIT", Mode.A1);
srs.add(quit);
try {
sendCmds(srs);
// do NOT call close() here, we included QUIT above
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
connected = false;
}
clear();
// result of QUIT
boolean success = srs.get(srs.size() - 1).result;
if (success) {
for (int i = 0; i < srs.size() - 1; i++) {
SendRecv sr = srs.get(i);
// ignore sr.result, if it failed it's because
// it's already deleted
rv.add((String) sr.savedObject);
if (isConnected()) {
doDelete(noWait);
} else {
// calls connect() which calls doDelete()
checkConnection();
sendCmd1a("QUIT");
if (socket != null) {
try { socket.close(); } catch (IOException e) {}
socket = null;
connected = false;
}
}
// why reconnect?
//connect();
} catch (IOException ioe) {
if (_log.shouldDebug()) _log.debug("Error deleting", ioe);
if (socket != null) {
@@ -376,10 +347,8 @@ public class POP3MailBox implements NewMailListener {
socket = null;
connected = false;
}
// todo maybe
}
}
return rv;
}
/**
@@ -841,7 +810,7 @@ public class POP3MailBox implements NewMailListener {
}
/**
* Send STAT, UIDL, LIST. Must be connected.
* Send STAT, UIDL, LIST, and DELE for all pending. Must be connected.
* Caller must sync.
* Leaves socket connected. Caller must close on IOE.
*
@@ -874,9 +843,64 @@ public class POP3MailBox implements NewMailListener {
updateSizes(list.ls);
else
if (_log.shouldDebug()) _log.debug("LIST failed");
// delete all pending deletions
doDelete(false);
if (socket != null) try { socket.setSoTimeout(300*1000); } catch (IOException ioe) {}
return ok;
}
/**
* Send DELE for all pending deletions. Must be connected.
* Caller must sync.
* Leaves socket connected. Caller must close on IOE.
*
* @param noWait fire-and-forget mode
* @throws IOException
* @since 0.9.35 pulled out of delete()
*/
private void doDelete(boolean noWait) throws IOException {
// delete all pending deletions
Collection<String> uidls = delayedDeleter.getQueued();
if (uidls.isEmpty())
return;
List<SendRecv> cmds = new ArrayList<SendRecv>(uidls.size());
for (String uid : uidls) {
int id = getIDfromUIDL(uid);
if (id < 0) {
// presumed already deleted
delayedDeleter.removeQueued(uid);
continue;
}
if (noWait) {
sendCmd1aNoWait("DELE " + id);
delayedDeleter.removeQueued(uid);
uidlToID.remove(uid);
sizes.remove(Integer.valueOf(id));
} else {
SendRecv sr = new SendRecv("DELE " + id, Mode.A1);
sr.savedObject = uid;
cmds.add(sr);
}
}
if (!cmds.isEmpty()) {
// ignore rv
sendCmds(cmds);
// use isConnected() as a proxy for success
if (isConnected()) {
for (SendRecv sr : cmds) {
// ignore sr.result, if it failed it's because
// it's already deleted
String uid = (String) sr.savedObject;
delayedDeleter.removeQueued(uid);
Integer id = uidlToID.remove(uid);
if (id != null)
sizes.remove(id);
}
}
}
}
/**
* send command to pop3 server (and expect single line answer)
@@ -1291,33 +1315,11 @@ public class POP3MailBox implements NewMailListener {
idleCloser.cancel();
if (socket != null && socket.isConnected()) {
try {
Collection<String> toDelete = delayedDeleter.getQueued();
Map<String, Integer> sendDelete = new HashMap<String, Integer>(toDelete.size());
for (String uidl : toDelete) {
int id = getIDfromUIDL(uidl);
if (id >= 0) {
sendDelete.put(uidl, Integer.valueOf(id));
}
}
deletePending(!shouldWait);
if (shouldWait) {
if (!sendDelete.isEmpty()) {
// Verify deleted, remove from the delete queue
// this does the quit and close
Collection<String> deleted = delete(sendDelete.keySet());
for (String uidl : deleted) {
delayedDeleter.removeQueued(uidl);
}
} else {
sendCmd1a("QUIT");
}
sendCmd1a("QUIT");
if (_log.shouldDebug()) _log.debug("close() with wait complete");
} else {
if (!sendDelete.isEmpty()) {
// spray and pray the deletions, don't remove from delete queue
for (Integer id : sendDelete.values()) {
sendCmd1aNoWait("DELE " + id);
}
}
sendCmd1aNoWait("QUIT");
}
} catch (IOException e) {

View File

@@ -1,3 +1,9 @@
2018-05-28 zzz
* SusiMail: (ticket #2087)
- Send deletions after connect so emails don't come back after a move
- Fix fetches in check mail
- CSS fixes
2018-05-26 zzz
* /confignet: Reorganize (ticket #2217)
* /configsidebar: Tag sections for translation; sort unselected sections by translated name
@@ -7,6 +13,7 @@
- Hide column 1 icon for peers (ticket #1996)
* i2ptunnel: Retry accept after server socket closed (ticket #2003)
* Jetty: Skip files with [] in default servlet listing
* ministreaming: Add classpath to jar (ticket #2228)
* Router: Fix wrapper.config path in OOM message when installed as
Debian package, but not running as a service (ticket #2223)
* Summary Bar: Change header from "I2P Updates" to "Update Status" (ticket #2137)

View File

@@ -509,6 +509,7 @@ button:focus, input[type="submit"]:focus, input[type="reset"]:focus {
filter: drop-shadow(0 0 1px #89f);
}
select,
button, input[type="submit"], input[type="reset"] {
padding: 5px;
border-radius: 2px;
@@ -630,7 +631,7 @@ input.offline:hover, input.offline:focus {
background: url(/themes/susimail/images/offline_hover.png) no-repeat 7px center, linear-gradient(to bottom, #ddd 0%, #fff 100%);
}
input.list, input.moveto, input.switchto {
input.list, input.moveto, #pagenav input.switchto {
background: #eee url(/themes/susimail/images/folder.png) no-repeat 7px center;
background: url(/themes/susimail/images/folder.png) no-repeat 7px center, linear-gradient(to bottom, #fff 0%, #ddd 100%);
padding: 5px 8px 5px 24px;

View File

@@ -514,6 +514,7 @@ input[type="text"], input[type="password"] {
font-size: 9pt;
}
select,
input[type="submit"], input[type="reset"] {
border: 1px solid #999daf;
box-shadow: inset 0 0 0 1px #fff;
@@ -607,7 +608,7 @@ input.offline:hover {
background: url(/themes/susimail/images/offline_hover.png) no-repeat 6px center, linear-gradient(to bottom, #eee, #fff);
}
input.list, input.moveto, input.switchto {
input.list, input.moveto, #pagenav input.switchto {
background: #eee url(/themes/susimail/images/folder.png) no-repeat 6px center;
background: url(/themes/susimail/images/folder.png) no-repeat 6px center, linear-gradient(to bottom, #fff, #efefff);
padding: 5px 7px 5px 24px;

View File

@@ -595,6 +595,7 @@ input[type=submit]::-moz-focus-inner, input.cancel::-moz-focus-inner {
box-shadow: none;
}
select,
input[type=submit], input.cancel {
color: #4e47bf;
background: #000;
@@ -1071,7 +1072,7 @@ input.offline:hover, input.offline:focus {
background: #000 url(/themes/susimail/images/offline_hover.png) no-repeat 6px center !important;
}
input.list, input.moveto, input.switchto {
input.list, input.moveto, #pagenav input.switchto {
background: #000 url(/themes/susimail/images/folder.png) no-repeat 6px center !important;
background: url(/themes/susimail/images/folder.png) no-repeat 6px center, linear-gradient(to bottom, #1f1e32, #090812 50%, #000 50%) !important;
padding: 5px 7px 5px 23px !important;

View File

@@ -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 = 14;
public final static long BUILD = 15;
/** for example "-test" */
public final static String EXTRA = "";