diff --git a/LICENSE.txt b/LICENSE.txt
index 002fc1862b005f069381d1196b60a90886a4e3d9..d178230aa0a14527224de2f1a0a5c2adcbe068a7 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -139,6 +139,7 @@ Applications:
    I2PSnark:
    Copyright (C) 2003 Mark J. Wielaard
    See licenses/LICENSE-GPLv2.txt
+       Silk icons: See licenses/LICENSE-SilkIcons.txt
 
    I2PTunnel:
    (c) 2003 - 2004 mihi
@@ -176,6 +177,7 @@ Applications:
    Router console:
    Public domain.
        Flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
+       Silk icons: See licenses/LICENSE-SilkIcons.txt
 
        GeoIP Data:
        Copyright (c) 2003 Direct Information Pvt. Ltd. All Rights Reserved.
diff --git a/apps/i2psnark/_icons/application.png b/apps/i2psnark/_icons/application.png
new file mode 100644
index 0000000000000000000000000000000000000000..1dee9e366094e87db68c606d0522d72d4b939818
Binary files /dev/null and b/apps/i2psnark/_icons/application.png differ
diff --git a/apps/i2psnark/_icons/book.png b/apps/i2psnark/_icons/book.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0f4dd7928cc5714e002fd2a6e8f2faac0073f00
Binary files /dev/null and b/apps/i2psnark/_icons/book.png differ
diff --git a/apps/i2psnark/_icons/bug.png b/apps/i2psnark/_icons/bug.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d5fb90ec6ee08f53947e0266a87b03f75893446
Binary files /dev/null and b/apps/i2psnark/_icons/bug.png differ
diff --git a/apps/i2psnark/_icons/cancel.png b/apps/i2psnark/_icons/cancel.png
new file mode 100644
index 0000000000000000000000000000000000000000..c149c2bc017d5ce5a8ae9330dd7dbd012482e0f4
Binary files /dev/null and b/apps/i2psnark/_icons/cancel.png differ
diff --git a/apps/i2psnark/_icons/clock.png b/apps/i2psnark/_icons/clock.png
new file mode 100644
index 0000000000000000000000000000000000000000..e2672c20676177efb2fdea593b8f000fd5f12342
Binary files /dev/null and b/apps/i2psnark/_icons/clock.png differ
diff --git a/apps/i2psnark/_icons/compress.png b/apps/i2psnark/_icons/compress.png
new file mode 100644
index 0000000000000000000000000000000000000000..8606ff0fd23c97d71d43afa0bd587e47c1e90441
Binary files /dev/null and b/apps/i2psnark/_icons/compress.png differ
diff --git a/apps/i2psnark/_icons/film.png b/apps/i2psnark/_icons/film.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0ce7bb198a3b268bd634d2b26e9b710f3797d37
Binary files /dev/null and b/apps/i2psnark/_icons/film.png differ
diff --git a/apps/i2psnark/_icons/folder.png b/apps/i2psnark/_icons/folder.png
new file mode 100644
index 0000000000000000000000000000000000000000..784e8fa48234f4f64b6922a6758f254ee0ca08ec
Binary files /dev/null and b/apps/i2psnark/_icons/folder.png differ
diff --git a/apps/i2psnark/_icons/html.png b/apps/i2psnark/_icons/html.png
new file mode 100644
index 0000000000000000000000000000000000000000..55d1072eafda48abb0a5fcecb98b114d866077b9
Binary files /dev/null and b/apps/i2psnark/_icons/html.png differ
diff --git a/apps/i2psnark/_icons/music.png b/apps/i2psnark/_icons/music.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8b3ede3df956f8d505543b190bc8d1b5b4dce75
Binary files /dev/null and b/apps/i2psnark/_icons/music.png differ
diff --git a/apps/i2psnark/_icons/package.png b/apps/i2psnark/_icons/package.png
new file mode 100644
index 0000000000000000000000000000000000000000..da3c2a2d74bab159ba0f65d7db601768258afcb2
Binary files /dev/null and b/apps/i2psnark/_icons/package.png differ
diff --git a/apps/i2psnark/_icons/page.png b/apps/i2psnark/_icons/page.png
new file mode 100644
index 0000000000000000000000000000000000000000..03ddd799fa0a3aec561c75d4221f195db65d6eb9
Binary files /dev/null and b/apps/i2psnark/_icons/page.png differ
diff --git a/apps/i2psnark/_icons/page_white_acrobat.png b/apps/i2psnark/_icons/page_white_acrobat.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f8095e46fa4965700afe1f9d065d8a37b101676
Binary files /dev/null and b/apps/i2psnark/_icons/page_white_acrobat.png differ
diff --git a/apps/i2psnark/_icons/photo.png b/apps/i2psnark/_icons/photo.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c2aaaaaf33ec07184ae0f5824ef24c82c41106f
Binary files /dev/null and b/apps/i2psnark/_icons/photo.png differ
diff --git a/apps/i2psnark/_icons/plugin.png b/apps/i2psnark/_icons/plugin.png
new file mode 100644
index 0000000000000000000000000000000000000000..6187b15aec001b7080b51a5f944f07591f26cc15
Binary files /dev/null and b/apps/i2psnark/_icons/plugin.png differ
diff --git a/apps/i2psnark/_icons/tick.png b/apps/i2psnark/_icons/tick.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9925a06ab02db30c1e7ead9c701c15bc63145cb
Binary files /dev/null and b/apps/i2psnark/_icons/tick.png differ
diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml
index 4d51cb7426d9374a1867b5a0d1b9e88d4d24149f..d3b653d59a47b8be4dd2d6978ec3f2e33b692b47 100644
--- a/apps/i2psnark/java/build.xml
+++ b/apps/i2psnark/java/build.xml
@@ -52,7 +52,7 @@
           <classes dir="./build/obj" includes="**/I2PSnarkServlet*.class" />
      -->
     <target name="war" depends="jar, bundle"> 
