Changeset 91d7a0a


Ignore:
Timestamp:
Apr 27, 2014 2:57:28 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
611ff635
Parents:
f5661da
Message:
  • 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
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • apps/susimail/src/src/i2p/susi/util/Config.java

    rf5661da r91d7a0a  
    3030import java.io.InputStream;
    3131import java.io.IOException;
     32import java.util.Map;
    3233import java.util.Properties;
    3334
    3435import net.i2p.I2PAppContext;
    3536import net.i2p.data.DataHelper;
     37import net.i2p.util.OrderedProperties;
    3638
    3739/**
     
    4951         * @param name
    5052         */
    51         public static String getProperty( String name )
     53        public synchronized static String getProperty( String name )
    5254        {
    5355                if( configPrefix != null )
     
    8082         *  @since 0.9.13
    8183         */
    82         public static boolean hasConfigFile() {
     84        public synchronized static boolean hasConfigFile() {
    8385                File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
    8486                return cfg.exists();
     
    8991         *
    9092         */
    91         public static void reloadConfiguration()
     93        public synchronized static void reloadConfiguration()
    9294        {
    9395                // DEBUG level logging won't work here since we haven't loaded the config yet...
     
    105107                        File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
    106108                        if (cfg.exists()) {
    107                                 config = new Properties();
     109                                config = new OrderedProperties();
    108110                                DataHelper.loadProps(config, cfg);
    109111                        }
     
    114116
    115117        /**
     118         * Returns the properties, sorted, WITHOUT the prefix
     119         *
     120         * @since 0.9.13
     121         */
     122        public synchronized static Properties getProperties() {
     123                Properties rv = new OrderedProperties();
     124                if (properties != null) {
     125                        if (configPrefix == null) {
     126                                rv.putAll(properties);
     127                        } else {
     128                                for (Map.Entry<Object, Object> e : properties.entrySet()) {
     129                                        String k = (String) e.getKey();
     130                                        if (k.startsWith(configPrefix))
     131                                                rv.put(k.substring(configPrefix.length()), e.getValue());
     132                                }
     133                        }
     134                }
     135                if (config != null) {
     136                        if (configPrefix == null) {
     137                                rv.putAll(config);
     138                        } else {
     139                                for (Map.Entry<Object, Object> e : config.entrySet()) {
     140                                        String k = (String) e.getKey();
     141                                        if (k.startsWith(configPrefix))
     142                                                rv.put(k.substring(configPrefix.length()), e.getValue());
     143                                }
     144                        }
     145                }
     146                return rv;
     147        }
     148
     149        /**
     150         * Saves the properties. A property not in newProps will be removed but
     151         * will not override the default in the resource.
     152         *
     153         * @param newProps non-null WITHOUT the prefix
     154         * @since 0.9.13
     155         */
     156        public synchronized static void saveConfiguration(Properties newProps) throws IOException {
     157                Properties toSave = new OrderedProperties();
     158                for (Map.Entry<Object, Object> e : newProps.entrySet()) {
     159                        Object k = e.getKey();
     160                        if (configPrefix != null)
     161                                k = configPrefix + k;
     162                        toSave.put(k, e.getValue());
     163                }
     164                config = toSave;
     165                File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
     166                DataHelper.storeProps(toSave, cfg);
     167        }
     168
     169        /**
    116170         *
    117171         * @param name
    118172         * @param defaultValue
    119173         */
    120         public static String getProperty( String name, String defaultValue )
     174        public synchronized static String getProperty( String name, String defaultValue )
    121175        {
    122176                String result = getProperty( name );
    123177                return result != null ? result : defaultValue;
    124178        }
     179
    125180        /**
    126181         *
     
    128183         * @param defaultValue
    129184         */
    130         public static int getProperty( String name, int defaultValue )
     185        public synchronized static int getProperty( String name, int defaultValue )
    131186        {
    132187                int result = defaultValue;
     
    149204         * @param prefix
    150205         */
    151         public static void setPrefix( String prefix )
     206        public synchronized static void setPrefix( String prefix )
    152207        {
    153208                configPrefix = prefix.endsWith( "." ) ? prefix : prefix + ".";
  • apps/susimail/src/src/i2p/susi/webmail/PersistentMailCache.java

    rf5661da r91d7a0a  
    1717import java.util.Hashtable;
    1818import java.util.List;
     19import java.util.concurrent.ConcurrentHashMap;
    1920import java.util.zip.GZIPInputStream;
    2021import java.util.zip.GZIPOutputStream;
     
    4748class PersistentMailCache {
    4849       
     50        /**
     51         *  One lock for each user in the whole JVM, to protect against multiple sessions.
     52         *  One big lock for the whole cache dir, not one for each file or subdir.
     53         *  Never expired.
     54         *  Sure, if we did a maildir format we wouldn't need this.
     55         */
     56        private static final ConcurrentHashMap<String, Object> _locks = new ConcurrentHashMap<String, Object>();
     57
     58        private final Object _lock;
    4959        private final File _cacheDir;
    5060
     
    6474         */
    6575        public PersistentMailCache(String host, int port, String user, String pass) throws IOException {
    66                 _cacheDir = makeCacheDirs(host, port, user, pass);
    67                 // TODO static locking
     76                _lock = getLock(host, port, user, pass);
     77                synchronized(_lock) {
     78                        _cacheDir = makeCacheDirs(host, port, user, pass);
     79                }
    6880        }
    6981
     
    7486         */
    7587        public Collection<Mail> getMails() {
     88                synchronized(_lock) {
     89                        return locked_getMails();
     90                }
     91        }
     92
     93        private Collection<Mail> locked_getMails() {
    7694                List<Mail> rv = new ArrayList<Mail>();
    7795                for (int j = 0; j < B64.length(); j++) {
     
    98116         */
    99117        public boolean getMail(Mail mail, boolean headerOnly) {
     118                synchronized(_lock) {
     119                        return locked_getMail(mail, headerOnly);
     120                }
     121        }
     122
     123        private boolean locked_getMail(Mail mail, boolean headerOnly) {
    100124                File f = getFullFile(mail.uidl);
    101125                if (f.exists()) {
     
    123147         */
    124148        public boolean saveMail(Mail mail) {
     149                synchronized(_lock) {
     150                        return locked_saveMail(mail);
     151                }
     152        }
     153
     154        private boolean locked_saveMail(Mail mail) {
    125155                ReadBuffer rb = mail.getBody();
    126156                if (rb != null) {
     
    157187         */
    158188        public void deleteMail(String uidl) {
    159                 getFullFile(uidl).delete();
    160                 getHeaderFile(uidl).delete();
     189                synchronized(_lock) {
     190                        getFullFile(uidl).delete();
     191                        getHeaderFile(uidl).delete();
     192                }
     193        }
     194
     195        private static Object getLock(String host, int port, String user, String pass) {
     196                Object lock = new Object();
     197                Object old = _locks.putIfAbsent(user + host + port, lock);
     198                return (old != null) ? old : lock;
    161199        }
    162200
  • apps/susimail/src/src/i2p/susi/webmail/WebMail.java

    rf5661da r91d7a0a  
    5454import java.util.List;
    5555import java.util.Locale;
     56import java.util.Map;
     57import java.util.Properties;
    5658import java.util.zip.ZipEntry;
    5759import java.util.zip.ZipOutputStream;
     
    9294        private static final int STATE_SHOW = 3;
    9395        private static final int STATE_NEW = 4;
    94         // TODO
    9596        private static final int STATE_CONFIG = 5;
    9697       
     
    114115        private static final String LOGOUT = "logout";
    115116        private static final String RELOAD = "reload";
     117        private static final String SAVE = "save";
    116118        private static final String REFRESH = "refresh";
     119        private static final String CONFIGURE = "configure";
    117120        private static final String NEW = "new";
    118121        private static final String REPLY = "reply";
     
    158161        private static final String SORT_DATE = "sort_date";
    159162        private static final String SORT_SIZE = "sort_size";
     163
     164        private static final String CONFIG_TEXT = "config_text";
    160165
    161166        private static final boolean SHOW_HTML = true;
     
    828833         * @param request
    829834         */
    830         private static void processLogout( SessionObject sessionObject, RequestWrapper request )
    831         {
    832                 if( buttonPressed( request, LOGOUT ) ) {
     835        private static void processLogout( SessionObject sessionObject, RequestWrapper request, boolean isPOST )
     836        {
     837                if( buttonPressed( request, LOGOUT ) && isPOST) {
    833838                        Debug.debug(Debug.DEBUG, "LOGOUT, REMOVING SESSION");
    834839                        HttpSession session = request.getSession();
     
    843848                        sessionObject.info += _("User logged out.") + "<br>";
    844849                        sessionObject.state = STATE_AUTH;
    845                 }
    846                 else if( sessionObject.mailbox == null ) {
     850                } else if( sessionObject.mailbox == null ) {
    847851                        sessionObject.error += _("Internal error, lost connection.") + "<br>";
    848852                        sessionObject.state = STATE_AUTH;
    849853                }
    850854        }
     855
    851856        /**
    852857         * Process all buttons, which possibly change internal state.
     
    865870                        processLogin( sessionObject, request );
    866871
    867                 if( sessionObject.state != STATE_AUTH && isPOST )
    868                         processLogout( sessionObject, request );
     872                if( sessionObject.state != STATE_AUTH && sessionObject.state != STATE_CONFIG )
     873                        processLogout( sessionObject, request, isPOST );
    869874
    870875                /*
     
    908913                }
    909914                /*
    910                  * message dialog
     915                 * message dialog or config
    911916                 */
    912                 if( sessionObject.state == STATE_SHOW && isPOST ) {
     917                if((sessionObject.state == STATE_SHOW || sessionObject.state == STATE_CONFIG) && isPOST ) {
    913918                        if( buttonPressed( request, LIST ) ) {
    914919                                sessionObject.state = STATE_LIST;
     
    931936                        }
    932937                }
     938
     939                /*
     940                 * config
     941                 */
     942                if (sessionObject.state == STATE_CONFIG && isPOST) {
     943                        if (buttonPressed(request, OFFLINE)) {       // lost
     944                                sessionObject.state = STATE_AUTH;
     945                        } else if (buttonPressed(request, LOGIN)) {  // lost
     946                                sessionObject.state = STATE_AUTH;
     947                        }
     948                }
     949
    933950                /*
    934951                 * buttons on both folder and message dialog
     
    13301347                 * process paging buttons
    13311348                 */
    1332                 if (buttonPressed(request, PAGESIZE) && !buttonPressed(request, RELOAD)) {
     1349                if (buttonPressed(request, SETPAGESIZE)) {
    13331350                        try {
    13341351                                int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
     
    14201437                }
    14211438        }
     1439
     1440        /*
     1441         * process config buttons, both entering and exiting
     1442         */
     1443        private static void processConfigButtons(SessionObject sessionObject, RequestWrapper request) {
     1444                if (buttonPressed(request, SAVE)) {
     1445                        try {
     1446                                String raw = request.getParameter(CONFIG_TEXT);
     1447                                if (raw == null)
     1448                                        return;
     1449                                Properties props = new Properties();
     1450                                DataHelper.loadProps(props, new ByteArrayInputStream(DataHelper.getUTF8(raw)));
     1451                                Config.saveConfiguration(props);
     1452                                String ps = props.getProperty(Folder.PAGESIZE);
     1453                                if (sessionObject.folder != null && ps != null) {
     1454                                        try {
     1455                                                int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
     1456                                                int oldPageSize = sessionObject.folder.getPageSize();
     1457                                                if( pageSize != oldPageSize )
     1458                                                        sessionObject.folder.setPageSize( pageSize );
     1459                                        } catch( NumberFormatException nfe ) {}
     1460                                }
     1461                                sessionObject.state = sessionObject.folder != null ? STATE_LIST : STATE_AUTH;
     1462                                sessionObject.info = _("Configuration saved");
     1463                        } catch (IOException ioe) {
     1464                                sessionObject.error = ioe.toString();
     1465                        }
     1466                } else if (buttonPressed(request, SETPAGESIZE)) {
     1467                        try {
     1468                                int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE)));
     1469                                Properties props = Config.getProperties();
     1470                                props.setProperty(Folder.PAGESIZE, String.valueOf(pageSize));
     1471                                Config.saveConfiguration(props);
     1472                                if (sessionObject.folder != null) {
     1473                                        int oldPageSize = sessionObject.folder.getPageSize();
     1474                                        if( pageSize != oldPageSize )
     1475                                                sessionObject.folder.setPageSize( pageSize );
     1476                                        sessionObject.state = STATE_LIST;
     1477                                } else {
     1478                                        sessionObject.state = STATE_AUTH;
     1479                                }
     1480                        } catch (IOException ioe) {
     1481                                sessionObject.error = ioe.toString();
     1482                        } catch( NumberFormatException nfe ) {
     1483                                sessionObject.error += _("Invalid pagesize number, resetting to default value.") + "<br>";
     1484                        }
     1485                } else if (buttonPressed(request, CANCEL)) {
     1486                        sessionObject.state = (sessionObject.folder != null) ? STATE_LIST : STATE_AUTH;
     1487                } else if (buttonPressed(request, CONFIGURE)) {
     1488                        sessionObject.state = STATE_CONFIG;
     1489                }
     1490        }
     1491
    14221492        /**
    14231493         * @param httpSession
     
    14381508                return sessionObject;
    14391509        }
     1510
    14401511    /**
    14411512     * Copied from net.i2p.router.web.CSSHelper
     
    15291600                        int oldState = sessionObject.state;
    15301601                        processStateChangeButtons( sessionObject, request, isPOST );
     1602                        if (isPOST)
     1603                                processConfigButtons( sessionObject, request );
    15311604                        int newState = sessionObject.state;
    15321605                        if (oldState != newState)
     
    15831656                         * update folder content
    15841657                         */
    1585                         if( sessionObject.state != STATE_AUTH ) {
     1658                        if( sessionObject.state == STATE_LIST ) {
    15861659                                // get through cache so we have the disk-only ones too
    15871660                                String[] uidls = sessionObject.mailCache.getUIDLs();
     
    16121685                                } else if( sessionObject.state == STATE_NEW ) {
    16131686                                        subtitle = _("New Message");
     1687                                } else if( sessionObject.state == STATE_CONFIG ) {
     1688                                        subtitle = _("Configuration");
    16141689                                }
    16151690
     
    16491724                                }
    16501725                                if( sessionObject.info != null && sessionObject.info.length() > 0 ) {
    1651                                         out.println( "<p class=\"info\">" + sessionObject.info + "</p>" );
     1726                                        out.println( "<p class=\"info\"><b>" + sessionObject.info + "</b></p>" );
    16521727                                }
    16531728                                /*
     
    16651740                                else if( sessionObject.state == STATE_NEW )
    16661741                                        showCompose( out, sessionObject, request );
     1742                               
     1743                                else if( sessionObject.state == STATE_CONFIG )
     1744                                        showConfig(out, sessionObject);
    16671745                               
    16681746                                //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>");                               
     
    19732051                out.println( "</table>" );
    19742052        }
     2053
    19752054        /**
    19762055         *
     
    20002079                        "<tr><td colspan=\"2\">&nbsp;</td></tr>\n" +
    20012080                        "<tr><td></td><td align=\"left\">" + button( LOGIN, _("Login") ) + spacer +
    2002                           button(OFFLINE, _("Read Mail Offline") ) + spacer +
    2003                          " <input class=\"cancel\" type=\"reset\" value=\"" + _("Reset") + "\"></td></tr>\n" +
     2081                         button(OFFLINE, _("Read Mail Offline") ) +
     2082                         //spacer +
     2083                         //" <input class=\"cancel\" type=\"reset\" value=\"" + _("Reset") + "\">" +
     2084                         spacer +
     2085                         button(CONFIGURE, _("Settings")) +
     2086                        "</td></tr>\n" +
    20042087                        "<tr><td colspan=\"2\">&nbsp;</td></tr>\n" +
    20052088                        "<tr><td></td><td align=\"left\"><a href=\"http://hq.postman.i2p/?page_id=14\">" + _("Learn about I2P mail") + "</a></td></tr>\n" +
     
    20072090                        "</table>");
    20082091        }
     2092
    20092093        /**
    20102094         *
     
    20152099        private static void showFolder( PrintWriter out, SessionObject sessionObject, RequestWrapper request )
    20162100        {
    2017                 out.println( button( NEW, _("New") ) + spacer +
     2101                out.println( button( NEW, _("New") ) + spacer);
    20182102                        // In theory, these are valid and will apply to the first checked message,
    20192103                        // but that's not obvious and did it work?
     
    20222106                        //button( FORWARD, _("Forward") ) + spacer +
    20232107                        //button( DELETE, _("Delete") ) + spacer +
    2024                         button( REFRESH, _("Check Mail") ) + spacer);
    2025                 if (Config.hasConfigFile())
    2026                         out.println(button( RELOAD, _("Reload Config") ) + spacer);
     2108                out.println(button( REFRESH, _("Check Mail") ) + spacer);
     2109                //if (Config.hasConfigFile())
     2110                //      out.println(button( RELOAD, _("Reload Config") ) + spacer);
    20272111                out.println(button( LOGOUT, _("Logout") ));
    20282112
     
    20582142                                type = "linkold";
    20592143                        String link = "<a href=\"" + myself + "?" + SHOW + "=" + i + "\" class=\"" + type + "\">";
     2144                        String jslink = " onclick=\"document.location='" + myself + '?' + SHOW + '=' + i + "';\" ";
    20602145                       
    20612146                        boolean idChecked = false;
     
    20762161                        //              ", invert=" + sessionObject.invert +
    20772162                        //              ", clear=" + sessionObject.clear );
    2078                         out.println( "<tr class=\"list" + bg + "\"><td><input type=\"checkbox\" class=\"optbox\" name=\"check" + i + "\" value=\"1\"" +
    2079                                         ( idChecked ? "checked" : "" ) + ">" + "</td><td>" +
    2080                                         (mail.isNew() ? "<img src=\"/susimail/icons/flag_green.png\" alt=\"\" title=\"" + _("Message is new") + "\">" : "&nbsp;") + "</td><td>" +
    2081                                         link + mail.shortSender + "</a></td><td>" +
    2082                                         (mail.hasAttachment() ? "<img src=\"/susimail/icons/attach.png\" alt=\"\" title=\"" + _("Message has an attachment") + "\">" : "&nbsp;") + "</td><td>" +
    2083                                         link + mail.shortSubject + "</a></td><td>" +
    2084                                         (mail.isSpam() ? "<img src=\"/susimail/icons/flag_red.png\" alt=\"\" title=\"" + _("Message is spam") + "\">" : "&nbsp;") + "</td><td>" +
     2163                        out.println( "<tr class=\"list" + bg + "\">" +
     2164                                        "<td><input type=\"checkbox\" class=\"optbox\" name=\"check" + i + "\" value=\"1\"" +
     2165                                        ( idChecked ? "checked" : "" ) + ">" + "</td><td " + jslink + ">" +
     2166                                        (mail.isNew() ? "<img src=\"/susimail/icons/flag_green.png\" alt=\"\" title=\"" + _("Message is new") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
     2167                                        link + mail.shortSender + "</a></td><td " + jslink + ">" +
     2168                                        (mail.hasAttachment() ? "<img src=\"/susimail/icons/attach.png\" alt=\"\" title=\"" + _("Message has an attachment") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
     2169                                        link + mail.shortSubject + "</a></td><td " + jslink + ">" +
     2170                                        (mail.isSpam() ? "<img src=\"/susimail/icons/flag_red.png\" alt=\"\" title=\"" + _("Message is spam") + "\">" : "&nbsp;") + "</td><td " + jslink + ">" +
    20852171                                        // don't let date get split across lines
    2086                                         mail.localFormattedDate.replace(" ", "&nbsp;") + "</td><td>&nbsp;</td><td align=\"right\">" +
     2172                                        mail.localFormattedDate.replace(" ", "&nbsp;") + "</td><td " + jslink + ">&nbsp;</td><td align=\"right\" " + jslink + ">" +
    20872173                                        ((mail.getSize() > 0) ? (DataHelper.formatSize2(mail.getSize()) + 'B') : "???") + "</td></tr>" );
    20882174                        bg = 1 - bg;
     
    21092195                                out.println(button( DELETE, _("Delete Selected") ) + "<br>");
    21102196                                out.print(
    2111                                         button( CLEAR, _("Clear All") ) +
     2197                                        button( MARKALL, _("Mark All") ) +
    21122198                                        "&nbsp;" +
    2113                                         button( MARKALL, _("Mark All") ));
     2199                                        button( CLEAR, _("Clear All") ));
    21142200                                        //"<br>" +
    21152201                                        //button( INVERT, _("Invert Selection") ) +
     
    21172203                        }
    21182204                        out.print("</td>\n<td colspan=\"4\" align=\"right\">");
    2119                         out.print(
    2120                                 _("Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE + "\" size=\"4\" value=\"" +  sessionObject.folder.getPageSize() + "\">" +
    2121                                 "&nbsp;" +
    2122                                 button( SETPAGESIZE, _("Set") ) );
     2205                        // moved to config page
     2206                        //out.print(
     2207                        //      _("Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE + "\" size=\"4\" value=\"" +  sessionObject.folder.getPageSize() + "\">" +
     2208                        //      "&nbsp;" +
     2209                        //      button( SETPAGESIZE, _("Set") ) );
     2210                        out.print("<br>");
     2211                        out.print(button(CONFIGURE, _("Settings")));
    21232212                        out.println("</td>");
    21242213                }
     
    21992288        }
    22002289
     2290        /**
     2291         *  Simple configure page
     2292         *
     2293         *  @since 0.9.13
     2294         */
     2295        private static void showConfig(PrintWriter out, SessionObject sessionObject) {
     2296                int sz;
     2297                if (sessionObject.folder != null)
     2298                        sz = sessionObject.folder.getPageSize();
     2299                else
     2300                        sz = Config.getProperty(Folder.PAGESIZE, Folder.DEFAULT_PAGESIZE);
     2301                out.println(
     2302                        _("Folder Page Size") + ":&nbsp;<input type=\"text\" style=\"text-align: right;\" name=\"" + PAGESIZE +
     2303                        "\" size=\"4\" value=\"" +  sz + "\">" +
     2304                        "&nbsp;" +
     2305                        button( SETPAGESIZE, _("Set") ) );
     2306                out.println("<p>");
     2307                out.print(_("Advanced Configuration"));
     2308                out.print(":</p><textarea cols=\"80\" rows=\"20\" spellcheck=\"false\" name=\"" + CONFIG_TEXT + "\">");
     2309                Properties config = Config.getProperties();
     2310                for (Map.Entry<Object, Object> e : config.entrySet()) {
     2311                        out.print(e.getKey());
     2312                        out.print('=');
     2313                        out.println(e.getValue());
     2314                }
     2315                out.println("</textarea>");
     2316                out.println("</br>");
     2317                out.println(button(SAVE, _("Save Configuration")));
     2318                out.println(button(CANCEL, _("Cancel")));
     2319        }
     2320
    22012321        /** translate */
    22022322        private static String _(String s) {
  • apps/susimail/src/susimail.properties

    rf5661da r91d7a0a  
    44susimail.ports.pop3=7660
    55susimail.ports.smtp=7659
    6 
    7 susimail.fast.start=true
    86
    97susimail.sender.fixed=true
  • installer/resources/themes/susimail/dark/susimail.css

    rf5661da r91d7a0a  
    234234}
    235235
    236 input.send, input.setpagesize {
     236input.send, input.setpagesize, input.save {
    237237     background: #000 url('/themes/console/images/accept.png') no-repeat 2px center;
     238     min-height: 22px;
     239}
     240
     241input.configure {
     242     background: #000 url('/susimail/icons/wrench.png') no-repeat 2px center;
    238243     min-height: 22px;
    239244}
  • installer/resources/themes/susimail/light/susimail.css

    rf5661da r91d7a0a  
    115115
    116116tr.list0 {
    117      background-color:#e0e0e0;
     117     background-color:#ececec;
    118118}
    119119
    120120tr.list1 {
    121      background-color:#ffffff;
     121     background-color:#f4f4f4;
     122}
     123
     124tr.list0:hover {
     125     background-color:#e0e0f4;
     126}
     127
     128tr.list1:hover {
     129     background-color:#e0e0f4;
     130}
     131
     132tr.list0 a:link {
     133     text-decoration: none;
     134}
     135
     136tr.list1 a:link {
     137     text-decoration: none;
    122138}
    123139
     
    243259}
    244260
    245 input.send, input.setpagesize {
     261input.send, input.setpagesize, input.save {
    246262     background: #ddf url('/themes/console/images/accept.png') no-repeat 4px center;
     263     padding: 2px 3px 2px 24px;
     264     min-height: 22px;
     265}
     266
     267input.configure {
     268     background: #ddf url('/susimail/icons/wrench.png') no-repeat 4px center;
    247269     padding: 2px 3px 2px 24px;
    248270     min-height: 22px;
Note: See TracChangeset for help on using the changeset viewer.