diff --git a/src/qz/App.java b/src/qz/App.java index 376833b65..a5853b314 100644 --- a/src/qz/App.java +++ b/src/qz/App.java @@ -88,13 +88,12 @@ private static void setupFileLogging() { System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog"); System.setProperty("org.eclipse.jetty.LEVEL", "OFF"); - Properties app = CertificateManager.loadProperties(); - if(PrefsSearch.get(app, Constants.PREFS_LOG_DISABLE, false)) { + if(PrefsSearch.getBoolean(ArgValue.LOG_DISABLE)) { return; } - int logSize = PrefsSearch.get(app, Constants.PREFS_LOG_SIZE, Constants.DEFAULT_LOG_SIZE); - int logRotate = PrefsSearch.get(app, Constants.PREFS_LOG_ROTATE, Constants.DEFAULT_LOG_ROTATIONS); + int logSize = PrefsSearch.getInt(ArgValue.LOG_SIZE); + int logRotate = PrefsSearch.getInt(ArgValue.LOG_ROTATE); RollingFileAppender fileAppender = RollingFileAppender.newBuilder() .setName("log-file") .withAppend(true) diff --git a/src/qz/auth/Certificate.java b/src/qz/auth/Certificate.java index e91d7b3f5..69106333f 100644 --- a/src/qz/auth/Certificate.java +++ b/src/qz/auth/Certificate.java @@ -13,9 +13,7 @@ import org.apache.logging.log4j.Logger; import qz.App; import qz.common.Constants; -import qz.utils.ByteUtilities; -import qz.utils.FileUtilities; -import qz.utils.SystemUtilities; +import qz.utils.*; import java.io.*; import java.nio.file.Files; @@ -139,15 +137,12 @@ public enum Algorithm { public static void scanAdditionalCAs() { ArrayList> certPaths = new ArrayList<>(); - // First, look for "-DtrustedRootCert" command line property - certPaths.addAll(FileUtilities.parseDelimitedPaths(System.getProperty(Constants.PREFS_OVERRIDE_CA_CLI))); + // First, look for "authcert.override", "-DtrustedRootCert" + certPaths.addAll(FileUtilities.parseDelimitedPaths(PrefsSearch.getString(ArgValue.AUTHCERT_OVERRIDE, App.getTrayProperties()))); // Second, look for "override.crt" within App directory certPaths.add(new AbstractMap.SimpleEntry<>(SystemUtilities.getJarParentPath().resolve(Constants.OVERRIDE_CERT), QUIETLY_FAIL)); - // Third, look for "authcert.override" property in qz-tray.properties - certPaths.addAll(FileUtilities.parseDelimitedPaths(App.getTrayProperties(), Constants.PREFS_OVERRIDE_CA)); - for(Map.Entry certPath : certPaths) { if(certPath.getKey() != null) { if (certPath.getKey().toFile().exists()) { diff --git a/src/qz/common/Constants.java b/src/qz/common/Constants.java index 38063763e..37d2ce335 100644 --- a/src/qz/common/Constants.java +++ b/src/qz/common/Constants.java @@ -1,6 +1,7 @@ package qz.common; import com.github.zafarkhaja.semver.Version; +import qz.utils.ArgValue; import qz.utils.SystemUtilities; import java.awt.*; @@ -28,8 +29,6 @@ public class Constants { public static final String[] PERSIST_PROPS = {"file.whitelist", "file.allow", "networking.hostname", "networking.port", STEAL_WEBSOCKET_PROPERTY }; public static final String AUTOSTART_FILE = ".autostart"; public static final String DATA_DIR = "qz"; - public static final int DEFAULT_LOG_SIZE = 524288; - public static final int DEFAULT_LOG_ROTATIONS = 5; public static final int BORDER_PADDING = 10; @@ -59,25 +58,6 @@ public class Constants { public static final String PROBE_REQUEST = "getProgramName"; public static final String PROBE_RESPONSE = ABOUT_TITLE; - public static final String PREFS_NOTIFICATIONS = "tray.notifications"; - public static final String PREFS_HEADLESS = "tray.headless"; - public static final String PREFS_MONOCLE = "tray.monocle"; - public static final String PREFS_STRICT_MODE = "tray.strictmode"; - public static final String PREFS_IDLE_PRINTERS = "tray.idle.printers"; - public static final String PREFS_IDLE_JFX = "tray.idle.javafx"; - - public static final String PREFS_FILEIO_ENABLED = "security.file.enabled"; - public static final String PREFS_FILEIO_STRICT = "security.file.strict"; - - public static final String PREFS_LOG_DISABLE = "log.disable"; - public static final String PREFS_LOG_ROTATE = "log.rotate"; - public static final String PREFS_LOG_SIZE = "log.size"; - - public static final String PREFS_OVERRIDE_CA = "authcert.override"; - public static final String PREFS_OVERRIDE_CA_CLI = "trustedRootCert"; - - public static final String PREFS_PRINTER_JOB_DATA = "printer.status.jobdata"; - public static final String ALLOW_SITES_TEXT = "Permanently allowed \"%s\" to access local resources"; public static final String BLOCK_SITES_TEXT = "Permanently blocked \"%s\" from accessing local resources"; diff --git a/src/qz/common/PropertyHelper.java b/src/qz/common/PropertyHelper.java index 8a4b7f964..ad1fe60f6 100644 --- a/src/qz/common/PropertyHelper.java +++ b/src/qz/common/PropertyHelper.java @@ -2,6 +2,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import qz.utils.ArgValue; import java.io.File; import java.io.FileInputStream; @@ -53,8 +54,8 @@ public boolean getBoolean(String key, boolean defaultVal) { } } - public void setProperty(String key, boolean value) { - setProperty(key, "" + value); + public void setProperty(ArgValue arg, boolean value) { + setProperty(arg.getMatch(), "" + value); } public void load(File file) { diff --git a/src/qz/common/TrayManager.java b/src/qz/common/TrayManager.java index dc8bc2ab4..252dc2589 100644 --- a/src/qz/common/TrayManager.java +++ b/src/qz/common/TrayManager.java @@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit; import static qz.ui.component.IconCache.Icon.*; +import static qz.utils.ArgValue.*; /** * Manages the icons and actions associated with the TrayIcon @@ -95,14 +96,14 @@ public TrayManager(boolean isHeadless) { prefs = new PropertyHelper(FileUtilities.USER_DIR + File.separator + Constants.PREFS_FILE + ".properties"); // Set strict certificate mode preference - Certificate.setTrustBuiltIn(!getPref(Constants.PREFS_STRICT_MODE, false)); + Certificate.setTrustBuiltIn(!getPref(TRAY_STRICTMODE)); // Set FileIO security - FileUtilities.setFileIoEnabled(getPref(Constants.PREFS_FILEIO_ENABLED, true)); - FileUtilities.setFileIoStrict(getPref(Constants.PREFS_FILEIO_STRICT, false)); + FileUtilities.setFileIoEnabled(getPref(SECURITY_FILE_ENABLED)); + FileUtilities.setFileIoStrict(getPref(SECURITY_FILE_STRICT)); // Headless if turned on by user or unsupported by environment - headless = isHeadless || getPref(Constants.PREFS_HEADLESS, false) || GraphicsEnvironment.isHeadless(); + headless = isHeadless || getPref(HEADLESS) || GraphicsEnvironment.isHeadless(); if (headless) { log.info("Running in headless mode"); } @@ -207,7 +208,7 @@ public TrayManager(boolean isHeadless) { // Initialize idle actions // Slow to start JavaFX the first time - if (getPref(Constants.PREFS_IDLE_JFX, true)) { + if (getPref(TRAY_IDLE_JAVAFX)) { performIfIdle((int)TimeUnit.SECONDS.toMillis(60), evt -> { log.debug("IDLE: Starting up JFX for HTML printing"); try { @@ -220,7 +221,7 @@ public TrayManager(boolean isHeadless) { } // Slow to find printers the first time if a lot of printers are installed // Must run after JavaFX per https://github.com/qzind/tray/issues/924 - if (getPref(Constants.PREFS_IDLE_PRINTERS, true)) { + if (getPref(TRAY_IDLE_PRINTERS)) { performIfIdle((int)TimeUnit.SECONDS.toMillis(120), evt -> { log.debug("IDLE: Performing first run of find printers"); PrintServiceMatcher.getNativePrinterList(false, true); @@ -279,14 +280,14 @@ private void addMenuItems() { JCheckBoxMenuItem notificationsItem = new JCheckBoxMenuItem("Show all notifications"); notificationsItem.setToolTipText("Shows all connect/disconnect messages, useful for debugging purposes"); notificationsItem.setMnemonic(KeyEvent.VK_S); - notificationsItem.setState(getPref(Constants.PREFS_NOTIFICATIONS, false)); + notificationsItem.setState(getPref(TRAY_NOTIFICATIONS)); notificationsItem.addActionListener(notificationsListener); diagnosticMenu.add(notificationsItem); JCheckBoxMenuItem monocleItem = new JCheckBoxMenuItem("Use Monocle for HTML"); monocleItem.setToolTipText("Use monocle platform for HTML printing (restart required)"); monocleItem.setMnemonic(KeyEvent.VK_U); - monocleItem.setState(getPref(Constants.PREFS_MONOCLE, true)); + monocleItem.setState(getPref(TRAY_MONOCLE)); if(!SystemUtilities.hasMonocle()) { log.warn("Monocle engine was not detected"); monocleItem.setEnabled(false); @@ -378,7 +379,7 @@ private void addMenuItems() { private final ActionListener notificationsListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - prefs.setProperty(Constants.PREFS_NOTIFICATIONS, ((JCheckBoxMenuItem)e.getSource()).getState()); + prefs.setProperty(TRAY_NOTIFICATIONS, ((JCheckBoxMenuItem)e.getSource()).getState()); } }; @@ -386,7 +387,7 @@ public void actionPerformed(ActionEvent e) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem j = (JCheckBoxMenuItem)e.getSource(); - prefs.setProperty(Constants.PREFS_MONOCLE, j.getState()); + prefs.setProperty(TRAY_MONOCLE, j.getState()); displayWarningMessage(String.format("A restart of %s is required to ensure this feature is %sabled.", Constants.ABOUT_TITLE, j.getState()? "en":"dis")); } @@ -470,7 +471,7 @@ public void actionPerformed(ActionEvent e) { private final ActionListener exitListener = new ActionListener() { public void actionPerformed(ActionEvent e) { - boolean showAllNotifications = getPref(Constants.PREFS_NOTIFICATIONS, false); + boolean showAllNotifications = getPref(TRAY_NOTIFICATIONS); if (!showAllNotifications || confirmDialog.prompt("Exit " + name + "?")) { exit(0); } } }; @@ -620,7 +621,7 @@ private void displayMessage(final String caption, final String text, final TrayI if (!headless) { if (tray != null) { SwingUtilities.invokeLater(() -> { - boolean showAllNotifications = getPref(Constants.PREFS_NOTIFICATIONS, false); + boolean showAllNotifications = getPref(TRAY_NOTIFICATIONS); if (showAllNotifications || level != TrayIcon.MessageType.INFO) { tray.displayMessage(caption, text, level); } @@ -640,7 +641,7 @@ public void singleInstanceCheck(java.util.List insecurePorts, Integer i } public boolean isMonoclePreferred() { - return getPref(Constants.PREFS_MONOCLE, true); + return getPref(TRAY_MONOCLE); } public boolean isHeadless() { @@ -650,8 +651,8 @@ public boolean isHeadless() { /** * Get boolean user pref: Searching "user", "app" and System.getProperty(...). */ - private boolean getPref(String name, boolean defaultVal) { - return "true".equalsIgnoreCase(PrefsSearch.get(prefs, App.getTrayProperties(), name, defaultVal + "")); + private boolean getPref(ArgValue argValue) { + return PrefsSearch.getBoolean(argValue, prefs, App.getTrayProperties()); } private void performIfIdle(int idleQualifier, ActionListener performer) { diff --git a/src/qz/printer/status/StatusSession.java b/src/qz/printer/status/StatusSession.java index d7c0b5c1b..8e519d9da 100644 --- a/src/qz/printer/status/StatusSession.java +++ b/src/qz/printer/status/StatusSession.java @@ -60,8 +60,7 @@ public void enableJobDataOnPrinter(String printer, int maxJobData, PrintingUtili if (!SystemUtilities.isWindows()) { throw new UnsupportedOperationException("Job data listeners are only supported on Windows"); } - String spoolFileMonitoring = PrefsSearch.get(App.getTrayProperties(), Constants.PREFS_PRINTER_JOB_DATA, "false", false ); - if (!Boolean.parseBoolean(spoolFileMonitoring)) { + if (!PrefsSearch.getBoolean(ArgValue.PRINTER_STATUS_JOB_DATA, false, App.getTrayProperties())) { throw new UnsupportedOperationException("Job data listeners are currently disabled"); } if (printerSpoolerMap.containsKey(printer)) { diff --git a/src/qz/ui/SiteManagerDialog.java b/src/qz/ui/SiteManagerDialog.java index f60f2fddb..6c3296d40 100644 --- a/src/qz/ui/SiteManagerDialog.java +++ b/src/qz/ui/SiteManagerDialog.java @@ -11,9 +11,7 @@ import qz.installer.certificate.CertificateManager; import qz.installer.certificate.KeyPairWrapper; import qz.ui.component.*; -import qz.utils.FileUtilities; -import qz.utils.ShellUtilities; -import qz.utils.SystemUtilities; +import qz.utils.*; import javax.swing.*; import javax.swing.border.Border; @@ -242,7 +240,7 @@ public void mousePressed(MouseEvent e) { readerThread = new Thread(this); threadRunning = new AtomicBoolean(false); - strictModeCheckBox = new JCheckBox(Constants.STRICT_MODE_LABEL, prefs.getBoolean(Constants.PREFS_STRICT_MODE, false)); + strictModeCheckBox = new JCheckBox(Constants.STRICT_MODE_LABEL, PrefsSearch.getBoolean(ArgValue.SECURITY_FILE_STRICT, prefs)); strictModeCheckBox.setToolTipText(Constants.STRICT_MODE_TOOLTIP); strictModeCheckBox.addActionListener(e -> { if (strictModeCheckBox.isSelected() && !new ConfirmDialog(null, "Please Confirm", iconCache).prompt(Constants.STRICT_MODE_CONFIRM)) { @@ -250,7 +248,7 @@ public void mousePressed(MouseEvent e) { return; } Certificate.setTrustBuiltIn(!strictModeCheckBox.isSelected()); - prefs.setProperty(Constants.PREFS_STRICT_MODE, strictModeCheckBox.isSelected()); + prefs.setProperty(ArgValue.SECURITY_FILE_STRICT, strictModeCheckBox.isSelected()); certTable.refreshComponents(); }); refreshStrictModeCheckbox(); diff --git a/src/qz/utils/ArgParser.java b/src/qz/utils/ArgParser.java index b0b58790f..e4f84a661 100644 --- a/src/qz/utils/ArgParser.java +++ b/src/qz/utils/ArgParser.java @@ -22,6 +22,7 @@ import qz.installer.certificate.CertificateManager; import java.io.File; +import java.lang.reflect.Field; import java.util.*; import java.util.List; @@ -48,6 +49,7 @@ public int getCode() { protected static final Logger log = LogManager.getLogger(ArgParser.class); private static final String USAGE_COMMAND = String.format("java -jar %s.jar", PROPS_FILE); + private static final String USAGE_COMMAND_PARAMETER = String.format("java -Dfoo.bar= -jar %s.jar", PROPS_FILE); private static final int DESCRIPTION_COLUMN = 30; private static final int INDENT_SIZE = 2; @@ -203,7 +205,7 @@ public ExitStatus processInstallerArgs(ArgValue argValue, List args) { throw new UnsupportedOperationException("Installation type " + argValue + " is not yet supported"); } } catch(MissingArgException e) { - log.error("Valid usage:\n {} {}", USAGE_COMMAND, argValue.getUsage()); + log.error("Valid usage:{} {} {}", System.lineSeparator(), USAGE_COMMAND, argValue.getUsage()); return USAGE_ERROR; } catch(Exception e) { log.error("Installation step {} failed", argValue, e); @@ -229,7 +231,7 @@ public ExitStatus processBuildArgs(ArgValue argValue) { throw new UnsupportedOperationException("Build type " + argValue + " is not yet supported"); } } catch(MissingArgException e) { - log.error("Valid usage:\n {} {}", USAGE_COMMAND, argValue.getUsage()); + log.error("Valid usage:{} {} {}", System.lineSeparator(), USAGE_COMMAND, argValue.getUsage()); return USAGE_ERROR; } catch(Exception e) { log.error("Build step {} failed", argValue, e); @@ -265,6 +267,15 @@ public boolean intercept() { // Show generic help for(ArgValue.ArgType argType : ArgValue.ArgType.values()) { System.out.println(String.format("%s%s", System.lineSeparator(), argType)); + switch(argType) { + case PREFERENCES: + System.out.println(String.format(" Preferences can be set via \"%s %s=%s\", command line via \"%s\" or via file using %s.properties" + System.lineSeparator(), + SystemUtilities.isWindows() ? "set" : "export", + "QZ_OPTS", + "-Dfoo.bar=", + USAGE_COMMAND_PARAMETER, + PROPS_FILE)); + } for(ArgValue argValue : ArgValue.filter(argType)) { printHelp(argValue); } @@ -378,11 +389,44 @@ public boolean intercept() { return false; } - private static void printHelp(String[] commands, String description, String usage, int indent) { + private static ArrayList collectPrefs() { + ArrayList opts = new ArrayList<>(); + for(Field f : Constants.class.getDeclaredFields()) { + if(f.getName().startsWith("PREFS_")) { + try { + Object val = f.get(null); + if (val instanceof String) { + opts.add((String)val); + } + } catch(Exception ignore) {} + } + } + return opts; + } + + private static void printHelp(String[] commands, String description, String usage, Object defaultVal, int indent) { String text = String.format("%s%s", StringUtils.leftPad("", indent), StringUtils.join(commands, ", ")); + + // Try to handle overflow + String[] overflow = null; + if((text.length() > 27 + indent) && text.contains(",")) { + String[] split = text.split(","); + text = split[0] + ","; + overflow = Arrays.copyOfRange(split, 1, split.length); + } + if (description != null) { text = StringUtils.rightPad(text, DESCRIPTION_COLUMN) + description; + if(defaultVal != null) { + text += String.format(" [%s]", defaultVal); + } + } + if(overflow != null) { + for(int i = 0; i < overflow.length; i++) { + String ending = (i == overflow.length - 1) ? "" : ","; + text += System.lineSeparator() + StringUtils.leftPad("", indent + INDENT_SIZE) + overflow[i].trim() + ending; + } } System.out.println(text); if (usage != null) { @@ -391,10 +435,10 @@ private static void printHelp(String[] commands, String description, String usag } private static void printHelp(ArgValue argValue) { - printHelp(argValue.getMatches(), argValue.getDescription(), argValue.getUsage(), INDENT_SIZE); + printHelp(argValue.getMatches(), argValue.getDescription(), argValue.getUsage(), argValue.getDefaultVal(), INDENT_SIZE); } private static void printHelp(ArgValueOption argValueOption) { - printHelp(argValueOption.getMatches(), argValueOption.getDescription(), null, INDENT_SIZE); + printHelp(argValueOption.getMatches(), argValueOption.getDescription(), null, null, INDENT_SIZE); } } diff --git a/src/qz/utils/ArgValue.java b/src/qz/utils/ArgValue.java index a1560f3ae..d16f5025c 100644 --- a/src/qz/utils/ArgValue.java +++ b/src/qz/utils/ArgValue.java @@ -9,60 +9,93 @@ public enum ArgValue { // Informational - HELP(INFORMATION, "Display help information and exit.", null, + HELP(INFORMATION, "Display help information and exit.", null, null, "--help", "-h", "/?"), - VERSION(INFORMATION, "Display version information and exit.", null, + VERSION(INFORMATION, "Display version information and exit.", null, null, "--version", "-v"), - BUNDLEID(INFORMATION, "Display Apple bundle identifier and exit.", null, + BUNDLEID(INFORMATION, "Display Apple bundle identifier and exit.", null, null, "--bundleid", "-i"), - LIBINFO(INFORMATION, "Display detailed library version information and exit.", null, + LIBINFO(INFORMATION, "Display detailed library version information and exit.", null, null, "--libinfo", "-l"), // Actions - ALLOW(ACTION,String.format("Add the specified certificate to %s.dat.", Constants.ALLOW_FILE), "--allow cert.pem", + ALLOW(ACTION,String.format("Add the specified certificate to %s.dat.", Constants.ALLOW_FILE), "--allow cert.pem", null, "--allow", "--whitelist", "-a"), - BLOCK(ACTION, String.format("Add the specified certificate to %s.dat.", Constants.BLOCK_FILE), "--block cert.pem", + BLOCK(ACTION, String.format("Add the specified certificate to %s.dat.", Constants.BLOCK_FILE), "--block cert.pem", null, "--block", "--blacklist", "-b"), - FILE_ALLOW(ACTION, String.format("Add the specified file.allow entry to %s.properties for FileIO operations, sandboxed to a specified certificate if provided", Constants.PROPS_FILE), "--file-allow /my/file/path [--sandbox \"Company Name\"]", + FILE_ALLOW(ACTION, String.format("Add the specified file.allow entry to %s.properties for FileIO operations, sandboxed to a specified certificate if provided", Constants.PROPS_FILE), "--file-allow /my/file/path [--sandbox \"Company Name\"]", null, "--file-allow"), - FILE_REMOVE(ACTION, String.format("Removes the specified file.allow entry from %s.properties for FileIO operations", Constants.PROPS_FILE), "--file-remove /my/file/path", + FILE_REMOVE(ACTION, String.format("Removes the specified file.allow entry from %s.properties for FileIO operations", Constants.PROPS_FILE), "--file-remove /my/file/path", null, "--file-remove"), // Options - AUTOSTART(OPTION,"Read and honor any autostart preferences before launching.", null, + AUTOSTART(OPTION,"Read and honor any autostart preferences before launching.", null, true, "--honorautostart", "-A"), - STEAL(OPTION, "Ask other running instance to stop so that this instance can take precedence.", null, + STEAL(OPTION, "Ask other running instance to stop so that this instance can take precedence.", null, false, "--steal", Constants.DATA_DIR + ":steal"), - HEADLESS(OPTION, "Force startup \"headless\" without graphical interface or interactive components.", null, + HEADLESS(OPTION, "Force startup \"headless\" without graphical interface or interactive components.", null, false, "--headless"), // Installer stubs - PREINSTALL(INSTALLER, "Perform critical pre-installation steps: Stop instances, all other special considerations.", null, + PREINSTALL(INSTALLER, "Perform critical pre-installation steps: Stop instances, all other special considerations.", null, null, "preinstall"), - INSTALL(INSTALLER, "Copy to the specified destination and preforms platform-specific registration.", "install --dest /my/install/location [--silent]", + INSTALL(INSTALLER, "Copy to the specified destination and preforms platform-specific registration.", "install --dest /my/install/location [--silent]", null, "install"), - CERTGEN(INSTALLER, "Performs certificate generation and registration for proper HTTPS support.", "certgen [--key key.pem --cert cert.pem] [--pfx cert.pfx --pass 12345] [--host \"list;of;hosts\"]", + CERTGEN(INSTALLER, "Performs certificate generation and registration for proper HTTPS support.", "certgen [--key key.pem --cert cert.pem] [--pfx cert.pfx --pass 12345] [--host \"list;of;hosts\"]", null, "certgen"), - UNINSTALL(INSTALLER, "Perform all uninstall tasks: Stop instances, delete files, unregister settings.", null, + UNINSTALL(INSTALLER, "Perform all uninstall tasks: Stop instances, delete files, unregister settings.", null, null, "uninstall"), - SPAWN(INSTALLER, "Spawn an instance of the specified program as the logged-in user, avoiding starting as the root user if possible.", "spawn [program params ...]", + SPAWN(INSTALLER, "Spawn an instance of the specified program as the logged-in user, avoiding starting as the root user if possible.", "spawn [program params ...]", null, "spawn"), // Build stubs - JLINK(BUILD, "Download, compress and bundle a Java Runtime", "jlink [--platform mac|windows|linux] [--arch x64|aarch64] [--vendor bellsoft|eclipse|...] [--version ...] [--gc hotspot|openj9] [--gcversion ...]", - "jlink"); + JLINK(BUILD, "Download, compress and bundle a Java Runtime", "jlink [--platform mac|windows|linux] [--arch x64|aarch64] [--vendor bellsoft|eclipse|...] [--version ...] [--gc hotspot|openj9] [--gcversion ...]", null, + "jlink"), + + // Parameter stubs + TRAY_NOTIFICATIONS(PREFERENCES, "Show verbose connect/disconnect notifications in the tray area", null, false, + "tray.notifications"), + TRAY_HEADLESS(PREFERENCES, "Start QZ Tray in headless (no user interface) mode", null, false, + "tray.headless"), + TRAY_MONOCLE(PREFERENCES, "Enable/disable the use of the Monocle for JavaFX/HTML rendering", null, true, + "tray.monocle"), + TRAY_STRICTMODE(PREFERENCES, "Enable/disable solely trusting certificates matching authcert.override", null, false, + "tray.strictmode"), + TRAY_IDLE_PRINTERS(PREFERENCES, "Enable/disable idle crawling of printers and their media information for faster initial results", null, true, + "tray.idle.printers"), + TRAY_IDLE_JAVAFX(PREFERENCES, "Enable/disable idle starting of JavaFX for better initial performance", null, true, + "tray.idle.javafx"), + SECURITY_FILE_ENABLED(PREFERENCES, "Enable/disable all File Communications features", null, true, + "security.file.enabled"), + SECURITY_FILE_STRICT(PREFERENCES, "Enable/disable signing requirements for File Communications features", null, true, + "security.file.strict"), + LOG_DISABLE(PREFERENCES, "Disable/enable logging features", null, false, + "log.disable"), + LOG_ROTATE(PREFERENCES, "Number of log files to retain when the size fills up", null, 5, + "log.rotate"), + LOG_SIZE(PREFERENCES, "Maximum file size (in bytes) of a single log file", null, 524288, + "log.size"), + AUTHCERT_OVERRIDE(PREFERENCES, "Override the trusted root certificate in the software.", null, null, + "authcert.override", "trustedRootCert"), + PRINTER_STATUS_JOB_DATA(PREFERENCES, "Return all raw (binary) job data with job statuses (use with caution)", null, false, + "printer.status.jobdata"); private ArgType argType; private String description; private String usage; + private Object defaultVal; private String[] matches; - ArgValue(ArgType argType, String description, String usage, String ... matches) { + ArgValue(ArgType argType, String description, String usage, Object defaultVal, String ... matches) { this.argType = argType; this.description = description; this.usage = usage; + this.defaultVal = defaultVal; this.matches = matches; } + + public String getMatch() { return matches[0]; } + public String[] getMatches() { return matches; } @@ -79,12 +112,17 @@ public ArgType getType() { return argType; } + public Object getDefaultVal() { + return defaultVal; + } + public enum ArgType { INFORMATION, ACTION, OPTION, INSTALLER, BUILD, + PREFERENCES, } public static ArgValue[] filter(ArgType ... argTypes) { diff --git a/src/qz/utils/PrefsSearch.java b/src/qz/utils/PrefsSearch.java index 8fbc685cf..5286a638f 100644 --- a/src/qz/utils/PrefsSearch.java +++ b/src/qz/utils/PrefsSearch.java @@ -2,9 +2,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import qz.installer.certificate.CertificateManager; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Properties; /** @@ -12,38 +11,17 @@ */ public class PrefsSearch { protected static final Logger log = LoggerFactory.getLogger(PrefsSearch.class); + private static Properties appProps = null; - public static String get(Properties user, Properties app, String name) { - return get(user, app, name, null); - } - - public static String get(Properties app, String name, String defaultVal, boolean searchSystemProperties) { - return get(null, app, name, defaultVal, searchSystemProperties); - } - - public static int get(Properties app, String name, int defaultVal) { - try { - return Integer.parseInt(get(app, name, "", true)); - } catch(NumberFormatException ignore) {} - return defaultVal; - } - - public static boolean get(Properties app, String name, boolean defaultVal) { - return Boolean.parseBoolean(get(app, name, "" + defaultVal, true)); - } - - public static String get(Properties user, Properties app, String name, String defaultVal, String... altNames) { - return get(user, app, name, defaultVal, true, altNames); - } - - public static String get(Properties user, Properties app, String name, String defaultVal, boolean searchSystemProperties, String... altNames) { + private static String getProperty(String[] names, String defaultVal, boolean searchSystemProperties, Properties ... propArray) { String returnVal; - ArrayList names = new ArrayList<>(); - names.add(name); - - if (altNames != null && altNames.length > 0) { - names.addAll(Arrays.asList(altNames)); + // If none are provided, ensure we have some types of properties to iterate over + if(propArray.length == 0) { + if(appProps == null) { + appProps = CertificateManager.loadProperties(); + } + propArray = new Properties[]{ appProps }; } for(String n : names) { @@ -53,19 +31,13 @@ public static String get(Properties user, Properties app, String name, String de return returnVal; } - // Second, honor user preference - if (user != null) { - if ((returnVal = user.getProperty(n)) != null) { - log.info("Picked up user preference {}={}", n, returnVal); - return returnVal; - } - } - - // Third, honor app property - if (app != null) { - if ((returnVal = app.getProperty(n)) != null) { - log.info("Picked up app property {}={}", n, returnVal); - return returnVal; + for(Properties props : propArray) { + // Second, honor properties file(s) + if (props != null) { + if ((returnVal = props.getProperty(n)) != null) { + log.info("Picked up property {}={}", n, returnVal); + return returnVal; + } } } } @@ -73,4 +45,48 @@ public static String get(Properties user, Properties app, String name, String de // Last, return default property return defaultVal; } + + /* + * Typed String[] helper implementations + */ + private static int getInt(String[] names, int defaultVal, boolean searchSystemProperties, Properties ... propsArray) { + try { + return Integer.parseInt(getProperty(names, "", searchSystemProperties, propsArray)); + } catch(NumberFormatException ignore) {} + return defaultVal; + } + + private static boolean getBoolean(String[] names, boolean defaultVal, boolean searchSystemProperties, Properties ... propsArray) { + return Boolean.parseBoolean(getProperty(names, "" + defaultVal, searchSystemProperties, propsArray)); + } + + /* + * Typed ArgValue implementations + */ + public static String getString(ArgValue argValue, boolean searchSystemProperties, Properties ... propsArray) { + return getProperty(argValue.getMatches(), (String)argValue.getDefaultVal(), searchSystemProperties, propsArray); + } + + public static int getInt(ArgValue argValue, boolean searchSystemProperties, Properties ... propsArray) { + return getInt(argValue.getMatches(), (Integer)argValue.getDefaultVal(), searchSystemProperties, propsArray); + } + + public static boolean getBoolean(ArgValue argValue, boolean searchSystemProperties, Properties ... propsArray) { + return getBoolean(argValue.getMatches(), (Boolean)argValue.getDefaultVal(), searchSystemProperties, propsArray); + } + + /* + * Typed ArgValue implementations (searchSystemProperties = true) + */ + public static String getString(ArgValue argValue, Properties ... propsArray) { + return getString(argValue, true, propsArray); + } + + public static int getInt(ArgValue argValue, Properties ... propsArray) { + return getInt(argValue, true, propsArray); + } + + public static boolean getBoolean(ArgValue argValue, Properties ... propsArray) { + return getBoolean(argValue, true, propsArray); + } }