* SusiMail:

- Fix fetching of new mail
   - More Folder cleanup
   - Prep for not leaving on server
   - Prep for background checker
This commit is contained in:
zzz
2014-04-23 22:46:57 +00:00
parent b365817c99
commit 1e4b43314c
7 changed files with 113 additions and 98 deletions

View File

@ -59,7 +59,7 @@ public class Folder<O extends Object> {
}
private int pages, pageSize, currentPage;
private O[] unsortedElements, elements;
private O[] elements;
private final Hashtable<String, Comparator<O>> sorter;
private SortOrder sortingDirection;
Comparator<O> currentSorter;
@ -74,6 +74,7 @@ public class Folder<O extends Object> {
/**
* Returns the current page.
* Starts at 1, even if empty.
*
* @return Returns the current page.
*/
@ -83,6 +84,7 @@ public class Folder<O extends Object> {
/**
* Sets the current page to the given parameter.
* Starts at 1.
*
* @param currentPage The current page to set.
*/
@ -102,6 +104,7 @@ public class Folder<O extends Object> {
/**
* Returns the number of pages in the folder.
* Minimum of 1 even if empty.
* @return Returns the number of pages.
*/
public synchronized int getPages() {
@ -129,20 +132,6 @@ public class Folder<O extends Object> {
update();
}
/**
* Creates a copy of an array by copying its elements.
*
* @param source Array to copy.
* @return Copy of source.
*/
@SuppressWarnings("unchecked")
private O[] copyArray( O[] source )
{
Object[] destination = new Object[source.length];
for( int i = 0; i < source.length; i++ )
destination[i] = source[i];
return (O[])destination;
}
/**
* Recalculates variables.
*/
@ -166,30 +155,25 @@ public class Folder<O extends Object> {
*/
private void sort()
{
if( currentSorter != null ) {
elements = copyArray( unsortedElements );
if( currentSorter != null )
Arrays.sort( elements, currentSorter );
}
else {
elements = unsortedElements;
}
}
/**
* Set the array of objects the folder should manage.
* Does NOT copy the array.
*
* @param elements Array of Os.
*/
public synchronized void setElements( O[] elements )
{
if (elements.length > 0) {
this.unsortedElements = elements;
this.elements = elements;
if( currentSorter != null )
sort();
else
this.elements = elements;
} else
} else {
this.elements = null;
}
update();
}
@ -198,7 +182,7 @@ public class Folder<O extends Object> {
*
* @param element to remove
*/
public synchronized void removeElement(O element) {
public void removeElement(O element) {
removeElements(Collections.singleton(element));
}
@ -211,19 +195,49 @@ public class Folder<O extends Object> {
public synchronized void removeElements(Collection<O> elems) {
if (elements != null) {
List<O> list = new ArrayList<O>(Arrays.asList(elements));
boolean shouldUpdate = false;
for (O e : elems) {
list.remove(e);
if (list.remove(e))
shouldUpdate = true;
}
if (shouldUpdate) {
elements = (O[]) list.toArray(new Object[list.size()]);
update(); // will still be sorted
}
elements = (O[]) list.toArray(new Object[list.size()]);
}
if (unsortedElements != null) {
List<O> list = new ArrayList<O>(Arrays.asList(unsortedElements));
}
/**
* Add an element only if it does not already exist
*
* @param element to add
*/
public void addElement(O element) {
addElements(Collections.singleton(element));
}
/**
* Add elements only if it they do not already exist
*
* @param elems to adde
*/
@SuppressWarnings("unchecked")
public synchronized void addElements(Collection<O> elems) {
if (elements != null) {
List<O> list = new ArrayList<O>(Arrays.asList(elements));
boolean shouldUpdate = false;
for (O e : elems) {
list.remove(e);
if (!list.contains(e)) {
list.add(e);
shouldUpdate = true;
}
}
if (shouldUpdate) {
elements = (O[]) list.toArray(new Object[list.size()]);
sort();
update();
}
unsortedElements = (O[]) list.toArray(new Object[list.size()]);
}
update();
}
/**

View File

@ -24,6 +24,7 @@
package i2p.susi.webmail;
import i2p.susi.debug.Debug;
import i2p.susi.util.Config;
import i2p.susi.util.ReadBuffer;
import i2p.susi.webmail.pop3.POP3MailBox;
import i2p.susi.webmail.pop3.POP3MailBox.FetchRequest;
@ -136,8 +137,10 @@ class MailCache {
}
}
if (disk != null) {
if (disk.saveMail(mail) && mail.hasBody()) {
// TODO delete on server
if (disk.saveMail(mail) && mail.hasBody() &&
false && // TO ENABLE
!Boolean.parseBoolean(Config.getProperty(WebMail.CONFIG_LEAVE_ON_SERVER))) {
mailbox.queueForDeletion(mail.uidl);
}
}
return mail;
@ -146,18 +149,23 @@ class MailCache {
/**
* Fetch any needed data from pop3 server.
* Mail objects are inserted into the requests.
* After this, call getUIDLs() to get all known mail UIDLs.
* MUST already be connected, otherwise returns false.
*
* @return true if any were fetched
* @since 0.9.13
*/
public void getMail(Collection<MailRequest> requests) {
public boolean getMail(boolean hOnly) {
Collection<String> popKnown = mailbox.getUIDLs();
if (popKnown == null)
return false;
List<POP3Request> fetches = new ArrayList<POP3Request>();
// Fill in the answers from the cache and make a list of
// requests.to send off
for (MailRequest mr : requests) {
for (String uidl : popKnown) {
Mail mail = null, newMail = null;
String uidl = mr.getUIDL();
boolean headerOnly = mr.getHeaderOnly();
boolean headerOnly = hOnly;
/*
* synchronize update to hashtable
@ -175,7 +183,6 @@ class MailCache {
}
if (mail.markForDeletion)
continue;
mr.setMail(mail);
int sz = mail.getSize();
if (sz > 0 && sz <= FETCH_ALL_SIZE)
headerOnly = false;
@ -187,7 +194,7 @@ class MailCache {
continue; // found on disk, woo
}
}
POP3Request pr = new POP3Request(mr, mail, true);
POP3Request pr = new POP3Request(mail, true);
fetches.add(pr);
}
} else {
@ -198,12 +205,13 @@ class MailCache {
continue; // found on disk, woo
}
}
POP3Request pr = new POP3Request(mr, mail, false);
POP3Request pr = new POP3Request(mail, false);
fetches.add(pr);
}
}
}
boolean rv = false;
if (!fetches.isEmpty()) {
// Send off the fetches
// gaah compiler
@ -220,14 +228,18 @@ class MailCache {
} else {
mail.setBody(rb);
}
rv = true;
if (disk != null) {
if (disk.saveMail(mail) && mail.hasBody()) {
// TODO delete on server
if (disk.saveMail(mail) && mail.hasBody() &&
false && // TO ENABLE
!Boolean.parseBoolean(Config.getProperty(WebMail.CONFIG_LEAVE_ON_SERVER))) {
mailbox.queueForDeletion(mail.uidl);
}
}
}
}
}
return rv;
}
/**
@ -264,32 +276,21 @@ class MailCache {
mailbox.queueForDeletion(toDelete);
}
/**
* Incoming to us
*/
public interface MailRequest {
public String getUIDL();
public boolean getHeaderOnly();
public void setMail(Mail mail);
}
/**
* Outgoing to POP3
*/
private static class POP3Request implements FetchRequest {
public final MailRequest request;
public final Mail mail;
private final boolean headerOnly;
public ReadBuffer buf;
public POP3Request(MailRequest req, Mail m, boolean hOnly) {
request = req;
public POP3Request(Mail m, boolean hOnly) {
mail = m;
headerOnly = hOnly;
}
public String getUIDL() {
return request.getUIDL();
return mail.uidl;
}
public boolean getHeaderOnly() {

View File

@ -174,7 +174,7 @@ public class WebMail extends HttpServlet
private static final String CONFIG_COMPOSER_ROWS = "composer.rows";
private static final String CONFIG_BCC_TO_SELF = "composer.bcc.to.self";
private static final String CONFIG_LEAVE_ON_SERVER = "pop3.leave.on.server";
static final String CONFIG_LEAVE_ON_SERVER = "pop3.leave.on.server";
private static final String CONFIG_DEBUG = "debug";
private static final String RC_PROP_THEME = "routerconsole.theme";
@ -676,18 +676,14 @@ public class WebMail extends HttpServlet
MailCache mc = new MailCache(mailbox, host, pop3PortNo, user, pass);
sessionObject.mailCache = mc;
sessionObject.folder = new Folder<String>();
if (!offline) {
// prime the cache, request all headers at once
// otherwise they are pulled one at a time by sortBy() below
mc.getMail(true);
}
// get through cache so we have the disk-only ones too
String[] uidls = mc.getUIDLs();
sessionObject.folder.setElements(uidls);
if (uidls.length > 0 && !offline) {
// prime the cache, request all headers at once
// otherwise they are pulled one at a time by sortBy() below
List<MailCache.MailRequest> reqs = new ArrayList<MailCache.MailRequest>(uidls.length);
for (int i = 0; i < uidls.length; i++) {
reqs.add(new CacheRequest(uidls[i]));
}
mc.getMail(reqs);
}
//sessionObject.folder.addSorter( SORT_ID, new IDSorter( sessionObject.mailCache ) );
sessionObject.folder.addSorter( SORT_SENDER, new SenderSorter( sessionObject.mailCache ) );
@ -714,30 +710,6 @@ public class WebMail extends HttpServlet
}
}
/**
* Outgoing to MailCache
* @since 0.9.13
*/
private static class CacheRequest implements MailCache.MailRequest {
private final String uidl;
public CacheRequest(String uidl) {
this.uidl = uidl;
}
public String getUIDL() {
return uidl;
}
public boolean getHeaderOnly() {
return true;
}
public void setMail(Mail mail) {
// do nothing, this just pumps up the cache
}
}
/**
*
* @param sessionObject
@ -1036,6 +1008,7 @@ public class WebMail extends HttpServlet
}
if( buttonPressed( request, REFRESH ) ) {
sessionObject.mailbox.refresh();
sessionObject.mailCache.getMail(true);
// get through cache so we have the disk-only ones too
String[] uidls = sessionObject.mailCache.getUIDLs();
if (uidls != null)
@ -1461,8 +1434,10 @@ public class WebMail extends HttpServlet
if( sessionObject.state != STATE_AUTH ) {
// get through cache so we have the disk-only ones too
String[] uidls = sessionObject.mailCache.getUIDLs();
if (uidls != null)
if (uidls != null) {
// TODO why every time?
sessionObject.folder.setElements(uidls);
}
}
if( ! sendAttachment( sessionObject, response ) ) {
@ -1852,7 +1827,7 @@ public class WebMail extends HttpServlet
out.println(
"<tr><td colspan=\"2\">&nbsp;</td></tr>\n" +
"<tr><td></td><td align=\"left\">" + button( LOGIN, _("Login") ) + spacer +
button(OFFLINE, _("View Mail Offline") ) + spacer +
button(OFFLINE, _("Read Mail Offline") ) + spacer +
" <input class=\"cancel\" type=\"reset\" value=\"" + _("Reset") + "\"></td></tr>\n" +
"<tr><td colspan=\"2\">&nbsp;</td></tr>\n" +
"<tr><td></td><td align=\"left\"><a href=\"http://hq.postman.i2p/?page_id=14\">" + _("Learn about I2P mail") + "</a></td></tr>\n" +

View File

@ -71,8 +71,10 @@ class DelayedDeleter {
isDeleting = true;
t.start();
} else {
Debug.debug(Debug.DEBUG, "Nothing to delete");
Debug.debug(Debug.DEBUG, "Not deleting, only idle " + idle);
}
} else {
Debug.debug(Debug.DEBUG, "Nothing to delete");
}
schedule(CHECK_TIME);
}

View File

@ -66,6 +66,7 @@ public class POP3MailBox {
private Socket socket;
private final AtomicLong lastActive;
private final AtomicLong lastChecked;
private final Object synchronizer;
private final DelayedDeleter delayedDeleter;
@ -92,6 +93,7 @@ public class POP3MailBox {
// this appears in the UI so translate
lastLine = _("No response from server");
lastActive = new AtomicLong(System.currentTimeMillis());
lastChecked = new AtomicLong();
delayedDeleter = new DelayedDeleter(this);
}
@ -270,10 +272,20 @@ public class POP3MailBox {
*/
public void queueForDeletion(Collection<String> uidls) {
for (String uidl : uidls) {
delayedDeleter.queueDelete(uidl);
queueForDeletion(uidl);
}
}
/**
* Queue for later deletion. Non-blocking.
*
* @since 0.9.13
*/
public void queueForDeletion(String uidl) {
Debug.debug(Debug.DEBUG, "Queueing for deletion: " + uidl);
delayedDeleter.queueDelete(uidl);
}
/**
* Delete all at once and close. Does not reconnect.
* Do NOT call performDelete() after this.
@ -445,6 +457,15 @@ public class POP3MailBox {
return lastActive.get();
}
/**
* Timestamp. When we last successfully got the UIDL list.
*
* @since 0.9.13
*/
long getLastChecked() {
return lastChecked.get();
}
/**
*
* @param response line starting with +OK
@ -489,6 +510,7 @@ public class POP3MailBox {
}
}
}
lastChecked.set(System.currentTimeMillis());
} else {
Debug.debug(Debug.DEBUG, "Error getting UIDL list from server.");
}
@ -1085,12 +1107,12 @@ public class POP3MailBox {
*
* @return A new array of the available UIDLs. No particular order.
*/
public String[] getUIDLs()
public Collection<String> getUIDLs()
{
if (!isConnected())
return null;
synchronized( synchronizer ) {
return uidlToID.keySet().toArray(new String[uidlToID.size()]);
return new ArrayList(uidlToID.keySet());
}
}

View File

@ -2,6 +2,7 @@
* SusiMail:
- Queue deletions for a later thread
- Synch all folder access
- Fix fetching of new mail
2014-04-22 zzz
* SusiMail:

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