source: josm/trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java@ 11915

Last change on this file since 11915 was 11642, checked in by Don-vip, 7 years ago

fix #14422 - Dynamic NTV2 grids

  • Property svn:eol-style set to native
File size: 35.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static java.awt.event.InputEvent.ALT_DOWN_MASK;
5import static java.awt.event.InputEvent.CTRL_DOWN_MASK;
6import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
7import static java.awt.event.KeyEvent.VK_A;
8import static java.awt.event.KeyEvent.VK_C;
9import static java.awt.event.KeyEvent.VK_D;
10import static java.awt.event.KeyEvent.VK_DELETE;
11import static java.awt.event.KeyEvent.VK_DOWN;
12import static java.awt.event.KeyEvent.VK_ENTER;
13import static java.awt.event.KeyEvent.VK_ESCAPE;
14import static java.awt.event.KeyEvent.VK_F10;
15import static java.awt.event.KeyEvent.VK_F4;
16import static java.awt.event.KeyEvent.VK_LEFT;
17import static java.awt.event.KeyEvent.VK_NUM_LOCK;
18import static java.awt.event.KeyEvent.VK_PRINTSCREEN;
19import static java.awt.event.KeyEvent.VK_RIGHT;
20import static java.awt.event.KeyEvent.VK_SHIFT;
21import static java.awt.event.KeyEvent.VK_SPACE;
22import static java.awt.event.KeyEvent.VK_TAB;
23import static java.awt.event.KeyEvent.VK_UP;
24import static java.awt.event.KeyEvent.VK_V;
25import static java.awt.event.KeyEvent.VK_X;
26import static java.awt.event.KeyEvent.VK_Y;
27import static java.awt.event.KeyEvent.VK_Z;
28import static org.openstreetmap.josm.tools.I18n.tr;
29
30import java.awt.GraphicsEnvironment;
31import java.io.BufferedWriter;
32import java.io.File;
33import java.io.FileInputStream;
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.OutputStreamWriter;
37import java.io.Writer;
38import java.nio.charset.StandardCharsets;
39import java.nio.file.DirectoryStream;
40import java.nio.file.FileSystems;
41import java.nio.file.Files;
42import java.nio.file.Path;
43import java.security.InvalidKeyException;
44import java.security.KeyFactory;
45import java.security.KeyStore;
46import java.security.KeyStoreException;
47import java.security.NoSuchAlgorithmException;
48import java.security.NoSuchProviderException;
49import java.security.PublicKey;
50import java.security.SignatureException;
51import java.security.cert.CertificateException;
52import java.security.spec.InvalidKeySpecException;
53import java.security.spec.X509EncodedKeySpec;
54import java.util.ArrayList;
55import java.util.Arrays;
56import java.util.Collection;
57import java.util.Enumeration;
58import java.util.List;
59import java.util.Locale;
60import java.util.Properties;
61
62import javax.swing.JOptionPane;
63
64import org.openstreetmap.josm.Main;
65import org.openstreetmap.josm.data.Preferences;
66
67/**
68 * {@code PlatformHook} implementation for Microsoft Windows systems.
69 * @since 1023
70 */
71public class PlatformHookWindows implements PlatformHook {
72
73 /**
74 * Simple data class to hold information about a font.
75 *
76 * Used for fontconfig.properties files.
77 */
78 public static class FontEntry {
79 /**
80 * The character subset. Basically a free identifier, but should be unique.
81 */
82 @Preferences.pref
83 public String charset;
84
85 /**
86 * Platform font name.
87 */
88 @Preferences.pref
89 @Preferences.writeExplicitly
90 public String name = "";
91
92 /**
93 * File name.
94 */
95 @Preferences.pref
96 @Preferences.writeExplicitly
97 public String file = "";
98
99 /**
100 * Constructs a new {@code FontEntry}.
101 */
102 public FontEntry() {
103 // Default constructor needed for construction by reflection
104 }
105
106 /**
107 * Constructs a new {@code FontEntry}.
108 * @param charset The character subset. Basically a free identifier, but should be unique
109 * @param name Platform font name
110 * @param file File name
111 */
112 public FontEntry(String charset, String name, String file) {
113 this.charset = charset;
114 this.name = name;
115 this.file = file;
116 }
117 }
118
119 private static final byte[] INSECURE_PUBLIC_KEY = new byte[] {
120 0x30, (byte) 0x82, 0x1, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a, (byte) 0x86, 0x48,
121 (byte) 0x86, (byte) 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3, (byte) 0x82, 0x1, 0xf, 0x0,
122 0x30, (byte) 0x82, 0x01, 0x0a, 0x02, (byte) 0x82, 0x01, 0x01, 0x00, (byte) 0x95, (byte) 0x95, (byte) 0x88,
123 (byte) 0x84, (byte) 0xc8, (byte) 0xd9, 0x6b, (byte) 0xc5, (byte) 0xda, 0x0b, 0x69, (byte) 0xbf, (byte) 0xfc,
124 0x7e, (byte) 0xb9, (byte) 0x96, 0x2c, (byte) 0xeb, (byte) 0x8f, (byte) 0xbc, 0x6e, 0x40, (byte) 0xe6, (byte) 0xe2,
125 (byte) 0xfc, (byte) 0xf1, 0x7f, 0x73, (byte) 0xa7, (byte) 0x9d, (byte) 0xde, (byte) 0xc7, (byte) 0x88, 0x57, 0x51,
126 (byte) 0x84, (byte) 0xed, (byte) 0x96, (byte) 0xfb, (byte) 0xe1, 0x38, (byte) 0xef, 0x08, 0x2b, (byte) 0xf3,
127 (byte) 0xc7, (byte) 0xc3, 0x5d, (byte) 0xfe, (byte) 0xf9, 0x51, (byte) 0xe6, 0x29, (byte) 0xfc, (byte) 0xe5, 0x0d,
128 (byte) 0xa1, 0x0d, (byte) 0xa8, (byte) 0xb4, (byte) 0xae, 0x26, 0x18, 0x19, 0x4d, 0x6c, 0x0c, 0x3b, 0x12, (byte) 0xba,
129 (byte) 0xbc, 0x5f, 0x32, (byte) 0xb3, (byte) 0xbe, (byte) 0x9d, 0x17, 0x0d, 0x4d, 0x2f, 0x1a, 0x48, (byte) 0xb7,
130 (byte) 0xac, (byte) 0xf7, 0x1a, 0x43, 0x01, (byte) 0x97, (byte) 0xf4, (byte) 0xf8, 0x4c, (byte) 0xbb, 0x6a, (byte) 0xbc,
131 0x33, (byte) 0xe1, 0x73, 0x1e, (byte) 0x86, (byte) 0xfb, 0x2e, (byte) 0xb1, 0x63, 0x75, (byte) 0x85, (byte) 0xdc,
132 (byte) 0x82, 0x6c, 0x28, (byte) 0xf1, (byte) 0xe3, (byte) 0x90, 0x63, (byte) 0x9d, 0x3d, 0x48, (byte) 0x8a, (byte) 0x8c,
133 0x47, (byte) 0xe2, 0x10, 0x0b, (byte) 0xef, (byte) 0x91, (byte) 0x94, (byte) 0xb0, 0x6c, 0x4c, (byte) 0x80, 0x76, 0x03,
134 (byte) 0xe1, (byte) 0xb6, (byte) 0x90, (byte) 0x87, (byte) 0xd9, (byte) 0xae, (byte) 0xf4, (byte) 0x8e, (byte) 0xe0,
135 (byte) 0x9f, (byte) 0xe7, 0x3a, 0x2c, 0x2f, 0x21, (byte) 0xd4, 0x46, (byte) 0xba, (byte) 0x95, 0x70, (byte) 0xa9, 0x5b,
136 0x20, 0x2a, (byte) 0xfa, 0x52, 0x3e, (byte) 0x9d, (byte) 0xd9, (byte) 0xef, 0x28, (byte) 0xc5, (byte) 0xd1, 0x60,
137 (byte) 0x89, 0x68, 0x6e, 0x7f, (byte) 0xd7, (byte) 0x9e, (byte) 0x89, 0x4c, (byte) 0xeb, 0x4d, (byte) 0xd2, (byte) 0xc6,
138 (byte) 0xf4, 0x2d, 0x02, 0x5d, (byte) 0xda, (byte) 0xde, 0x33, (byte) 0xfe, (byte) 0xc1, 0x7e, (byte) 0xde, 0x4f, 0x1f,
139 (byte) 0x9b, 0x6e, 0x6f, 0x0f, 0x66, 0x71, 0x19, (byte) 0xe9, 0x43, 0x3c, (byte) 0x83, 0x0a, 0x0f, 0x28, 0x21, (byte) 0xc8,
140 0x38, (byte) 0xd3, 0x4e, 0x48, (byte) 0xdf, (byte) 0xd4, (byte) 0x99, (byte) 0xb5, (byte) 0xc6, (byte) 0x8d, (byte) 0xd4,
141 (byte) 0xc1, 0x69, 0x58, 0x79, (byte) 0x82, 0x32, (byte) 0x82, (byte) 0xd4, (byte) 0x86, (byte) 0xe2, 0x04, 0x08, 0x63,
142 (byte) 0x87, (byte) 0xf0, 0x2a, (byte) 0xf6, (byte) 0xec, 0x3e, 0x51, 0x0f, (byte) 0xda, (byte) 0xb4, 0x67, 0x19, 0x5e,
143 0x16, 0x02, (byte) 0x9f, (byte) 0xf1, 0x19, 0x0c, 0x3e, (byte) 0xb8, 0x04, 0x49, 0x07, 0x53, 0x02, 0x03, 0x01, 0x00, 0x01
144 };
145
146 private static final String WINDOWS_ROOT = "Windows-ROOT";
147
148 @Override
149 public void afterPrefStartupHook() {
150 extendFontconfig("fontconfig.properties.src");
151 }
152
153 @Override
154 public void openUrl(String url) throws IOException {
155 Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
156 }
157
158 @Override
159 public void initSystemShortcuts() {
160 // CHECKSTYLE.OFF: LineLength
161 //Shortcut.registerSystemCut("system:menuexit", tr("reserved"), VK_Q, CTRL_DOWN_MASK);
162 Shortcut.registerSystemShortcut("system:duplicate", tr("reserved"), VK_D, CTRL_DOWN_MASK); // not really system, but to avoid odd results
163
164 // Windows 7 shortcuts: http://windows.microsoft.com/en-US/windows7/Keyboard-shortcuts
165
166 // Shortcuts with setAutomatic(): items with automatic shortcuts will not be added to the menu bar at all
167
168 // Don't know why Ctrl-Alt-Del isn't even listed on official Microsoft support page
169 Shortcut.registerSystemShortcut("system:reset", tr("reserved"), VK_DELETE, CTRL_DOWN_MASK | ALT_DOWN_MASK).setAutomatic();
170
171 // Ease of Access keyboard shortcuts
172 Shortcut.registerSystemShortcut("microsoft-reserved-01", tr("reserved"), VK_PRINTSCREEN, ALT_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Turn High Contrast on or off
173 Shortcut.registerSystemShortcut("microsoft-reserved-02", tr("reserved"), VK_NUM_LOCK, ALT_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Turn Mouse Keys on or off
174 //Shortcut.registerSystemCut("microsoft-reserved-03", tr("reserved"), VK_U, );// Open the Ease of Access Center (TODO: Windows-U, how to handle it in Java ?)
175
176 // General keyboard shortcuts
177 //Shortcut.registerSystemShortcut("system:help", tr("reserved"), VK_F1, 0); // Display Help
178 Shortcut.registerSystemShortcut("system:copy", tr("reserved"), VK_C, CTRL_DOWN_MASK); // Copy the selected item
179 Shortcut.registerSystemShortcut("system:cut", tr("reserved"), VK_X, CTRL_DOWN_MASK); // Cut the selected item
180 Shortcut.registerSystemShortcut("system:paste", tr("reserved"), VK_V, CTRL_DOWN_MASK); // Paste the selected item
181 Shortcut.registerSystemShortcut("system:undo", tr("reserved"), VK_Z, CTRL_DOWN_MASK); // Undo an action
182 Shortcut.registerSystemShortcut("system:redo", tr("reserved"), VK_Y, CTRL_DOWN_MASK); // Redo an action
183 //Shortcut.registerSystemCut("microsoft-reserved-10", tr("reserved"), VK_DELETE, 0); // Delete the selected item and move it to the Recycle Bin
184 //Shortcut.registerSystemCut("microsoft-reserved-11", tr("reserved"), VK_DELETE, SHIFT_DOWN_MASK); // Delete the selected item without moving it to the Recycle Bin first
185 //Shortcut.registerSystemCut("system:rename", tr("reserved"), VK_F2, 0); // Rename the selected item
186 Shortcut.registerSystemShortcut("system:movefocusright", tr("reserved"), VK_RIGHT, CTRL_DOWN_MASK); // Move the cursor to the beginning of the next word
187 Shortcut.registerSystemShortcut("system:movefocusleft", tr("reserved"), VK_LEFT, CTRL_DOWN_MASK); // Move the cursor to the beginning of the previous word
188 Shortcut.registerSystemShortcut("system:movefocusdown", tr("reserved"), VK_DOWN, CTRL_DOWN_MASK); // Move the cursor to the beginning of the next paragraph
189 Shortcut.registerSystemShortcut("system:movefocusup", tr("reserved"), VK_UP, CTRL_DOWN_MASK); // Move the cursor to the beginning of the previous paragraph
190 //Shortcut.registerSystemCut("microsoft-reserved-17", tr("reserved"), VK_RIGHT, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
191 //Shortcut.registerSystemCut("microsoft-reserved-18", tr("reserved"), VK_LEFT, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
192 //Shortcut.registerSystemCut("microsoft-reserved-19", tr("reserved"), VK_DOWN, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
193 //Shortcut.registerSystemCut("microsoft-reserved-20", tr("reserved"), VK_UP, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
194 //Shortcut.registerSystemCut("microsoft-reserved-21", tr("reserved"), VK_RIGHT, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
195 //Shortcut.registerSystemCut("microsoft-reserved-22", tr("reserved"), VK_LEFT, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
196 //Shortcut.registerSystemCut("microsoft-reserved-23", tr("reserved"), VK_DOWN, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
197 //Shortcut.registerSystemCut("microsoft-reserved-24", tr("reserved"), VK_UP, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
198 //Shortcut.registerSystemCut("microsoft-reserved-25", tr("reserved"), VK_RIGHT+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
199 //Shortcut.registerSystemCut("microsoft-reserved-26", tr("reserved"), VK_LEFT+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
200 //Shortcut.registerSystemCut("microsoft-reserved-27", tr("reserved"), VK_DOWN+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
201 //Shortcut.registerSystemCut("microsoft-reserved-28", tr("reserved"), VK_UP+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
202 Shortcut.registerSystemShortcut("system:selectall", tr("reserved"), VK_A, CTRL_DOWN_MASK); // Select all items in a document or window
203 //Shortcut.registerSystemCut("system:search", tr("reserved"), VK_F3, 0); // Search for a file or folder
204 Shortcut.registerSystemShortcut("microsoft-reserved-31", tr("reserved"), VK_ENTER, ALT_DOWN_MASK).setAutomatic(); // Display properties for the selected item
205 Shortcut.registerSystemShortcut("system:exit", tr("reserved"), VK_F4, ALT_DOWN_MASK).setAutomatic(); // Close the active item, or exit the active program
206 Shortcut.registerSystemShortcut("microsoft-reserved-33", tr("reserved"), VK_SPACE, ALT_DOWN_MASK).setAutomatic(); // Open the shortcut menu for the active window
207 //Shortcut.registerSystemCut("microsoft-reserved-34", tr("reserved"), VK_F4, CTRL_DOWN_MASK); // Close the active document (in programs that allow you to have multiple documents open simultaneously)
208 Shortcut.registerSystemShortcut("microsoft-reserved-35", tr("reserved"), VK_TAB, ALT_DOWN_MASK).setAutomatic(); // Switch between open items
209 Shortcut.registerSystemShortcut("microsoft-reserved-36", tr("reserved"), VK_TAB, CTRL_DOWN_MASK | ALT_DOWN_MASK).setAutomatic(); // Use the arrow keys to switch between open items
210 //Shortcut.registerSystemCut("microsoft-reserved-37", tr("reserved"), VK_TAB, ); // Cycle through programs on the taskbar by using Aero Flip 3-D (TODO: Windows-Tab, how to handle it in Java ?)
211 //Shortcut.registerSystemCut("microsoft-reserved-38", tr("reserved"), VK_TAB, CTRL_DOWN_MASK | ); // Use the arrow keys to cycle through programs on the taskbar by using Aero Flip 3-D (TODO: Ctrl-Windows-Tab, how to handle it in Java ?)
212 Shortcut.registerSystemShortcut("microsoft-reserved-39", tr("reserved"), VK_ESCAPE, ALT_DOWN_MASK).setAutomatic(); // Cycle through items in the order in which they were opened
213 //Shortcut.registerSystemCut("microsoft-reserved-40", tr("reserved"), VK_F6, 0); // Cycle through screen elements in a window or on the desktop
214 //Shortcut.registerSystemCut("microsoft-reserved-41", tr("reserved"), VK_F4, 0); // Display the address bar list in Windows Explorer
215 Shortcut.registerSystemShortcut("microsoft-reserved-42", tr("reserved"), VK_F10, SHIFT_DOWN_MASK); // Display the shortcut menu for the selected item
216 Shortcut.registerSystemShortcut("microsoft-reserved-43", tr("reserved"), VK_ESCAPE, CTRL_DOWN_MASK).setAutomatic(); // Open the Start menu
217 //Shortcut.registerSystemShortcut("microsoft-reserved-44", tr("reserved"), VK_F10, 0); // Activate the menu bar in the active program
218 //Shortcut.registerSystemCut("microsoft-reserved-45", tr("reserved"), VK_RIGHT, 0); // Open the next menu to the right, or open a submenu
219 //Shortcut.registerSystemCut("microsoft-reserved-46", tr("reserved"), VK_LEFT, 0); // Open the next menu to the left, or close a submenu
220 //Shortcut.registerSystemCut("microsoft-reserved-47", tr("reserved"), VK_F5, 0); // Refresh the active window
221 //Shortcut.registerSystemCut("microsoft-reserved-48", tr("reserved"), VK_UP, ALT_DOWN_MASK); // View the folder one level up in Windows Explorer
222 //Shortcut.registerSystemCut("microsoft-reserved-49", tr("reserved"), VK_ESCAPE, 0); // Cancel the current task
223 Shortcut.registerSystemShortcut("microsoft-reserved-50", tr("reserved"), VK_ESCAPE, CTRL_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Open Task Manager
224 Shortcut.registerSystemShortcut("microsoft-reserved-51", tr("reserved"), VK_SHIFT, ALT_DOWN_MASK).setAutomatic(); // Switch the input language when multiple input languages are enabled
225 Shortcut.registerSystemShortcut("microsoft-reserved-52", tr("reserved"), VK_SHIFT, CTRL_DOWN_MASK).setAutomatic(); // Switch the keyboard layout when multiple keyboard layouts are enabled
226 //Shortcut.registerSystemCut("microsoft-reserved-53", tr("reserved"), ); // Change the reading direction of text in right-to-left reading languages (TODO: unclear)
227 // CHECKSTYLE.ON: LineLength
228 }
229
230 @Override
231 public String getDefaultStyle() {
232 return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
233 }
234
235 @Override
236 public boolean rename(File from, File to) {
237 if (to.exists())
238 Utils.deleteFile(to);
239 return from.renameTo(to);
240 }
241
242 @Override
243 public String getOSDescription() {
244 return Utils.strip(System.getProperty("os.name")) + ' ' +
245 ((System.getenv("ProgramFiles(x86)") == null) ? "32" : "64") + "-Bit";
246 }
247
248 /**
249 * Loads Windows-ROOT keystore.
250 * @return Windows-ROOT keystore
251 * @throws NoSuchAlgorithmException if the algorithm used to check the integrity of the keystore cannot be found
252 * @throws CertificateException if any of the certificates in the keystore could not be loaded
253 * @throws IOException if there is an I/O or format problem with the keystore data, if a password is required but not given
254 * @throws KeyStoreException if no Provider supports a KeyStore implementation for the type "Windows-ROOT"
255 * @since 7343
256 */
257 public static KeyStore getRootKeystore() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
258 KeyStore ks = KeyStore.getInstance(WINDOWS_ROOT);
259 ks.load(null, null);
260 return ks;
261 }
262
263 /**
264 * Removes potential insecure certificates installed with previous versions of JOSM on Windows.
265 * @throws NoSuchAlgorithmException on unsupported signature algorithms
266 * @throws CertificateException if any of the certificates in the Windows keystore could not be loaded
267 * @throws KeyStoreException if no Provider supports a KeyStoreSpi implementation for the type "Windows-ROOT"
268 * @throws IOException if there is an I/O or format problem with the keystore data, if a password is required but not given
269 * @since 7335
270 */
271 public static void removeInsecureCertificates() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
272 // We offered before a public private key we need now to remove from Windows PCs as it might be a huge security risk (see #10230)
273 PublicKey insecurePubKey = null;
274 try {
275 insecurePubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(INSECURE_PUBLIC_KEY));
276 } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
277 Main.error(e);
278 return;
279 }
280 KeyStore ks = getRootKeystore();
281 Enumeration<String> en = ks.aliases();
282 Collection<String> insecureCertificates = new ArrayList<>();
283 while (en.hasMoreElements()) {
284 String alias = en.nextElement();
285 // Look for certificates associated with a private key
286 if (ks.isKeyEntry(alias)) {
287 try {
288 ks.getCertificate(alias).verify(insecurePubKey);
289 // If no exception, this is a certificate signed with the insecure key -> remove it
290 insecureCertificates.add(alias);
291 } catch (InvalidKeyException | NoSuchProviderException | SignatureException e) {
292 // If exception this is not a certificate related to JOSM, just trace it
293 Main.trace(alias + " --> " + e.getClass().getName());
294 Main.trace(e);
295 }
296 }
297 }
298 // Remove insecure certificates
299 if (!insecureCertificates.isEmpty()) {
300 StringBuilder message = new StringBuilder("<html>");
301 message.append(tr("A previous version of JOSM has installed a custom certificate "+
302 "in order to provide HTTPS support for Remote Control:"))
303 .append("<br><ul>");
304 for (String alias : insecureCertificates) {
305 message.append("<li>")
306 .append(alias)
307 .append("</li>");
308 }
309 message.append("</ul>")
310 .append(tr("It appears it could be an important <b>security risk</b>.<br><br>"+
311 "You are now going to be prompted by Windows to remove this insecure certificate.<br>"+
312 "For your own safety, <b>please click Yes</b> in next dialog."))
313 .append("</html>");
314 JOptionPane.showMessageDialog(Main.parent, message.toString(), tr("Warning"), JOptionPane.WARNING_MESSAGE);
315 for (String alias : insecureCertificates) {
316 Main.warn(tr("Removing insecure certificate from {0} keystore: {1}", WINDOWS_ROOT, alias));
317 try {
318 ks.deleteEntry(alias);
319 } catch (KeyStoreException e) {
320 Main.error(e, tr("Unable to remove insecure certificate from keystore: {0}", e.getMessage()));
321 }
322 }
323 }
324 }
325
326 @Override
327 public boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
328 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
329 KeyStore ks = getRootKeystore();
330 // Look for certificate to install
331 String alias = ks.getCertificateAlias(trustedCert.getTrustedCertificate());
332 if (alias != null) {
333 // JOSM certificate found, return
334 Main.debug(tr("JOSM localhost certificate found in {0} keystore: {1}", WINDOWS_ROOT, alias));
335 return false;
336 }
337 if (!GraphicsEnvironment.isHeadless()) {
338 // JOSM certificate not found, warn user
339 StringBuilder message = new StringBuilder("<html>");
340 message.append(tr("Remote Control is configured to provide HTTPS support.<br>"+
341 "This requires to add a custom certificate generated by JOSM to the Windows Root CA store.<br><br>"+
342 "You are now going to be prompted by Windows to confirm this operation.<br>"+
343 "To enable proper HTTPS support, <b>please click Yes</b> in next dialog.<br><br>"+
344 "If unsure, you can also click No then disable HTTPS support in Remote Control preferences."))
345 .append("</html>");
346 JOptionPane.showMessageDialog(Main.parent, message.toString(),
347 tr("HTTPS support in Remote Control"), JOptionPane.INFORMATION_MESSAGE);
348 }
349 // install it to Windows-ROOT keystore, used by IE, Chrome and Safari, but not by Firefox
350 Main.info(tr("Adding JOSM localhost certificate to {0} keystore", WINDOWS_ROOT));
351 ks.setEntry(entryAlias, trustedCert, null);
352 return true;
353 }
354
355 @Override
356 public File getDefaultCacheDirectory() {
357 String p = System.getenv("LOCALAPPDATA");
358 if (p == null || p.isEmpty()) {
359 // Fallback for Windows OS earlier than Windows Vista, where the variable is not defined
360 p = System.getenv("APPDATA");
361 }
362 return new File(new File(p, Main.pref.getJOSMDirectoryBaseName()), "cache");
363 }
364
365 @Override
366 public File getDefaultPrefDirectory() {
367 return new File(System.getenv("APPDATA"), Main.pref.getJOSMDirectoryBaseName());
368 }
369
370 @Override
371 public File getDefaultUserDataDirectory() {
372 // Use preferences directory by default
373 return Main.pref.getPreferencesDirectory();
374 }
375
376 /**
377 * <p>Add more fallback fonts to the Java runtime, in order to get
378 * support for more scripts.</p>
379 *
380 * <p>The font configuration in Java doesn't include some Indic scripts,
381 * even though MS Windows ships with fonts that cover these unicode ranges.</p>
382 *
383 * <p>To fix this, the fontconfig.properties template is copied to the JOSM
384 * cache folder. Then, the additional entries are added to the font
385 * configuration. Finally the system property "sun.awt.fontconfig" is set
386 * to the customized fontconfig.properties file.</p>
387 *
388 * <p>This is a crude hack, but better than no font display at all for these languages.
389 * There is no guarantee, that the template file
390 * ($JAVA_HOME/lib/fontconfig.properties.src) matches the default
391 * configuration (which is in a binary format).
392 * Furthermore, the system property "sun.awt.fontconfig" is undocumented and
393 * may no longer work in future versions of Java.</p>
394 *
395 * <p>Related Java bug: <a href="https://bugs.openjdk.java.net/browse/JDK-8008572">JDK-8008572</a></p>
396 *
397 * @param templateFileName file name of the fontconfig.properties template file
398 */
399 protected void extendFontconfig(String templateFileName) {
400 String customFontconfigFile = Main.pref.get("fontconfig.properties", null);
401 if (customFontconfigFile != null) {
402 Utils.updateSystemProperty("sun.awt.fontconfig", customFontconfigFile);
403 return;
404 }
405 if (!Main.pref.getBoolean("font.extended-unicode", true))
406 return;
407
408 String javaLibPath = System.getProperty("java.home") + File.separator + "lib";
409 Path templateFile = FileSystems.getDefault().getPath(javaLibPath, templateFileName);
410 if (!Files.isReadable(templateFile)) {
411 Main.warn("extended font config - unable to find font config template file {0}", templateFile.toString());
412 return;
413 }
414 try (FileInputStream fis = new FileInputStream(templateFile.toFile())) {
415 Properties props = new Properties();
416 props.load(fis);
417 byte[] content = Files.readAllBytes(templateFile);
418 File cachePath = Main.pref.getCacheDirectory();
419 Path fontconfigFile = cachePath.toPath().resolve("fontconfig.properties");
420 OutputStream os = Files.newOutputStream(fontconfigFile);
421 os.write(content);
422 try (Writer w = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
423 Collection<FontEntry> extrasPref = Main.pref.getListOfStructs(
424 "font.extended-unicode.extra-items", getAdditionalFonts(), FontEntry.class);
425 Collection<FontEntry> extras = new ArrayList<>();
426 w.append("\n\n# Added by JOSM to extend unicode coverage of Java font support:\n\n");
427 List<String> allCharSubsets = new ArrayList<>();
428 for (FontEntry entry: extrasPref) {
429 Collection<String> fontsAvail = getInstalledFonts();
430 if (fontsAvail != null && fontsAvail.contains(entry.file.toUpperCase(Locale.ENGLISH))) {
431 if (!allCharSubsets.contains(entry.charset)) {
432 allCharSubsets.add(entry.charset);
433 extras.add(entry);
434 } else {
435 Main.trace("extended font config - already registered font for charset ''{0}'' - skipping ''{1}''",
436 entry.charset, entry.name);
437 }
438 } else {
439 Main.trace("extended font config - Font ''{0}'' not found on system - skipping", entry.name);
440 }
441 }
442 for (FontEntry entry: extras) {
443 allCharSubsets.add(entry.charset);
444 if ("".equals(entry.name)) {
445 continue;
446 }
447 String key = "allfonts." + entry.charset;
448 String value = entry.name;
449 String prevValue = props.getProperty(key);
450 if (prevValue != null && !prevValue.equals(value)) {
451 Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
452 }
453 w.append(key + '=' + value + '\n');
454 }
455 w.append('\n');
456 for (FontEntry entry: extras) {
457 if ("".equals(entry.name) || "".equals(entry.file)) {
458 continue;
459 }
460 String key = "filename." + entry.name.replace(' ', '_');
461 String value = entry.file;
462 String prevValue = props.getProperty(key);
463 if (prevValue != null && !prevValue.equals(value)) {
464 Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
465 }
466 w.append(key + '=' + value + '\n');
467 }
468 w.append('\n');
469 String fallback = props.getProperty("sequence.fallback");
470 if (fallback != null) {
471 w.append("sequence.fallback=" + fallback + ',' + Utils.join(",", allCharSubsets) + '\n');
472 } else {
473 w.append("sequence.fallback=" + Utils.join(",", allCharSubsets) + '\n');
474 }
475 }
476 Utils.updateSystemProperty("sun.awt.fontconfig", fontconfigFile.toString());
477 } catch (IOException ex) {
478 Main.error(ex);
479 }
480 }
481
482 /**
483 * Get a list of fonts that are installed on the system.
484 *
485 * Must be done without triggering the Java Font initialization.
486 * (See {@link #extendFontconfig(java.lang.String)}, have to set system
487 * property first, which is then read by sun.awt.FontConfiguration upon initialization.)
488 *
489 * @return list of file names
490 */
491 protected Collection<String> getInstalledFonts() {
492 // Cannot use GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()
493 // because we have to set the system property before Java initializes its fonts.
494 // Use more low-level method to find the installed fonts.
495 List<String> fontsAvail = new ArrayList<>();
496 Path fontPath = FileSystems.getDefault().getPath(System.getenv("SYSTEMROOT"), "Fonts");
497 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fontPath)) {
498 for (Path p : ds) {
499 Path filename = p.getFileName();
500 if (filename != null) {
501 fontsAvail.add(filename.toString().toUpperCase(Locale.ENGLISH));
502 }
503 }
504 fontsAvail.add(""); // for devanagari
505 } catch (IOException ex) {
506 Main.error(ex, false);
507 Main.warn("extended font config - failed to load available Fonts");
508 fontsAvail = null;
509 }
510 return fontsAvail;
511 }
512
513 /**
514 * Get default list of additional fonts to add to the configuration.
515 *
516 * Java will choose thee first font in the list that can render a certain character.
517 *
518 * @return list of FontEntry objects
519 */
520 protected Collection<FontEntry> getAdditionalFonts() {
521 Collection<FontEntry> def = new ArrayList<>(33);
522 def.add(new FontEntry("devanagari", "", "")); // just include in fallback list font already defined in template
523
524 // Windows scripts: https://msdn.microsoft.com/en-us/goglobal/bb688099.aspx
525 // IE default fonts: https://msdn.microsoft.com/en-us/library/ie/dn467844(v=vs.85).aspx
526
527 // Windows 10 and later
528 def.add(new FontEntry("historic", "Segoe UI Historic", "SEGUIHIS.TTF")); // historic charsets
529
530 // Windows 8/8.1 and later
531 def.add(new FontEntry("javanese", "Javanese Text", "JAVATEXT.TTF")); // ISO 639: jv
532 def.add(new FontEntry("leelawadee", "Leelawadee", "LEELAWAD.TTF")); // ISO 639: bug
533 def.add(new FontEntry("myanmar", "Myanmar Text", "MMRTEXT.TTF")); // ISO 639: my
534 def.add(new FontEntry("nirmala", "Nirmala UI", "NIRMALA.TTF")); // ISO 639: sat,srb
535 def.add(new FontEntry("segoeui", "Segoe UI", "SEGOEUI.TTF")); // ISO 639: lis
536
537 // Windows 7 and later
538 def.add(new FontEntry("nko_tifinagh_vai_osmanya", "Ebrima", "EBRIMA.TTF")); // ISO 639: ber. Nko only since Win 8
539 def.add(new FontEntry("khmer1", "Khmer UI", "KHMERUI.TTF")); // ISO 639: km
540 def.add(new FontEntry("lao1", "Lao UI", "LAOUI.TTF")); // ISO 639: lo
541 def.add(new FontEntry("tai_le", "Microsoft Tai Le", "TAILE.TTF")); // ISO 639: khb
542 def.add(new FontEntry("new_tai_lue", "Microsoft New Tai Lue", "NTHAILU.TTF")); // ISO 639: khb
543
544 // Windows Vista and later:
545 def.add(new FontEntry("ethiopic", "Nyala", "NYALA.TTF")); // ISO 639: am,gez,ti
546 def.add(new FontEntry("tibetan", "Microsoft Himalaya", "HIMALAYA.TTF")); // ISO 639: bo,dz
547 def.add(new FontEntry("cherokee", "Plantagenet Cherokee", "PLANTC.TTF")); // ISO 639: chr
548 def.add(new FontEntry("unified_canadian", "Euphemia", "EUPHEMIA.TTF")); // ISO 639: cr,in
549 def.add(new FontEntry("khmer2", "DaunPenh", "DAUNPENH.TTF")); // ISO 639: km
550 def.add(new FontEntry("khmer3", "MoolBoran", "MOOLBOR.TTF")); // ISO 639: km
551 def.add(new FontEntry("lao_thai", "DokChampa", "DOKCHAMP.TTF")); // ISO 639: lo
552 def.add(new FontEntry("mongolian", "Mongolian Baiti", "MONBAITI.TTF")); // ISO 639: mn
553 def.add(new FontEntry("oriya", "Kalinga", "KALINGA.TTF")); // ISO 639: or
554 def.add(new FontEntry("sinhala", "Iskoola Pota", "ISKPOTA.TTF")); // ISO 639: si
555 def.add(new FontEntry("yi", "Yi Baiti", "MSYI.TTF")); // ISO 639: ii
556
557 // Windows XP and later
558 def.add(new FontEntry("gujarati", "Shruti", "SHRUTI.TTF"));
559 def.add(new FontEntry("kannada", "Tunga", "TUNGA.TTF"));
560 def.add(new FontEntry("gurmukhi", "Raavi", "RAAVI.TTF"));
561 def.add(new FontEntry("telugu", "Gautami", "GAUTAMI.TTF"));
562 def.add(new FontEntry("bengali", "Vrinda", "VRINDA.TTF")); // since XP SP2
563 def.add(new FontEntry("syriac", "Estrangelo Edessa", "ESTRE.TTF")); // ISO 639: arc
564 def.add(new FontEntry("thaana", "MV Boli", "MVBOLI.TTF")); // ISO 639: dv
565 def.add(new FontEntry("malayalam", "Kartika", "KARTIKA.TTF")); // ISO 639: ml; since XP SP2
566
567 // Windows 2000 and later
568 def.add(new FontEntry("tamil", "Latha", "LATHA.TTF"));
569
570 // Comes with MS Office & Outlook 2000. Good unicode coverage, so add if available.
571 def.add(new FontEntry("arialuni", "Arial Unicode MS", "ARIALUNI.TTF"));
572
573 return def;
574 }
575
576 @Override
577 public List<File> getDefaultProj4NadshiftDirectories() {
578 return Arrays.asList(new File("C:\\PROJ\\NAD"));
579 }
580}
Note: See TracBrowser for help on using the repository browser.