Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 4402)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 4403)
@@ -3,8 +3,4 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
-
-import com.kitfox.svg.SVGDiagram;
-import com.kitfox.svg.SVGException;
-import com.kitfox.svg.SVGUniverse;
 
 import java.awt.Component;
@@ -21,4 +17,5 @@
 import java.awt.Transparency;
 import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -33,5 +30,4 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
-
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
@@ -41,4 +37,16 @@
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.plugins.PluginHandler;
+import org.openstreetmap.josm.tools.Utils;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import com.kitfox.svg.SVGDiagram;
+import com.kitfox.svg.SVGException;
+import com.kitfox.svg.SVGUniverse;
 
 /**
@@ -80,6 +88,6 @@
             String ext = name.indexOf('.') != -1 ? "" : ".???";
             throw new NullPointerException(tr(
-            "Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.",
-            name+ext));
+                    "Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.",
+                    name+ext));
         }
         return icon;
@@ -117,5 +125,5 @@
         return getIfAvailable(dirs, id, subdir, name, archive, null, sanitize);
     }
-    
+
     /**
      * The full path of the image is either a url (starting with http://)
@@ -129,5 +137,5 @@
      * @param archive   A zip file where the image is located (may be null).
      * @param dim       The dimensions of the image if it should be scaled. null if the
-     *                  original size of the image should be returned. The width 
+     *                  original size of the image should be returned. The width
      *                  part of the dimension can be -1. Then it will scale the width
      *                  in the same way as the height. (And the other way around.)
@@ -154,4 +162,12 @@
             if (ir != null) {
                 cache.put(url, ir);
+            }
+            return ir;
+        } else if (name.startsWith("wiki://")) {
+            ImageResource ir = cache.get(name);
+            if (ir != null) return ir;
+            ir = getIfAvailableWiki(name, type);
+            if (ir != null) {
+                cache.put(name, ir);
             }
             return ir;
@@ -209,6 +225,7 @@
                         // creating the image.
                         URL path = getImageUrl(full_name, dirs);
-                        if (path == null)
+                        if (path == null) {
                             continue;
+                        }
                         ir = getIfAvailableLocalURL(path, type);
                         if (ir != null) {
@@ -241,4 +258,34 @@
             return null;
         }
+    }
+
+    private static ImageResource getIfAvailableWiki(String name, ImageType type) {
+        final Collection<String> defaultBaseUrls = Arrays.asList(
+                "http://wiki.openstreetmap.org/w/images/",
+                "http://upload.wikimedia.org/wikipedia/commons/",
+                "http://wiki.openstreetmap.org/wiki/File:"
+        );
+        final Collection<String> baseUrls = Main.pref.getCollection("image-provider.wiki.urls", defaultBaseUrls);
+
+        final String fn = name.substring(name.lastIndexOf('/') + 1);
+
+        ImageResource result = null;
+        for (String b : baseUrls) {
+            String url;
+            if (b.endsWith(":")) {
+                url = getImgUrlFromWikiInfoPage(b, fn);
+                if (url == null) {
+                    continue;
+                }
+            } else {
+                final String fn_md5 = Utils.md5Hex(fn);
+                url = b + fn_md5.substring(0,1) + "/" + fn_md5.substring(0,2) + "/" + fn;
+            }
+            result = getIfAvailableHttp(url, type);
+            if (result != null) {
+                break;
+            }
+        }
+        return result;
     }
 
@@ -379,4 +426,56 @@
     }
 
+    /**
+     * Reads the wiki page on a certain file in html format in order to find the real image URL.
+     */
+    private static String getImgUrlFromWikiInfoPage(final String base, final String fn) {
+
+        /** Quit parsing, when a certain condition is met */
+        class SAXReturnException extends SAXException {
+            private String result;
+
+            public SAXReturnException(String result) {
+                this.result = result;
+            }
+
+            public String getResult() {
+                return result;
+            }
+        }
+
+        try {
+            final XMLReader parser = XMLReaderFactory.createXMLReader();
+            parser.setContentHandler(new DefaultHandler() {
+                @Override
+                public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+                    System.out.println();
+                    if (localName.equalsIgnoreCase("img")) {
+                        String val = atts.getValue("src");
+                        if (val.endsWith(fn))
+                            throw new SAXReturnException(val);  // parsing done, quit early
+                    }
+                }
+            });
+
+            parser.setEntityResolver(new EntityResolver() {
+                public InputSource resolveEntity (String publicId, String systemId) {
+                    return new InputSource(new ByteArrayInputStream(new byte[0]));
+                }
+            });
+
+            parser.parse(new InputSource(new MirroredInputStream(
+                    base + fn,
+                    new File(Main.pref.getPreferencesDir(), "images").toString()
+            )));
+        } catch (SAXReturnException r) {
+            return r.getResult();
+        } catch (Exception e) {
+            System.out.println("INFO: parsing " + base + fn + " failed:\n" + e);
+            return null;
+        }
+        System.out.println("INFO: parsing " + base + fn + " failed: Unexpected content.");
+        return null;
+    }
+
     public static Cursor getCursor(String name, String overlay) {
         ImageIcon img = get("cursor", name);
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4402)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4403)
@@ -15,4 +15,7 @@
 import java.io.OutputStream;
 import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -312,3 +315,39 @@
         return null;
     }
+
+    /**
+     * Calculate MD5 hash of a string and output in hexadecimal format.
+     * Output has length 32 with characters in range [0-9a-f]
+     */
+    public static String md5Hex(String data) {
+        byte[] byteData = null;
+        try {
+            byteData = data.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException();
+        }
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException();
+        }
+        byte[] byteDigest = md.digest(byteData);
+        return toHexString(byteDigest);
+    }
+
+    /**
+     * Converts a byte array to a string of hexadecimal characters. Preserves leading zeros, so the
+     * size of the output string is always twice the number of input bytes.
+     */
+    public static String toHexString(byte[] bytes) {
+        char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+        char[] hexChars = new char[bytes.length * 2];
+        for (int j=0; j<bytes.length; j++) {
+            int v = bytes[j] & 0xFF;
+            hexChars[j*2] = hexArray[v/16];
+            hexChars[j*2 + 1] = hexArray[v%16];
+        }
+        return new String(hexChars);
+    }
 }
