* SusiMail:

- Add locking for disk cache
   - Remove cancel button from login page
   - New configuration page
   - Move set page form to configuration page
   - Theme and folder js enhancements
   - Wrench icon from Silk, same license as the others
This commit is contained in:
zzz
2014-04-27 14:57:28 +00:00
parent f5661da595
commit 91d7a0ab98
7 changed files with 293 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

View File

@@ -29,10 +29,12 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.OrderedProperties;
/** /**
* Warning - static - not for use by multiple applications or prefixes * Warning - static - not for use by multiple applications or prefixes
@@ -48,7 +50,7 @@ public class Config {
* *
* @param name * @param name
*/ */
public static String getProperty( String name ) public synchronized static String getProperty( String name )
{ {
if( configPrefix != null ) if( configPrefix != null )
name = configPrefix + name; name = configPrefix + name;
@@ -79,7 +81,7 @@ public class Config {
* Don't bother showing a reload config button if this returns false. * Don't bother showing a reload config button if this returns false.
* @since 0.9.13 * @since 0.9.13
*/ */
public static boolean hasConfigFile() { public synchronized static boolean hasConfigFile() {
File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config"); File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
return cfg.exists(); return cfg.exists();
} }
@@ -88,7 +90,7 @@ public class Config {
* *
* *
*/ */
public static void reloadConfiguration() public synchronized static void reloadConfiguration()
{ {
// DEBUG level logging won't work here since we haven't loaded the config yet... // DEBUG level logging won't work here since we haven't loaded the config yet...
properties = new Properties(); properties = new Properties();
@@ -104,7 +106,7 @@ public class Config {
try { try {
File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config"); File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
if (cfg.exists()) { if (cfg.exists()) {
config = new Properties(); config = new OrderedProperties();
DataHelper.loadProps(config, cfg); DataHelper.loadProps(config, cfg);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -113,21 +115,74 @@ public class Config {
} }
/** /**
* * Returns the properties, sorted, WITHOUT the prefix
* @param name *
* @param defaultValue * @since 0.9.13
*/ */
public static String getProperty( String name, String defaultValue ) public synchronized static Properties getProperties() {
{ Properties rv = new OrderedProperties();
String result = getProperty( name ); if (properties != null) {
return result != null ? result : defaultValue; if (configPrefix == null) {
rv.putAll(properties);
} else {
for (Map.Entry<Object, Object> e : properties.entrySet()) {
String k = (String) e.getKey();
if (k.startsWith(configPrefix))
rv.put(k.substring(configPrefix.length()), e.getValue());
}
}
}
if (config != null) {
if (configPrefix == null) {
rv.putAll(config);
} else {
for (Map.Entry<Object, Object> e : config.entrySet()) {
String k = (String) e.getKey();
if (k.startsWith(configPrefix))
rv.put(k.substring(configPrefix.length()), e.getValue());
}
}
}
return rv;
} }
/**
* Saves the properties. A property not in newProps will be removed but
* will not override the default in the resource.
*
* @param newProps non-null WITHOUT the prefix
* @since 0.9.13
*/
public synchronized static void saveConfiguration(Properties newProps) throws IOException {
Properties toSave = new OrderedProperties();
for (Map.Entry<Object, Object> e : newProps.entrySet()) {
Object k = e.getKey();
if (configPrefix != null)
k = configPrefix + k;
toSave.put(k, e.getValue());
}
config = toSave;
File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
DataHelper.storeProps(toSave, cfg);
}
/** /**
* *
* @param name * @param name
* @param defaultValue * @param defaultValue
*/ */
public static int getProperty( String name, int defaultValue ) public synchronized static String getProperty( String name, String defaultValue )
{
String result = getProperty( name );
return result != null ? result : defaultValue;
}
/**
*
* @param name
* @param defaultValue
*/
public synchronized static int getProperty( String name, int defaultValue )
{ {
int result = defaultValue; int result = defaultValue;
@@ -148,7 +203,7 @@ public class Config {
* Static! Not for use by multiple applications! * Static! Not for use by multiple applications!
* @param prefix * @param prefix
*/ */
public static void setPrefix( String prefix ) public synchronized static void setPrefix( String prefix )
{ {
configPrefix = prefix.endsWith( "." ) ? prefix : prefix + "."; configPrefix = prefix.endsWith( "." ) ? prefix : prefix + ".";
} }

View File

@@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -46,6 +47,15 @@ import net.i2p.util.SecureFileOutputStream;
*/ */
class PersistentMailCache { class PersistentMailCache {
/**
* One lock for each user in the whole JVM, to protect against multiple sessions.
* One big lock for the whole cache dir, not one for each file or subdir.
* Never expired.
* Sure, if we did a maildir format we wouldn't need this.
*/
private static final ConcurrentHashMap<String, Object> _locks = new ConcurrentHashMap<String, Object>();
private final Object _lock;
private final File _cacheDir; private final File _cacheDir;
private static final String DIR_SUSI = "susimail"; private static final String DIR_SUSI = "susimail";
@@ -63,8 +73,10 @@ class PersistentMailCache {
* @param pass ignored * @param pass ignored
*/ */
public PersistentMailCache(String host, int port, String user, String pass) throws IOException { public PersistentMailCache(String host, int port, String user, String pass) throws IOException {
_cacheDir = makeCacheDirs(host, port, user, pass); _lock = getLock(host, port, user, pass);
// TODO static locking synchronized(_lock) {
_cacheDir = makeCacheDirs(host, port, user, pass);
}
} }
/** /**
@@ -73,6 +85,12 @@ class PersistentMailCache {
* @return a new collection * @return a new collection
*/ */
public Collection<Mail> getMails() { public Collection<Mail> getMails() {
synchronized(_lock) {
return locked_getMails();
}
}
private Collection<Mail> locked_getMails() {
List<Mail> rv = new ArrayList<Mail>(); List<Mail> rv = new ArrayList<Mail>();
for (int j = 0; j < B64.length(); j++) { for (int j = 0; j < B64.length(); j++) {
File subdir = new File(_cacheDir, DIR_PREFIX + B64.charAt(j)); File subdir = new File(_cacheDir, DIR_PREFIX + B64.charAt(j));
@@ -97,6 +115,12 @@ class PersistentMailCache {
* @return success * @return success
*/ */
public boolean getMail(Mail mail, boolean headerOnly) { public boolean getMail(Mail mail, boolean headerOnly) {
synchronized(_lock) {
return locked_getMail(mail, headerOnly);
}
}
private boolean locked_getMail(Mail mail, boolean headerOnly) {
File f = getFullFile(mail.uidl); File f = getFullFile(mail.uidl);
if (f.exists()) { if (f.exists()) {
ReadBuffer rb = read(f); ReadBuffer rb = read(f);
@@ -122,6 +146,12 @@ class PersistentMailCache {
* @return success * @return success
*/ */
public boolean saveMail(Mail mail) { public boolean saveMail(Mail mail) {
synchronized(_lock) {
return locked_saveMail(mail);
}
}
private boolean locked_saveMail(Mail mail) {
ReadBuffer rb = mail.getBody(); ReadBuffer rb = mail.getBody();
if (rb != null) { if (rb != null) {
File f = getFullFile(mail.uidl); File f = getFullFile(mail.uidl);
@@ -156,8 +186,16 @@ class PersistentMailCache {
* Delete data from disk. * Delete data from disk.
*/ */
public void deleteMail(String uidl) { public void deleteMail(String uidl) {
getFullFile(uidl).delete(); synchronized(_lock) {
getHeaderFile(uidl).delete(); getFullFile(uidl).delete();
getHeaderFile(uidl).delete();
}
}
private static Object getLock(String host, int port, String user, String pass) {
Object lock = new Object();
Object old = _locks.putIfAbsent(user + host + port, lock);
return (old != null) ? old : lock;
} }
/** /**

View File

@@ -53,6 +53,8 @@ import java.util.Enumeration;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@@ -91,7 +93,6 @@ public class WebMail extends HttpServlet
private static final int STATE_LIST = 2; private static final int STATE_LIST = 2;
private static final int STATE_SHOW = 3; private static final int STATE_SHOW = 3;
private static final int STATE_NEW = 4; private static final int STATE_NEW = 4;
// TODO
private static final int STATE_CONFIG = 5; private static final int STATE_CONFIG = 5;
// TODO generate from servlet name to allow for renaming or multiple instances // TODO generate from servlet name to allow for renaming or multiple instances
@@ -113,7 +114,9 @@ public class WebMail extends HttpServlet
*/ */
private static final String LOGOUT = "logout"; private static final String LOGOUT = "logout";
private static final String RELOAD = "reload"; private static final String RELOAD = "reload";
private static final String SAVE = "save";
private static final String REFRESH = "refresh"; private static final String REFRESH = "refresh";
private static final String CONFIGURE = "configure";
private static final String NEW = "new"; private static final String NEW = "new";
private static final String REPLY = "reply"; private static final String REPLY = "reply";
private static final String REPLYALL = "replyall"; private static final String REPLYALL = "replyall";
@@ -158,6 +161,8 @@ public class WebMail extends HttpServlet
private static final String SORT_DATE = "sort_date"; private static final String SORT_DATE = "sort_date";
private static final String SORT_SIZE = "sort_size"; private static final String SORT_SIZE = "sort_size";
private static final String CONFIG_TEXT = "config_text";
private static final boolean SHOW_HTML = true; private static final boolean SHOW_HTML = true;
private static final boolean TEXT_ONLY = false; private static final boolean TEXT_ONLY = false;
@@ -827,9 +832,9 @@ public class WebMail extends HttpServlet
* @param sessionObject * @param sessionObject
* @param request * @param request
*/ */
private static void processLogout( SessionObject sessionObject, RequestWrapper request ) private static void processLogout( SessionObject sessionObject, RequestWrapper request, boolean isPOST )
{ {
if( buttonPressed( request, LOGOUT ) ) { if( buttonPressed( request, LOGOUT ) && isPOST) {
Debug.debug(Debug.DEBUG, "LOGOUT, REMOVING SESSION"); Debug.debug(Debug.DEBUG, "LOGOUT, REMOVING SESSION");
HttpSession session = request.getSession(); HttpSession session = request.getSession();
session.removeAttribute( "sessionObject" ); session.removeAttribute( "sessionObject" );
@@ -842,12 +847,12 @@ public class WebMail extends HttpServlet
} }
sessionObject.info += _("User logged out.") + "<br>"; sessionObject.info += _("User logged out.") + "<br>";
sessionObject.state = STATE_AUTH; sessionObject.state = STATE_AUTH;
} } else if( sessionObject.mailbox == null ) {
else if( sessionObject.mailbox == null ) {
sessionObject.error += _("Internal error, lost connection.") + "<br>"; sessionObject.error += _("Internal error, lost connection.") + "<br>";
sessionObject.state = STATE_AUTH; sessionObject.state = STATE_AUTH;
} }
} }
/** /**
* Process all buttons, which possibly change internal state. * Process all buttons, which possibly change internal state.
* Also processes ?show=x for a GET * Also processes ?show=x for a GET
@@ -864,8 +869,8 @@ public class WebMail extends HttpServlet
if( sessionObject.state == STATE_AUTH && isPOST ) if( sessionObject.state == STATE_AUTH && isPOST )
processLogin( sessionObject, request ); processLogin( sessionObject, request );
if( sessionObject.state != STATE_AUTH && isPOST ) if( sessionObject.state != STATE_AUTH && sessionObject.state != STATE_CONFIG )
processLogout( sessionObject, request ); processLogout( sessionObject, request, isPOST );
/* /*
* compose dialog * compose dialog
@@ -907,9 +912,9 @@ public class WebMail extends HttpServlet
} }
} }
/* /*
* message dialog * message dialog or config
*/ */
if( sessionObject.state == STATE_SHOW && isPOST ) { if((sessionObject.state == STATE_SHOW || sessionObject.state == STATE_CONFIG) && isPOST ) {
if( buttonPressed( request, LIST ) ) { if( buttonPressed( request, LIST ) ) {
sessionObject.state = STATE_LIST; sessionObject.state = STATE_LIST;
} else if (buttonPressed( request, CANCEL ) || } else if (buttonPressed( request, CANCEL ) ||
@@ -930,6 +935,18 @@ public class WebMail extends HttpServlet
sessionObject.state = STATE_LIST; sessionObject.state = STATE_LIST;
} }
} }
/*
* config
*/
if (sessionObject.state == STATE_CONFIG && isPOST) {
if (buttonPressed(request, OFFLINE)) { // lost
sessionObject.state = STATE_AUTH;
} else if (buttonPressed(request, LOGIN)) { // lost
sessionObject.state = STATE_AUTH;
}
}
/* /*
* buttons on both folder and message dialog * buttons on both folder and message dialog
*/ */
@@ -1329,7 +1346,7 @@ public class WebMail extends HttpServlet
/* /*
* process paging buttons * process paging buttons
*/ */
if (buttonPressed(request, PAGESIZE) && !buttonPressed(request, RELOAD)) { if (buttonPressed(request, SETPAGESIZE)) {
try { try {
int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE))); int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
int oldPageSize = sessionObject.folder.getPageSize(); int oldPageSize = sessionObject.folder.getPageSize();
@@ -1419,6 +1436,59 @@ public class WebMail extends HttpServlet
} }
} }
} }
/*
* process config buttons, both entering and exiting
*/
private static void processConfigButtons(SessionObject sessionObject, RequestWrapper request) {
if (buttonPressed(request, SAVE)) {
try {
String raw = request.getParameter(CONFIG_TEXT);
if (raw == null)
return;
Properties props = new Properties();
DataHelper.loadProps(props, new ByteArrayInputStream(DataHelper.getUTF8(raw)));
Config.saveConfiguration(props);
String ps = props.getProperty(Folder.PAGESIZE);
if (sessionObject.folder != null && ps != null) {
try {
int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
int oldPageSize = sessionObject.folder.getPageSize();
if( pageSize != oldPageSize )
sessionObject.folder.setPageSize( pageSize );
} catch( NumberFormatException nfe ) {}
}
sessionObject.state = sessionObject.folder != null ? STATE_LIST : STATE_AUTH;
sessionObject.info = _("Configuration saved");
} catch (IOException ioe) {
sessionObject.error = ioe.toString();
}
} else if (buttonPressed(request, SETPAGESIZE)) {
try {
int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
Properties props = Config.getProperties();
props.setProperty(Folder.PAGESIZE, String.valueOf(pageSize));
Config.saveConfiguration(props);
if (sessionObject.folder != null) {
int oldPageSize = sessionObject.folder.getPageSize();
if( pageSize != oldPageSize )
sessionObject.folder.setPageSize( pageSize );
sessionObject.state = STATE_LIST;
} else {
sessionObject.state = STATE_AUTH;
}
} catch (IOException ioe) {
sessionObject.error = ioe.toString();
} catch( NumberFormatException nfe ) {
sessionObject.error += _("Invalid pagesize number, resetting to default value.") + "<br>";
}
} else if (buttonPressed(request, CANCEL)) {
sessionObject.state = (sessionObject.folder != null) ? STATE_LIST : STATE_AUTH;
} else if (buttonPressed(request, CONFIGURE)) {
sessionObject.state = STATE_CONFIG;
}
}
/** /**
* @param httpSession * @param httpSession
* @return non-null * @return non-null
@@ -1437,6 +1507,7 @@ public class WebMail extends HttpServlet
} }
return sessionObject; return sessionObject;
} }
/** /**
* Copied from net.i2p.router.web.CSSHelper * Copied from net.i2p.router.web.CSSHelper
* @since 0.9.7 * @since 0.9.7
@@ -1528,6 +1599,8 @@ public class WebMail extends HttpServlet
int oldState = sessionObject.state; int oldState = sessionObject.state;
processStateChangeButtons( sessionObject, request, isPOST ); processStateChangeButtons( sessionObject, request, isPOST );
if (isPOST)
processConfigButtons( sessionObject, request );
int newState = sessionObject.state; int newState = sessionObject.state;
if (oldState != newState) if (oldState != newState)
Debug.debug(Debug.DEBUG, "STATE CHANGE from " + oldState + " to " + newState); Debug.debug(Debug.DEBUG, "STATE CHANGE from " + oldState + " to " + newState);
@@ -1582,7 +1655,7 @@ public class WebMail extends HttpServlet
/* /*
* update folder content * update folder content
*/ */
if( sessionObject.state != STATE_AUTH ) { if( sessionObject.state == STATE_LIST ) {
// get through cache so we have the disk-only ones too // get through cache so we have the disk-only ones too
String[] uidls = sessionObject.mailCache.getUIDLs(); String[] uidls = sessionObject.mailCache.getUIDLs();
if (uidls != null) { if (uidls != null) {
@@ -1611,6 +1684,8 @@ public class WebMail extends HttpServlet
subtitle = _("Show Message"); subtitle = _("Show Message");
} else if( sessionObject.state == STATE_NEW ) { } else if( sessionObject.state == STATE_NEW ) {
subtitle = _("New Message"); subtitle = _("New Message");
} else if( sessionObject.state == STATE_CONFIG ) {
subtitle = _("Configuration");
} }
response.setContentType( "text/html" ); response.setContentType( "text/html" );
@@ -1648,7 +1723,7 @@ public class WebMail extends HttpServlet
out.println( "<p class=\"error\">" + sessionObject.error + "</p>" ); out.println( "<p class=\"error\">" + sessionObject.error + "</p>" );
} }
if( sessionObject.info != null && sessionObject.info.length() > 0 ) { if( sessionObject.info != null && sessionObject.info.length() > 0 ) {
out.println( "<p class=\"info\">" + sessionObject.info + "</p>" ); out.println( "<p class=\"info\"><b>" + sessionObject.info + "</b></p>" );
} }
/* /*
* now write body * now write body
@@ -1665,6 +1740,9 @@ public class WebMail extends HttpServlet
else if( sessionObject.state == STATE_NEW ) else if( sessionObject.state == STATE_NEW )
showCompose( out, sessionObject, request ); showCompose( out, sessionObject, request );
else if( sessionObject.state == STATE_CONFIG )
showConfig(out, sessionObject);
//out.println( "</form><div id=\"footer\"><hr><p class=\"footer\">susimail v0." + version +" " + ( RELEASE ? "release" : "development" ) + " &copy; 2004-2005 <a href=\"mailto:susi23@mail.i2p\">susi</a></div></div></body>\n</html>"); //out.println( "</form><div id=\"footer\"><hr><p class=\"footer\">susimail v0." + version +" " + ( RELEASE ? "release" : "development" ) + " &copy; 2004-2005 <a href=\"mailto:susi23@mail.i2p\">susi</a></div></div></body>\n</html>");
out.println( "</form><div id=\"footer\"><hr><p class=\"footer\">susimail &copy; 2004-2005 susi</div></div></body>\n</html>"); out.println( "</form><div id=\"footer\"><hr><p class=\"footer\">susimail &copy; 2004-2005 susi</div></div></body>\n</html>");
out.flush(); out.flush();
@@ -1972,6 +2050,7 @@ public class WebMail extends HttpServlet
} }
out.println( "</table>" ); out.println( "</table>" );
} }
/** /**
* *
* @param out * @param out
@@ -1999,13 +2078,18 @@ public class WebMail extends HttpServlet
out.println( out.println(
"<tr><td colspan=\"2\">&nbsp;</td></tr>\n" + "<tr><td colspan=\"2\">&nbsp;</td></tr>\n" +
"<tr><td></td><td align=\"left\">" + button( LOGIN, _("Login") ) + spacer + "<tr><td></td><td align=\"left\">" + button( LOGIN, _("Login") ) + spacer +
button(OFFLINE, _("Read Mail Offline") ) + spacer + button(OFFLINE, _("Read Mail Offline") ) +
" <input class=\"cancel\" type=\"reset\" value=\"" + _("Reset") + "\"></td></tr>\n" + //spacer +
//" <input class=\"cancel\" type=\"reset\" value=\"" + _("Reset") + "\">" +
spacer +
button(CONFIGURE, _("Settings")) +
"</td></tr>\n" +
"<tr><td colspan=\"2\">&nbsp;</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" + "<tr><td></td><td align=\"left\"><a href=\"http://hq.postman.i2p/?page_id=14\">" + _("Learn about I2P mail") + "</a></td></tr>\n" +
"<tr><td></td><td align=\"left\"><a href=\"http://hq.postman.i2p/?page_id=16\">" + _("Create Account") + "</a></td></tr>\n" + "<tr><td></td><td align=\"left\"><a href=\"http://hq.postman.i2p/?page_id=16\">" + _("Create Account") + "</a></td></tr>\n" +
"</table>"); "</table>");
} }
/** /**
* *
* @param out * @param out
@@ -2014,16 +2098,16 @@ public class WebMail extends HttpServlet
*/ */
private static void showFolder( PrintWriter out, SessionObject sessionObject, RequestWrapper request ) private static void showFolder( PrintWriter out, SessionObject sessionObject, RequestWrapper request )
{ {
out.println( button( NEW, _("New") ) + spacer + out.println( button( NEW, _("New") ) + spacer);
// In theory, these are valid and will apply to the first checked message, // In theory, these are valid and will apply to the first checked message,
// but that's not obvious and did it work? // but that's not obvious and did it work?
//button( REPLY, _("Reply") ) + //button( REPLY, _("Reply") ) +
//button( REPLYALL, _("Reply All") ) + //button( REPLYALL, _("Reply All") ) +
//button( FORWARD, _("Forward") ) + spacer + //button( FORWARD, _("Forward") ) + spacer +
//button( DELETE, _("Delete") ) + spacer + //button( DELETE, _("Delete") ) + spacer +
button( REFRESH, _("Check Mail") ) + spacer); out.println(button( REFRESH, _("Check Mail") ) + spacer);
if (Config.hasConfigFile()) //if (Config.hasConfigFile())
out.println(button( RELOAD, _("Reload Config") ) + spacer); // out.println(button( RELOAD, _("Reload Config") ) + spacer);
out.println(button( LOGOUT, _("Logout") )); out.println(button( LOGOUT, _("Logout") ));
if (sessionObject.folder.getPages() > 1) if (sessionObject.folder.getPages() > 1)
@@ -2057,6 +2141,7 @@ public class WebMail extends HttpServlet
else else
type = "linkold"; type = "linkold";
String link = "<a href=\"" + myself + "?" + SHOW + "=" + i + "\" class=\"" + type + "\">"; String link = "<a href=\"" + myself + "?" + SHOW + "=" + i + "\" class=\"" + type + "\">";
String jslink = " onclick=\"document.location='" + myself + '?' + SHOW + '=' + i + "';\" ";
boolean idChecked = false; boolean idChecked = false;
String checkId = sessionObject.pageChanged ? null : request.getParameter( "check" + i ); String checkId = sessionObject.pageChanged ? null : request.getParameter( "check" + i );
@@ -2075,15 +2160,16 @@ public class WebMail extends HttpServlet
// ", markAll=" + sessionObject.markAll + // ", markAll=" + sessionObject.markAll +
// ", invert=" + sessionObject.invert + // ", invert=" + sessionObject.invert +
// ", clear=" + sessionObject.clear ); // ", clear=" + sessionObject.clear );
out.println( "<tr class=\"list" + bg + "\"><td><input type=\"checkbox\" class=\"optbox\" name=\"check" + i + "\" value=\"1\"" + out.println( "<tr class=\"list" + bg + "\">" +
( idChecked ? "checked" : "" ) + ">" + "</td><td>" + "<td><input type=\"checkbox\" class=\"optbox\" name=\"check" + i + "\" value=\"1\"" +
(mail.isNew() ? "<img src=\"/susimail/icons/flag_green.png\" alt=\"\" title=\"" + _("Message is new") + "\">" : "&nbsp;") + "</td><td>" + ( idChecked ? "checked" : "" ) + ">" + "</td><td " + jslink + ">" +
link + mail.shortSender + "</a></td><td>" + (mail.isNew() ? "<img src=\"/susimail/icons/flag_green.png\" alt=\"\" title=\"" + _("Message is new") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
(mail.hasAttachment() ? "<img src=\"/susimail/icons/attach.png\" alt=\"\" title=\"" + _("Message has an attachment") + "\">" : "&nbsp;") + "</td><td>" + link + mail.shortSender + "</a></td><td " + jslink + ">" +
link + mail.shortSubject + "</a></td><td>" + (mail.hasAttachment() ? "<img src=\"/susimail/icons/attach.png\" alt=\"\" title=\"" + _("Message has an attachment") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
(mail.isSpam() ? "<img src=\"/susimail/icons/flag_red.png\" alt=\"\" title=\"" + _("Message is spam") + "\">" : "&nbsp;") + "</td><td>" + link + mail.shortSubject + "</a></td><td " + jslink + ">" +
(mail.isSpam() ? "<img src=\"/susimail/icons/flag_red.png\" alt=\"\" title=\"" + _("Message is spam") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
// don't let date get split across lines // don't let date get split across lines
mail.localFormattedDate.replace(" ", "&nbsp;") + "</td><td>&nbsp;</td><td align=\"right\">" + mail.localFormattedDate.replace(" ", "&nbsp;") + "</td><td " + jslink + ">&nbsp;</td><td align=\"right\" " + jslink + ">" +
((mail.getSize() > 0) ? (DataHelper.formatSize2(mail.getSize()) + 'B') : "???") + "</td></tr>" ); ((mail.getSize() > 0) ? (DataHelper.formatSize2(mail.getSize()) + 'B') : "???") + "</td></tr>" );
bg = 1 - bg; bg = 1 - bg;
i++; i++;
@@ -2108,18 +2194,21 @@ public class WebMail extends HttpServlet
// TODO js // TODO js
out.println(button( DELETE, _("Delete Selected") ) + "<br>"); out.println(button( DELETE, _("Delete Selected") ) + "<br>");
out.print( out.print(
button( CLEAR, _("Clear All") ) + button( MARKALL, _("Mark All") ) +
"&nbsp;" + "&nbsp;" +
button( MARKALL, _("Mark All") )); button( CLEAR, _("Clear All") ));
//"<br>" + //"<br>" +
//button( INVERT, _("Invert Selection") ) + //button( INVERT, _("Invert Selection") ) +
//"<br>"); //"<br>");
} }
out.print("</td>\n<td colspan=\"4\" align=\"right\">"); out.print("</td>\n<td colspan=\"4\" align=\"right\">");
out.print( // moved to config page
_("Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE + "\" size=\"4\" value=\"" + sessionObject.folder.getPageSize() + "\">" + //out.print(
"&nbsp;" + // _("Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE + "\" size=\"4\" value=\"" + sessionObject.folder.getPageSize() + "\">" +
button( SETPAGESIZE, _("Set") ) ); // "&nbsp;" +
// button( SETPAGESIZE, _("Set") ) );
out.print("<br>");
out.print(button(CONFIGURE, _("Settings")));
out.println("</td>"); out.println("</td>");
} }
out.println( "</table>"); out.println( "</table>");
@@ -2198,6 +2287,37 @@ public class WebMail extends HttpServlet
out.println( "<tr><td colspan=\"2\" align=\"center\"><hr></td></tr>\n</table>" ); out.println( "<tr><td colspan=\"2\" align=\"center\"><hr></td></tr>\n</table>" );
} }
/**
* Simple configure page
*
* @since 0.9.13
*/
private static void showConfig(PrintWriter out, SessionObject sessionObject) {
int sz;
if (sessionObject.folder != null)
sz = sessionObject.folder.getPageSize();
else
sz = Config.getProperty(Folder.PAGESIZE, Folder.DEFAULT_PAGESIZE);
out.println(
_("Folder Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE +
"\" size=\"4\" value=\"" + sz + "\">" +
"&nbsp;" +
button( SETPAGESIZE, _("Set") ) );
out.println("<p>");
out.print(_("Advanced Configuration"));
out.print(":</p><textarea cols=\"80\" rows=\"20\" spellcheck=\"false\" name=\"" + CONFIG_TEXT + "\">");
Properties config = Config.getProperties();
for (Map.Entry<Object, Object> e : config.entrySet()) {
out.print(e.getKey());
out.print('=');
out.println(e.getValue());
}
out.println("</textarea>");
out.println("</br>");
out.println(button(SAVE, _("Save Configuration")));
out.println(button(CANCEL, _("Cancel")));
}
/** translate */ /** translate */
private static String _(String s) { private static String _(String s) {
return Messages.getString(s); return Messages.getString(s);

View File

@@ -4,8 +4,6 @@ susimail.ports.fixed=true
susimail.ports.pop3=7660 susimail.ports.pop3=7660
susimail.ports.smtp=7659 susimail.ports.smtp=7659
susimail.fast.start=true
susimail.sender.fixed=true susimail.sender.fixed=true
susimail.sender.domain=mail.i2p susimail.sender.domain=mail.i2p

View File

@@ -233,11 +233,16 @@ input.prevpage, input.prev {
min-height: 22px; min-height: 22px;
} }
input.send, input.setpagesize { input.send, input.setpagesize, input.save {
background: #000 url('/themes/console/images/accept.png') no-repeat 2px center; background: #000 url('/themes/console/images/accept.png') no-repeat 2px center;
min-height: 22px; min-height: 22px;
} }
input.configure {
background: #000 url('/susimail/icons/wrench.png') no-repeat 2px center;
min-height: 22px;
}
input[type=file], input.new_upload { input[type=file], input.new_upload {
background: #000 url('/themes/console/images/add.png') no-repeat 2px center; background: #000 url('/themes/console/images/add.png') no-repeat 2px center;
min-height: 22px; min-height: 22px;

View File

@@ -114,11 +114,27 @@ td {
} }
tr.list0 { tr.list0 {
background-color:#e0e0e0; background-color:#ececec;
} }
tr.list1 { tr.list1 {
background-color:#ffffff; background-color:#f4f4f4;
}
tr.list0:hover {
background-color:#e0e0f4;
}
tr.list1:hover {
background-color:#e0e0f4;
}
tr.list0 a:link {
text-decoration: none;
}
tr.list1 a:link {
text-decoration: none;
} }
.iframed tr.list1 { .iframed tr.list1 {
@@ -242,12 +258,18 @@ input.prevpage, input.prev {
min-height: 22px; min-height: 22px;
} }
input.send, input.setpagesize { input.send, input.setpagesize, input.save {
background: #ddf url('/themes/console/images/accept.png') no-repeat 4px center; background: #ddf url('/themes/console/images/accept.png') no-repeat 4px center;
padding: 2px 3px 2px 24px; padding: 2px 3px 2px 24px;
min-height: 22px; min-height: 22px;
} }
input.configure {
background: #ddf url('/susimail/icons/wrench.png') no-repeat 4px center;
padding: 2px 3px 2px 24px;
min-height: 22px;
}
input[type=file], input.new_upload { input[type=file], input.new_upload {
background: #ddf url('/themes/console/images/add.png') no-repeat 4px center; background: #ddf url('/themes/console/images/add.png') no-repeat 4px center;
padding: 2px 3px 2px 24px; padding: 2px 3px 2px 24px;