-        <war destfile="../i2psnark.war" webxml="../web.xml">
+        <war destfile="../i2psnark.war" webxml="../web.xml" basedir="../" includes="_icons/*" >
           <!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
           <classes dir="./build/obj" includes="**/web/*.class" />
         </war>
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 85c0e917c9b4b1ca45e61da068eed1f6d010aecf..b9a97fe3fe9c65dcaad072c02b4f62811bb99be8 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -53,6 +53,7 @@ public class I2PSnarkServlet extends Default {
     private Log _log;
     private SnarkManager _manager;
     private static long _nonce;
+    private Resource _resourceBase;
     
     public static final String PROP_CONFIG_FILE = "i2psnark.configFile";
     
@@ -67,48 +68,33 @@ public class I2PSnarkServlet extends Default {
             configFile = "i2psnark.config";
         _manager.loadConfig(configFile);
         _manager.start();
-        super.init(new DefaultServletConfig(cfg, _manager.getDataDir().getAbsolutePath()));
+        try {
+            _resourceBase = Resource.newResource(_manager.getDataDir().getAbsolutePath());
+        } catch (IOException ioe) {}
+        super.init(cfg);
     }
     
-    /**
-     *  A ServletConfig we will pass to super
-     */
-    private static class DefaultServletConfig implements ServletConfig {
-        private final ServletConfig _sc;
-        private final String _path;
-
-        DefaultServletConfig(ServletConfig sc, String path) {
-            _sc = sc;
-            _path = path;
-        }
-
-        public String getInitParameter(String name) {
-            if ("acceptRanges".equals(name) || "dirAllowed".equals(name))
-                return "true";
-            if ("resourceBase".equals(name))
-                return _path;
-            return _sc.getInitParameter(name);
-        }
-
-        public Enumeration getInitParameterNames() {
-            return _sc.getInitParameterNames();
-        }
-
-        public ServletContext getServletContext() {
-            return _sc.getServletContext();
-        }
-
-        public String getServletName() {
-            return _sc.getServletName();
-        }
-    }
-
     @Override
     public void destroy() {
         _manager.stop();
         super.destroy();
     }
 
+    /**
+     *  We override this instead of passing a resource base to super(), because
+     *  if a resource base is set, super.getResource() always uses that base,
+     *  and we can't get any resources (like icons) out of the .war
+     */
+    @Override
+    protected Resource getResource(String pathInContext) throws IOException
+    {
+        if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") ||
+            pathInContext.equals("/index.html") || pathInContext.startsWith("/_icons/"))
+            return super.getResource(pathInContext);
+        // files in the i2psnark/ directory
+        return _resourceBase.addPath(pathInContext);
+    }
+
     /**
      * Some parts modified from:
      * <pre>
@@ -1261,26 +1247,30 @@ public class I2PSnarkServlet extends Default {
             long length = item.length();
             if (item.isDirectory()) {
                 complete = true;
-                status = _("Directory");
+                status = "<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/tick.png\"> " +
+                         _("Directory");
             } else {
                 if (snark == null) {
-                    status = "Snark not found?";
+                    // Assume complete, perhaps he removed a completed torrent but kept a bookmark
+                    complete = true;
+                    status = "<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/cancel.png\"> " +
+                                         _("Torrent not found?");
                 } else {
                     try {
                         File f = item.getFile();
                         if (f != null) {
                             long remaining = snark.storage.remaining(f.getCanonicalPath());
-                            if (remaining == 0) {
-                                complete = true;
-                                status = _("Complete");
-                            } else if (remaining < 0) {
+                            if (remaining < 0) {
                                 complete = true;
-                                status = _("File not found in torrent?");
-                            } else if (length <= 0) {
+                                status = "<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/cancel.png\"> " +
+                                         _("File not found in torrent?");
+                            } else if (remaining == 0 || length <= 0) {
                                 complete = true;
-                                status = _("Complete");
+                                status = "<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/tick.png\"> " +
+                                         _("Complete");
                             } else {
-                                status = (100 - (100 * remaining / length)) + "% " + _("complete") +
+                                status = "<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/clock.png\"> " +
+                                         (100 - (100 * remaining / length)) + "% " + _("complete") +
                                          " (" + DataHelper.formatSize(remaining) + " bytes remaining)";
                             }
                         } else {
@@ -1295,24 +1285,72 @@ public class I2PSnarkServlet extends Default {
             String path=URI.addPaths(base,encoded);
             if (item.isDirectory() && !path.endsWith("/"))
                 path=URI.addPaths(path,"/");
+            String plc = path.toLowerCase();
+
+            // pick an icon; try to catch the common types in an i2p environment
+            String icon;
+            if (item.isDirectory()) {
+                icon = "folder";
+            } else {
+                // Should really just add to the mime.properties file in org.mortbay.jetty.jar
+                // instead of this mishmash. We can't get to HttpContext.setMimeMapping()
+                // from here? We could do it from a web.xml perhaps.
+                // Or could we put our own org/mortbay/http/mime.properties file in the war?
+                String mime = getServletContext().getMimeType(path);
+                if (mime == null)
+                    mime = "";
+                if (mime.equals("text/html"))
+                    icon = "html";
+                else if (mime.equals("text/plain") || plc.endsWith(".nfo"))
+                    icon = "page";
+                else if (mime.equals("application/java-archive") || plc.endsWith(".war"))
+                    icon = "package";
+                else if (plc.endsWith(".xpi2p"))
+                    icon = "plugin";
+                else if (mime.equals("application/pdf"))
+                    icon = "page_white_acrobat";
+                else if (mime.startsWith("image/") || plc.endsWith(".ico"))
+                    icon = "photo";
+                else if (mime.startsWith("audio/") || mime.equals("application/ogg") ||
+                         plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") ||
+                         plc.endsWith(".ape"))
+                    icon = "music";
+                else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") ||
+                         plc.endsWith(".mp4"))
+                    icon = "film";
+                else if (mime.equals("application/zip") || mime.equals("application/x-gtar") ||
+                         mime.equals("application/compress") || mime.equals("application/gzip") ||
+                         mime.equals("application/x-tar") ||
+                         plc.endsWith(".rar") || plc.endsWith(".bz2") || plc.endsWith(".7z"))
+                    icon = "compress";
+                else if (plc.endsWith(".exe"))
+                    icon = "application";
+                else
+                    icon = "bug";
+            }
             if (complete) {
+                buf.append("<a href=\"").append(path).append("\"><img alt=\"\" border=\"0\" ");
                 // thumbnail ?
-                String plc = path.toLowerCase();
-                if (plc.endsWith(".jpg") || plc.endsWith(".png") || plc.endsWith(".gif")) {
-                    buf.append("<a href=\"").append(path).append("\"><img alt=\"\" border=\"0\" class=\"thumb\" src=\"")
+                if (plc.endsWith(".jpg") || plc.endsWith(".jpeg") || plc.endsWith(".png") ||
+                    plc.endsWith(".gif") || plc.endsWith(".ico")) {
+                    buf.append("class=\"thumb\" src=\"")
                        .append(path).append("\"></a> ");
+                } else {
+                    buf.append("height=\"16\" width=\"16\" src=\"/i2psnark/_icons/").append(icon).append(".png\"></a> ");
                 }
                 buf.append("<A HREF=\"");
                 buf.append(path);
                 buf.append("\">");
+            } else {
+                buf.append("<img height=\"16\" width=\"16\" src=\"/i2psnark/_icons/").append(icon).append(".png\"> ");
             }
             buf.append(ls[i]);
             if (complete)
                 buf.append("</a>");
-            buf.append("</TD><TD ALIGN=right class=\"").append(rowClass).append("\">");
+            buf.append("</TD><TD ALIGN=right class=\"").append(rowClass).append(" snarkFileSize\">");
             if (!item.isDirectory())
                 buf.append(DataHelper.formatSize(length)).append(' ').append(_("Bytes"));
-            buf.append("</TD><TD>");
+            buf.append("</TD><TD class=\"").append(rowClass).append(" snarkFileStatus\">");
             //buf.append(dfmt.format(new Date(item.lastModified())));
             buf.append(status);
             buf.append("</TD></TR>\n");
diff --git a/installer/resources/themes/console/snark.css b/installer/resources/themes/console/snark.css
index 70091b13f9fc32745f7d63dd3e56c675d5236e55..4c673c1426788311404ca60ebe036f6ee89b9184 100644
--- a/installer/resources/themes/console/snark.css
+++ b/installer/resources/themes/console/snark.css
@@ -110,6 +110,15 @@ td {
 
 .snarkFileName {
      min-width: 25em;
+     padding: 4px 10px;
+}
+
+.snarkFileSize {
+     padding: 4px 10px;
+}
+
+.snarkFileStatus {
+     padding: 4px 10px;
 }
 
 .thumb {
@@ -225,7 +234,8 @@ textarea {
 
 img {
      border: none;
-     margin: 5px 5px 0px 5px;
+     margin: 4px 8px 4px 4px;
+     vertical-align: middle;
      opacity: 1.0;
      line-height: 100%;
 }