1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail;
20
21 import davmail.ui.tray.DavGatewayTray;
22 import org.apache.log4j.ConsoleAppender;
23 import org.apache.log4j.FileAppender;
24 import org.apache.log4j.Level;
25 import org.apache.log4j.Logger;
26 import org.apache.log4j.PatternLayout;
27 import org.apache.log4j.RollingFileAppender;
28
29 import java.io.BufferedReader;
30 import java.io.BufferedWriter;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.InputStreamReader;
37 import java.io.OutputStreamWriter;
38 import java.nio.charset.StandardCharsets;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.nio.file.attribute.FileAttribute;
43 import java.nio.file.attribute.PosixFilePermissions;
44 import java.util.ArrayList;
45 import java.util.Enumeration;
46 import java.util.Iterator;
47 import java.util.Map;
48 import java.util.Properties;
49 import java.util.TreeSet;
50
51 import static org.apache.http.util.TextUtils.isEmpty;
52
53
54
55
56
57
58 public final class Settings {
59
60 private static final Logger LOGGER = Logger.getLogger(Settings.class);
61
62 public static final String OUTLOOK_URL = "https://outlook.office365.com";
63 public static final String O365_URL = OUTLOOK_URL + "/EWS/Exchange.asmx";
64
65 public static final String GRAPH_URL = "https://graph.microsoft.com";
66
67 public static final String O365_LOGIN_URL = "https://login.microsoftonline.com";
68
69
70 public static final String O365_EWS = "O365EWS";
71 public static final String O365_GRAPH = "O365Graph";
72 public static final String EXCHANGE_EWS = "ExchangeEWS";
73 public static final String EXCHANGE_WEBDAV = "ExchangeWebDav";
74
75
76 public static final String O365_INTERACTIVE = "O365Interactive";
77 public static final String O365_MANUAL = "O365Manual";
78 public static final String O365_DEVICECODE = "O365DeviceCode";
79 public static final String O365_TRANSPARENT = "O365Transparent";
80
81
82 public static final String O365_MODERN = "O365Modern";
83 public static final String O365 = "O365";
84 public static final String WEBDAV = "WebDav";
85 public static final String EWS = "EWS";
86 public static final String AUTO = "Auto";
87
88 public static final String EDGE_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.49";
89
90 private Settings() {
91 }
92
93 private static final Properties SETTINGS_PROPERTIES = new Properties() {
94 @Override
95 public synchronized Enumeration<Object> keys() {
96 Enumeration<Object> keysEnumeration = super.keys();
97 TreeSet<String> sortedKeySet = new TreeSet<>();
98 while (keysEnumeration.hasMoreElements()) {
99 sortedKeySet.add((String) keysEnumeration.nextElement());
100 }
101 final Iterator<String> sortedKeysIterator = sortedKeySet.iterator();
102 return new Enumeration<Object>() {
103
104 public boolean hasMoreElements() {
105 return sortedKeysIterator.hasNext();
106 }
107
108 public Object nextElement() {
109 return sortedKeysIterator.next();
110 }
111 };
112 }
113
114 };
115 private static String configFilePath;
116 private static boolean isFirstStart;
117
118
119
120
121
122
123 public static synchronized void setConfigFilePath(String path) {
124 configFilePath = path;
125 }
126
127
128
129
130
131
132 public static synchronized boolean isFirstStart() {
133 return isFirstStart;
134 }
135
136
137
138
139
140
141
142 public static synchronized void load(InputStream inputStream) throws IOException {
143 SETTINGS_PROPERTIES.load(inputStream);
144 updateLoggingConfig();
145 }
146
147
148
149
150 public static synchronized void load() {
151 try {
152 if (configFilePath == null) {
153
154 configFilePath = System.getProperty("user.home") + "/.davmail.properties";
155 if (!new File(configFilePath).exists()) {
156
157 configFilePath = getXDGConfigFilePath();
158 }
159 }
160 File configFile = new File(configFilePath);
161 if (configFile.exists()) {
162 try (FileInputStream fileInputStream = new FileInputStream(configFile)) {
163 load(fileInputStream);
164 }
165 } else {
166 isFirstStart = true;
167
168
169 setDefaultSettings();
170 save();
171 }
172 } catch (IOException e) {
173 DavGatewayTray.error(new BundleMessage("LOG_UNABLE_TO_LOAD_SETTINGS"), e);
174 }
175 updateLoggingConfig();
176 }
177
178
179
180
181
182
183 private static String getXDGConfigFilePath() {
184 String defaultConfigPath = System.getProperty("user.home")+".davmail.properties";
185 String xdgConfigDirectory = System.getenv("XDG_CONFIG_HOME");
186 if (xdgConfigDirectory == null) {
187 xdgConfigDirectory = System.getProperty("user.home")+"/.config";
188 }
189 File xdgConfigDirectoryFile = new File(xdgConfigDirectory);
190 if (!xdgConfigDirectoryFile.exists()) {
191 if (!xdgConfigDirectoryFile.mkdirs()) {
192 return defaultConfigPath;
193 }
194 }
195 File xdgConfigDavMailDirectoryFile = new File(xdgConfigDirectory+"/davmail");
196 if (!xdgConfigDavMailDirectoryFile.exists()) {
197 if (!xdgConfigDavMailDirectoryFile.mkdirs()) {
198 return defaultConfigPath;
199 }
200 }
201 return xdgConfigDirectory+"/davmail/davmail.properties";
202 }
203
204
205
206
207
208 public static void setDefaultSettings() {
209 SETTINGS_PROPERTIES.put("davmail.mode", O365_EWS);
210 SETTINGS_PROPERTIES.put("davmail.authentication", O365_INTERACTIVE);
211 SETTINGS_PROPERTIES.put("davmail.url", getO365Url());
212 SETTINGS_PROPERTIES.put("davmail.popPort", "1110");
213 SETTINGS_PROPERTIES.put("davmail.imapPort", "1143");
214 SETTINGS_PROPERTIES.put("davmail.smtpPort", "1025");
215 SETTINGS_PROPERTIES.put("davmail.caldavPort", "1080");
216 SETTINGS_PROPERTIES.put("davmail.ldapPort", "1389");
217 SETTINGS_PROPERTIES.put("davmail.clientSoTimeout", "");
218 SETTINGS_PROPERTIES.put("davmail.keepDelay", "30");
219 SETTINGS_PROPERTIES.put("davmail.sentKeepDelay", "0");
220 SETTINGS_PROPERTIES.put("davmail.caldavPastDelay", "0");
221 SETTINGS_PROPERTIES.put("davmail.caldavAutoSchedule", Boolean.TRUE.toString());
222 SETTINGS_PROPERTIES.put("davmail.imapIdleDelay", "");
223 SETTINGS_PROPERTIES.put("davmail.folderSizeLimit", "");
224 SETTINGS_PROPERTIES.put("davmail.enableKeepAlive", Boolean.FALSE.toString());
225 SETTINGS_PROPERTIES.put("davmail.allowRemote", Boolean.FALSE.toString());
226 SETTINGS_PROPERTIES.put("davmail.bindAddress", "");
227 SETTINGS_PROPERTIES.put("davmail.useSystemProxies", Boolean.FALSE.toString());
228 SETTINGS_PROPERTIES.put("davmail.enableProxy", Boolean.FALSE.toString());
229 SETTINGS_PROPERTIES.put("davmail.enableKerberos", "false");
230 SETTINGS_PROPERTIES.put("davmail.disableUpdateCheck", "false");
231 SETTINGS_PROPERTIES.put("davmail.proxyHost", "");
232 SETTINGS_PROPERTIES.put("davmail.proxyPort", "");
233 SETTINGS_PROPERTIES.put("davmail.proxyUser", "");
234 SETTINGS_PROPERTIES.put("davmail.proxyPassword", "");
235 SETTINGS_PROPERTIES.put("davmail.noProxyFor", "");
236 SETTINGS_PROPERTIES.put("davmail.server", Boolean.FALSE.toString());
237 SETTINGS_PROPERTIES.put("davmail.server.certificate.hash", "");
238 SETTINGS_PROPERTIES.put("davmail.caldavAlarmSound", "");
239 SETTINGS_PROPERTIES.put("davmail.carddavReadPhoto", Boolean.TRUE.toString());
240 SETTINGS_PROPERTIES.put("davmail.forceActiveSyncUpdate", Boolean.FALSE.toString());
241 if (isLinux()) {
242 SETTINGS_PROPERTIES.put("davmail.enableTray", Boolean.FALSE.toString());
243 } else {
244 SETTINGS_PROPERTIES.put("davmail.enableTray", Boolean.TRUE.toString());
245 }
246 SETTINGS_PROPERTIES.put("davmail.showStartupBanner", Boolean.TRUE.toString());
247 SETTINGS_PROPERTIES.put("davmail.disableGuiNotifications", Boolean.FALSE.toString());
248 SETTINGS_PROPERTIES.put("davmail.disableTrayActivitySwitch", Boolean.FALSE.toString());
249 SETTINGS_PROPERTIES.put("davmail.imapAutoExpunge", Boolean.TRUE.toString());
250 SETTINGS_PROPERTIES.put("davmail.imapAlwaysApproxMsgSize", Boolean.FALSE.toString());
251 SETTINGS_PROPERTIES.put("davmail.popMarkReadOnRetr", Boolean.FALSE.toString());
252 SETTINGS_PROPERTIES.put("davmail.smtpSaveInSent", Boolean.TRUE.toString());
253 SETTINGS_PROPERTIES.put("davmail.ssl.keystoreType", "");
254 SETTINGS_PROPERTIES.put("davmail.ssl.keystoreFile", "");
255 SETTINGS_PROPERTIES.put("davmail.ssl.keystorePass", "");
256 SETTINGS_PROPERTIES.put("davmail.ssl.keyPass", "");
257 if (isWindows()) {
258
259 SETTINGS_PROPERTIES.put("davmail.ssl.clientKeystoreType", "MSCAPI");
260 } else {
261 SETTINGS_PROPERTIES.put("davmail.ssl.clientKeystoreType", "");
262 }
263 SETTINGS_PROPERTIES.put("davmail.ssl.clientKeystoreFile", "");
264 SETTINGS_PROPERTIES.put("davmail.ssl.clientKeystorePass", "");
265 SETTINGS_PROPERTIES.put("davmail.ssl.pkcs11Library", "");
266 SETTINGS_PROPERTIES.put("davmail.ssl.pkcs11Config", "");
267 SETTINGS_PROPERTIES.put("davmail.ssl.nosecurepop", Boolean.FALSE.toString());
268 SETTINGS_PROPERTIES.put("davmail.ssl.nosecureimap", Boolean.FALSE.toString());
269 SETTINGS_PROPERTIES.put("davmail.ssl.nosecuresmtp", Boolean.FALSE.toString());
270 SETTINGS_PROPERTIES.put("davmail.ssl.nosecurecaldav", Boolean.FALSE.toString());
271 SETTINGS_PROPERTIES.put("davmail.ssl.nosecureldap", Boolean.FALSE.toString());
272
273
274 SETTINGS_PROPERTIES.put("log4j.rootLogger", Level.WARN.toString());
275 SETTINGS_PROPERTIES.put("log4j.logger.davmail", Level.DEBUG.toString());
276 SETTINGS_PROPERTIES.put("log4j.logger.httpclient.wire", Level.WARN.toString());
277 SETTINGS_PROPERTIES.put("log4j.logger.httpclient", Level.WARN.toString());
278 String logFilePath = "";
279 if (isFlatpak()) {
280 logFilePath = System.getenv("XDG_DATA_HOME")+"/davmail.log";
281 }
282 SETTINGS_PROPERTIES.put("davmail.logFilePath", logFilePath);
283 }
284
285
286
287
288
289
290 public static String getLogFilePath() {
291 String logFilePath = Settings.getProperty("davmail.logFilePath");
292
293 if ((logFilePath == null || logFilePath.isEmpty())) {
294 if (Settings.getBooleanProperty("davmail.server")) {
295 logFilePath = "davmail.log";
296 } else if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) {
297
298 logFilePath = System.getProperty("user.home") + "/Library/Logs/DavMail/davmail.log";
299 } else {
300
301 logFilePath = System.getProperty("user.home") + "/davmail.log";
302 }
303 } else {
304 File logFile = new File(logFilePath);
305 if (logFile.isDirectory()) {
306 logFilePath += "/davmail.log";
307 }
308 }
309 return logFilePath;
310 }
311
312
313
314
315
316
317 public static String getLogFileDirectory() {
318 String logFilePath = getLogFilePath();
319 if (logFilePath == null || logFilePath.isEmpty()) {
320 return ".";
321 }
322 int lastSlashIndex = logFilePath.lastIndexOf('/');
323 if (lastSlashIndex == -1) {
324 lastSlashIndex = logFilePath.lastIndexOf('\\');
325 }
326 if (lastSlashIndex >= 0) {
327 return logFilePath.substring(0, lastSlashIndex);
328 } else {
329 return ".";
330 }
331 }
332
333
334
335
336 public static void updateLoggingConfig() {
337 String logFilePath = getLogFilePath();
338
339 try {
340 if (!isDocker()) {
341 if (logFilePath != null && !logFilePath.isEmpty()) {
342 File logFile = new File(logFilePath);
343
344 File logFileDir = logFile.getParentFile();
345 if (logFileDir != null && !logFileDir.exists() && (!logFileDir.mkdirs())) {
346 DavGatewayTray.error(new BundleMessage("LOG_UNABLE_TO_CREATE_LOG_FILE_DIR"));
347 throw new IOException();
348
349 }
350 } else {
351 logFilePath = "davmail.log";
352 }
353
354 synchronized (Logger.getRootLogger()) {
355
356 FileAppender fileAppender = (FileAppender) Logger.getRootLogger().getAppender("FileAppender");
357 if (fileAppender == null) {
358 String logFileSize = Settings.getProperty("davmail.logFileSize");
359 if (logFileSize == null || logFileSize.isEmpty()) {
360 logFileSize = "1MB";
361 }
362
363 if ("0".equals(logFileSize)) {
364 fileAppender = new FileAppender();
365 } else {
366 fileAppender = new RollingFileAppender();
367 ((RollingFileAppender) fileAppender).setMaxBackupIndex(2);
368 ((RollingFileAppender) fileAppender).setMaxFileSize(logFileSize);
369 }
370 fileAppender.setName("FileAppender");
371 fileAppender.setEncoding("UTF-8");
372 fileAppender.setLayout(new PatternLayout("%d{ISO8601} %-5p [%t] %c %x - %m%n"));
373 }
374 fileAppender.setFile(logFilePath, true, false, 8192);
375 Logger.getRootLogger().addAppender(fileAppender);
376
377 if (Settings.getProperty("davmail.logConnectionFilePath", null) != null) {
378 FileAppender connectionFileAppender = (FileAppender) Logger.getLogger("davmail.connection").getAppender("ConnectionAppender");
379 if (connectionFileAppender == null) {
380 connectionFileAppender = new RollingFileAppender();
381 ((RollingFileAppender) connectionFileAppender).setMaxBackupIndex(0);
382 ((RollingFileAppender) connectionFileAppender).setMaxFileSize("10MB");
383
384 connectionFileAppender.setName("ConnectionAppender");
385 connectionFileAppender.setEncoding("UTF-8");
386 connectionFileAppender.setLayout(new PatternLayout("%d{ISO8601} %-5p [%t] %c %x - %m%n"));
387 }
388 connectionFileAppender.setFile(Settings.getProperty("davmail.logConnectionFilePath", null), true, false, 8192);
389
390 Logger.getLogger("davmail.connection").addAppender(connectionFileAppender);
391 }
392 }
393 }
394
395
396 ConsoleAppender consoleAppender = (ConsoleAppender) Logger.getRootLogger().getAppender("ConsoleAppender");
397 if (consoleAppender != null) {
398 consoleAppender.setThreshold(Level.ALL);
399 }
400
401 } catch (IOException e) {
402 DavGatewayTray.error(new BundleMessage("LOG_UNABLE_TO_SET_LOG_FILE_PATH"));
403 }
404
405
406 Settings.setLoggingLevel("rootLogger", Settings.getLoggingLevel("rootLogger"));
407 Settings.setLoggingLevel("davmail", Settings.getLoggingLevel("davmail"));
408
409 Settings.setLoggingLevel("org.apache.http.wire", Settings.getLoggingLevel("httpclient.wire"));
410 Settings.setLoggingLevel("org.apache.http.conn.ssl", Settings.getLoggingLevel("httpclient.wire"));
411 Settings.setLoggingLevel("org.apache.http", Settings.getLoggingLevel("httpclient"));
412 }
413
414
415
416
417 public static synchronized void save() {
418
419 if (configFilePath != null) {
420
421 Properties properties = new Properties();
422 properties.putAll(SETTINGS_PROPERTIES);
423
424 ArrayList<String> lines = new ArrayList<>();
425
426
427 createPrivateFile(configFilePath);
428
429 readLines(lines, properties);
430
431 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.ISO_8859_1))) {
432 for (String value : lines) {
433 writer.write(value);
434 writer.newLine();
435 }
436
437
438 Enumeration<?> propertyEnumeration = properties.propertyNames();
439 while (propertyEnumeration.hasMoreElements()) {
440 String propertyName = (String) propertyEnumeration.nextElement();
441 writer.write(propertyName + "=" + escapeValue(properties.getProperty(propertyName)));
442 writer.newLine();
443 }
444 } catch (IOException e) {
445 DavGatewayTray.error(new BundleMessage("LOG_UNABLE_TO_STORE_SETTINGS"), e);
446 }
447 }
448 updateLoggingConfig();
449 }
450
451 private static void createPrivateFile(String filePath) {
452 Path path = Paths.get(filePath);
453 if (!Files.exists(path)) {
454 try {
455 if (isUnix() || isOSX()) {
456 FileAttribute<?> permissions = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------"));
457 Files.createFile(path, permissions);
458 } else {
459 Files.createFile(path);
460 }
461 LOGGER.info("Created file " + filePath);
462 } catch (IOException e) {
463 LOGGER.error(e.getMessage());
464 }
465 }
466 }
467
468 private static void readLines(ArrayList<String> lines, Properties properties) {
469 try {
470 File configFile = new File(configFilePath);
471 if (configFile.exists()) {
472 try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(configFile.toPath()), StandardCharsets.ISO_8859_1))) {
473 String line;
474 while ((line = reader.readLine()) != null) {
475 lines.add(convertLine(line, properties));
476 }
477 }
478 }
479 } catch (IOException e) {
480 DavGatewayTray.error(new BundleMessage("LOG_UNABLE_TO_LOAD_SETTINGS"), e);
481 }
482 }
483
484
485
486
487
488
489
490
491
492 private static String convertLine(String line, Properties properties) {
493 int hashIndex = line.indexOf('#');
494 int equalsIndex = line.indexOf('=');
495
496
497 if (equalsIndex >= 0 && (hashIndex < 0 || hashIndex >= equalsIndex)) {
498 String key = line.substring(0, equalsIndex);
499 String value = properties.getProperty(key);
500 if (value != null) {
501
502 line = key + "=" + escapeValue(value);
503
504 properties.remove(key);
505 }
506 }
507 return line;
508 }
509
510
511
512
513
514
515
516 private static String escapeValue(String value) {
517 StringBuilder buffer = new StringBuilder();
518 for (char c : value.toCharArray()) {
519 if (c == '\\') {
520 buffer.append('\\');
521 }
522 buffer.append(c);
523 }
524 return buffer.toString();
525 }
526
527
528
529
530
531
532
533
534 public static synchronized String getProperty(String property) {
535 String value = SETTINGS_PROPERTIES.getProperty(property);
536
537 if (value != null && value.isEmpty()) {
538 value = null;
539 }
540 return value;
541 }
542
543
544
545
546
547
548
549
550 public static synchronized String getProperty(String property, String defaultValue) {
551 String value = getProperty(property);
552 if (value == null) {
553 value = defaultValue;
554 }
555 return value;
556 }
557
558
559
560
561
562
563
564
565 public static synchronized char[] getCharArrayProperty(String property) {
566 String propertyValue = Settings.getProperty(property);
567 char[] value = null;
568 if (propertyValue != null) {
569 value = propertyValue.toCharArray();
570 }
571 return value;
572 }
573
574
575
576
577
578
579
580 public static synchronized void setProperty(String property, String value) {
581 if (value != null) {
582 SETTINGS_PROPERTIES.setProperty(property, value);
583 } else {
584 SETTINGS_PROPERTIES.setProperty(property, "");
585 }
586 }
587
588
589
590
591
592
593
594 public static synchronized int getIntProperty(String property) {
595 return getIntProperty(property, 0);
596 }
597
598
599
600
601
602
603
604
605 public static synchronized int getIntProperty(String property, int defaultValue) {
606 int value = defaultValue;
607 try {
608 String propertyValue = SETTINGS_PROPERTIES.getProperty(property);
609 if (propertyValue != null && !propertyValue.isEmpty()) {
610 value = Integer.parseInt(propertyValue);
611 }
612 } catch (NumberFormatException e) {
613 DavGatewayTray.error(new BundleMessage("LOG_INVALID_SETTING_VALUE", property), e);
614 }
615 return value;
616 }
617
618
619
620
621
622
623
624 public static synchronized boolean getBooleanProperty(String property) {
625 String propertyValue = SETTINGS_PROPERTIES.getProperty(property);
626 return Boolean.parseBoolean(propertyValue);
627 }
628
629
630
631
632
633
634
635
636 public static synchronized boolean getBooleanProperty(String property, boolean defaultValue) {
637 boolean value = defaultValue;
638 String propertyValue = SETTINGS_PROPERTIES.getProperty(property);
639 if (propertyValue != null && !propertyValue.isEmpty()) {
640 value = Boolean.parseBoolean(propertyValue);
641 }
642 return value;
643 }
644
645 public static synchronized String loadRefreshToken(String username) {
646 String tokenFilePath = Settings.getProperty("davmail.oauth.tokenFilePath");
647 if (isEmpty(tokenFilePath)) {
648 return Settings.getProperty("davmail.oauth." + username.toLowerCase() + ".refreshToken");
649 } else {
650 return loadTokenFromFile(tokenFilePath, username.toLowerCase());
651 }
652 }
653
654
655 public static synchronized void storeRefreshToken(String username, String refreshToken) {
656 String tokenFilePath = Settings.getProperty("davmail.oauth.tokenFilePath");
657 if (isEmpty(tokenFilePath)) {
658 Settings.setProperty("davmail.oauth." + username.toLowerCase() + ".refreshToken", refreshToken);
659 Settings.save();
660 } else {
661 saveTokenToFile(tokenFilePath, username.toLowerCase(), refreshToken);
662 }
663 }
664
665
666
667
668
669
670
671
672 private static void saveTokenToFile(String tokenFilePath, String username, String refreshToken) {
673 try {
674 checkCreateTokenFilePath(tokenFilePath);
675 Properties properties = new Properties();
676 try (FileInputStream fis = new FileInputStream(tokenFilePath)) {
677 properties.load(fis);
678 }
679 properties.setProperty(username, refreshToken);
680 try (FileOutputStream fos = new FileOutputStream(tokenFilePath)) {
681 properties.store(fos, "Oauth tokens");
682 }
683 } catch (IOException e) {
684 Logger.getLogger(Settings.class).warn(e + " " + e.getMessage());
685 }
686 }
687
688
689
690
691
692
693
694
695 private static String loadTokenFromFile(String tokenFilePath, String username) {
696 try {
697 checkCreateTokenFilePath(tokenFilePath);
698 Properties properties = new Properties();
699 try (FileInputStream fis = new FileInputStream(tokenFilePath)) {
700 properties.load(fis);
701 }
702 return properties.getProperty(username);
703 } catch (IOException e) {
704 Logger.getLogger(Settings.class).warn(e + " " + e.getMessage());
705 }
706 return null;
707 }
708
709 private static void checkCreateTokenFilePath(String tokenFilePath) throws IOException {
710 File file = new File(tokenFilePath);
711 File parentFile = file.getParentFile();
712 if (parentFile != null && (parentFile.mkdirs())) {
713 LOGGER.info("Created token file directory " + parentFile.getAbsolutePath());
714 }
715 createPrivateFile(tokenFilePath);
716 }
717
718
719
720
721
722
723
724 private static String getLoggingPrefix(String category) {
725 String prefix;
726 if ("rootLogger".equals(category)) {
727 prefix = "log4j.";
728 } else {
729 prefix = "log4j.logger.";
730 }
731 return prefix;
732 }
733
734
735
736
737
738
739
740 public static synchronized Level getLoggingLevel(String category) {
741 String prefix = getLoggingPrefix(category);
742 String currentValue = SETTINGS_PROPERTIES.getProperty(prefix + category);
743
744 if (currentValue != null && !currentValue.isEmpty()) {
745 return Level.toLevel(currentValue);
746 } else if ("rootLogger".equals(category)) {
747 return Logger.getRootLogger().getLevel();
748 } else {
749 return Logger.getLogger(category).getLevel();
750 }
751 }
752
753
754
755
756
757
758
759 public static synchronized Properties getSubProperties(String scope) {
760 final String keyStart;
761 if (scope == null || scope.isEmpty()) {
762 keyStart = "";
763 } else if (scope.endsWith(".")) {
764 keyStart = scope;
765 } else {
766 keyStart = scope + '.';
767 }
768 Properties result = new Properties();
769 for (Map.Entry<Object, Object> entry : SETTINGS_PROPERTIES.entrySet()) {
770 String key = (String) entry.getKey();
771 if (key.startsWith(keyStart)) {
772 String value = (String) entry.getValue();
773 result.setProperty(key.substring(keyStart.length()), value);
774 }
775 }
776 return result;
777 }
778
779
780
781
782
783
784
785 public static synchronized void setLoggingLevel(String category, Level level) {
786 if (level != null) {
787 String prefix = getLoggingPrefix(category);
788 SETTINGS_PROPERTIES.setProperty(prefix + category, level.toString());
789 if ("rootLogger".equals(category)) {
790 Logger.getRootLogger().setLevel(level);
791 } else {
792 Logger.getLogger(category).setLevel(level);
793 }
794 }
795 }
796
797
798
799
800
801
802
803 public static synchronized void saveProperty(String property, String value) {
804 Settings.load();
805 Settings.setProperty(property, value);
806 Settings.save();
807 }
808
809
810
811
812
813
814 public static boolean isWindows() {
815 return System.getProperty("os.name").toLowerCase().startsWith("windows");
816 }
817
818
819
820
821
822
823 public static boolean isOSX() {
824 return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
825 }
826
827
828
829
830
831
832 public static boolean isLinux() {
833 return System.getProperty("os.name").toLowerCase().startsWith("linux");
834 }
835
836 public static boolean isUnix() {
837 return isLinux() ||
838 System.getProperty("os.name").toLowerCase().startsWith("freebsd");
839 }
840
841 public static String getUserAgent() {
842 return getProperty("davmail.userAgent", Settings.EDGE_USER_AGENT);
843 }
844
845 public static String getOutlookUrl() {
846 String tld = getProperty("davmail.tld");
847 String outlookUrl = getProperty("davmail.outlookUrl");
848 if (outlookUrl != null) {
849 return outlookUrl;
850 } else if (tld == null) {
851 return OUTLOOK_URL;
852 } else {
853 return "https://outlook.office365." + tld;
854 }
855 }
856
857 public static String getO365Url() {
858 String tld = getProperty("davmail.tld");
859 String outlookUrl = getProperty("davmail.outlookUrl");
860 if (outlookUrl != null) {
861 return outlookUrl + "/EWS/Exchange.asmx";
862 } else if (tld == null) {
863 return O365_URL;
864 } else {
865 return "https://outlook.office365." + tld + "/EWS/Exchange.asmx";
866 }
867 }
868
869
870
871
872
873
874 public static String getGraphUrl() {
875 String tld = getProperty("davmail.tld");
876 String graphUrl = getProperty("davmail.graphUrl");
877 if (graphUrl != null) {
878 return graphUrl;
879 } else if (tld == null) {
880 return GRAPH_URL;
881 } else {
882 return "https://graph.microsoft." + tld;
883 }
884 }
885
886 public static String getO365LoginUrl() {
887 String tld = getProperty("davmail.tld");
888 String loginUrl = getProperty("davmail.loginUrl");
889 if (loginUrl != null) {
890 return loginUrl;
891 } else if (tld == null) {
892 return O365_LOGIN_URL;
893 } else {
894 return "https://login.microsoftonline." + tld;
895 }
896 }
897
898 public static String getOauthScope() {
899 String defaultOauthScope = "openid profile offline_access Mail.ReadWrite Calendars.ReadWrite Calendars.ReadWrite.Shared MailboxSettings.Read Mail.ReadWrite.Shared Contacts.ReadWrite Tasks.ReadWrite Mail.Send People.Read";
900 if (Settings.getProperty("davmail.oauth.redirectUri","").startsWith("urn:")) {
901 defaultOauthScope = "openid profile offline_access";
902 }
903 return Settings.getProperty("davmail.oauth.scope", defaultOauthScope);
904 }
905
906 public static boolean isGraphEnabled() {
907 return Settings.O365_GRAPH.equals(Settings.getProperty("davmail.mode")) || Settings.getBooleanProperty("davmail.enableGraph");
908 }
909
910 public static boolean isSWTAvailable() {
911 boolean isSWTAvailable = false;
912 ClassLoader classloader = Settings.class.getClassLoader();
913 try {
914
915 classloader.loadClass("org.eclipse.swt.SWT");
916 isSWTAvailable = true;
917 } catch (Throwable e) {
918
919 if (!isOSX()) {
920 LOGGER.info(new BundleMessage("LOG_SWT_NOT_AVAILABLE"));
921 }
922 }
923 return isSWTAvailable;
924 }
925
926 public static boolean isJFXAvailable() {
927 boolean isJFXAvailable = false;
928 try {
929 Class.forName("javafx.application.Platform");
930 isJFXAvailable = true;
931 } catch (ClassNotFoundException | NullPointerException e) {
932 LOGGER.info("JavaFX (OpenJFX) not available");
933 }
934 return isJFXAvailable;
935 }
936
937 public static boolean isDocker() {
938 boolean isDocker = new File("/.dockerenv").exists();
939 boolean isPodman = new File("/run/.containerenv").exists();
940 if (isDocker) {
941 LOGGER.info("Running in docker or podman");
942 }
943 return isDocker || isPodman;
944 }
945
946 public static boolean isFlatpak() {
947 boolean isFlatpak = "flatpak".equals(System.getenv("container"));
948 if (isFlatpak) {
949 LOGGER.info("Running in Flatpak");
950 }
951 return isFlatpak;
952 }
953
954
955
956
957
958 public static synchronized String getConfigFilePath() {
959 if (configFilePath != null) {
960 return configFilePath;
961 } else if (isFlatpak()) {
962 return System.getenv("XDG_CONFIG_HOME")+"/davmail.properties";
963 } else {
964
965 return System.getenv("DAVMAIL_PROPERTIES");
966 }
967 }
968 }