Merge branch 'main' of ssh://git.zander.im/Zander671/curator
This commit is contained in:
		| @ -12,9 +12,6 @@ public class Start { | ||||
|     public static final String CURATOR_VERSION = "1.0"; | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         // TODO debug | ||||
|         System.setProperty("sun.java2d.uiScale", "2"); | ||||
|  | ||||
|         registerSecretsFactories(); | ||||
|         SwingUtilities.invokeLater(() -> new LibrarySelectFrame(args)); | ||||
|     } | ||||
|  | ||||
| @ -117,8 +117,9 @@ public class Library { | ||||
|     private LocalCache localCache; | ||||
|     private RemoteStore remoteStore; | ||||
|  | ||||
|     public Library(File local, URI remote, Secrets secrets) throws ManifestParseException, IOException { | ||||
|     public Library(File local, URI remote, boolean passiveMode, Secrets secrets) throws ManifestParseException, IOException { | ||||
|         remoteStore = new RemoteStore(remote, secrets); | ||||
|         remoteStore.setPassiveMode(passiveMode); | ||||
|         localCache = new LocalCache(local); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -7,6 +7,7 @@ import java.net.ProtocolException; | ||||
| import java.net.URI; | ||||
| import java.util.concurrent.atomic.AtomicReference; | ||||
|  | ||||
| import org.apache.commons.net.PrintCommandListener; | ||||
| import org.apache.commons.net.ftp.FTP; | ||||
| import org.apache.commons.net.ftp.FTPClient; | ||||
| import org.apache.commons.net.ftp.FTPFile; | ||||
| @ -34,6 +35,7 @@ public class RemoteStore { | ||||
|     private final FTPClient ftp; | ||||
|     private int connectionLevel = 0; | ||||
|     private boolean ignoreManifest = false; | ||||
|     private boolean passiveMode; | ||||
|  | ||||
|     public RemoteStoreFileTypeHandler fileTypeHandler = new RemoteStoreFileTypeHandler(); | ||||
|  | ||||
| @ -42,10 +44,14 @@ public class RemoteStore { | ||||
|         if (!url.isAbsolute() || url.getScheme().equals("ftp")) { | ||||
|             ftp = new FTPClient(); | ||||
|         } else if (url.getScheme().equals("ftps")) { | ||||
|             ftp = new FTPSClient(false); | ||||
|             ftp = new FTPSClient("TLS", false); | ||||
|             ((FTPSClient) ftp).setEndpointCheckingEnabled(true); | ||||
|         } else { | ||||
|             throw new ProtocolException("unknown protocol: '" + url.getScheme() + "'"); | ||||
|         } | ||||
|         // Uncomment this to print all FTP commands | ||||
|         // ftp.addProtocolCommandListener(new PrintCommandListener(System.out, true)); | ||||
|         ftp.setListHiddenFiles(true); | ||||
|         this.secrets = secrets; | ||||
|     } | ||||
|  | ||||
| @ -61,6 +67,24 @@ public class RemoteStore { | ||||
|         this.ignoreManifest = ignoreManifest; | ||||
|     } | ||||
|  | ||||
|     public boolean isPassiveMode() { | ||||
|         return passiveMode; | ||||
|     } | ||||
|  | ||||
|     public void setPassiveMode(boolean passiveMode) throws IOException { | ||||
|         this.passiveMode = passiveMode; | ||||
|         if (connectionLevel != 0) { | ||||
|             String modeString = passiveMode ? "passive" : "active"; | ||||
|             LOGGER.info("Switching to " + modeString + " mode"); | ||||
|             if (passiveMode) { | ||||
|                 ftp.enterLocalPassiveMode(); | ||||
|             } else { | ||||
|                 ftp.enterLocalActiveMode(); | ||||
|             } | ||||
|             checkFtpResponse("Failed to switch to " + modeString + " mode"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void fetchManifest() throws IOException { | ||||
|         doFtpActions(() -> { | ||||
|             FTPFile info = fileInformation(MANIFEST_PATH); | ||||
| @ -199,10 +223,27 @@ public class RemoteStore { | ||||
|         return fileInformation(path) != null; | ||||
|     } | ||||
|  | ||||
|     private boolean isRootDir(String path) { | ||||
|         return path.matches("^(/+\\.{0,2})+$"); | ||||
|     } | ||||
|  | ||||
|     public FTPFile fileInformation(String path) throws IOException { | ||||
|         if (isRootDir(path)) { | ||||
|             return null; | ||||
|         } | ||||
|         AtomicReference<FTPFile> file = new AtomicReference<FTPFile>(); | ||||
|         doFtpActions(() -> { | ||||
|             file.set(ftp.mlistFile(resolvePath(path))); | ||||
|             String pp = getParentPath(path); | ||||
|             if (pp == null) { | ||||
|                 pp = getBasePath(); | ||||
|             } | ||||
|             String name = getFileName(path); | ||||
|             FTPFile[] files = ftp.listFiles(pp); | ||||
|             for (FTPFile f : files) { | ||||
|                 if (f.getName().equals(name)) { | ||||
|                     file.set(f); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         return file.get(); | ||||
|     } | ||||
| @ -216,6 +257,14 @@ public class RemoteStore { | ||||
|                 throw new IOException("Invalid ftp secrets! Username: '" + secrets.getUsername() + "'"); | ||||
|             } | ||||
|             LOGGER.info("Logged info ftp as user '{}'", secrets.getUsername()); | ||||
|             if (ftp instanceof FTPSClient) { | ||||
|                 FTPSClient ftps = (FTPSClient) ftp; | ||||
|                 ftps.execPBSZ(0); | ||||
|                 checkFtpResponse("Failed to send PBSZ command"); | ||||
|                 ftps.execPROT("P"); | ||||
|                 checkFtpResponse("Failed to send PROT command"); | ||||
|             } | ||||
|             setPassiveMode(passiveMode); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -307,7 +356,10 @@ public class RemoteStore { | ||||
|                     pb.append("/"); | ||||
|                     ftp.makeDirectory(pb.toString()); | ||||
|                 } | ||||
|                 checkFtpResponse("Could not create directory: " + pp); | ||||
|                 info = fileInformation(pp); | ||||
|                 // if (info == null || !info.isDirectory()) { | ||||
|                 //     throw new IOException("Failed to create directory: " + pp); | ||||
|                 // } | ||||
|                 LOGGER.info("Created directory: {}", pp); | ||||
|             } else if (!info.isDirectory()) { | ||||
|                 throw new IOException("Not a directory: " + pp); | ||||
| @ -319,8 +371,15 @@ public class RemoteStore { | ||||
|         if (ftp.isConnected()) { | ||||
|             int r = ftp.getReplyCode(); | ||||
|             if (!FTPReply.isPositiveCompletion(r)) { | ||||
|                 LOGGER.info(error); | ||||
|                 throw new IOException(error); | ||||
|                 String replyString = ftp.getReplyString(); | ||||
|                 if (replyString.endsWith("\n")) { | ||||
|                     replyString = replyString.substring(0, replyString.length() - 1); | ||||
|                 } | ||||
|                 if (replyString.endsWith(".")) { | ||||
|                     replyString = replyString.substring(0, replyString.length() - 1); | ||||
|                 } | ||||
|                 LOGGER.info("{}: {}", error, replyString); | ||||
|                 throw new IOException(error + ": " + replyString); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -365,6 +424,19 @@ public class RemoteStore { | ||||
|         if (i == -1) { | ||||
|             return null; | ||||
|         } | ||||
|         return cp.substring(0, i); | ||||
|         String pp = cp.substring(0, i); | ||||
|         while (!pp.isEmpty() && pp.charAt(pp.length() - 1) == '/') { | ||||
|             pp = pp.substring(0, pp.length() - 1); | ||||
|         } | ||||
|         return pp; | ||||
|     } | ||||
|  | ||||
|     private static String getFileName(String path) { | ||||
|         String cp = cleanPath(path); | ||||
|         int i = cp.lastIndexOf("/"); | ||||
|         if (i == -1) { | ||||
|             return cp; | ||||
|         } | ||||
|         return cp.substring(i + 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,7 +33,7 @@ public class PassSecretsFactory extends SecretsFactory { | ||||
|  | ||||
|     public static boolean isBackendSupported() { | ||||
|         try { | ||||
|             Process p = Runtime.getRuntime().exec("which pass"); | ||||
|             Process p = Runtime.getRuntime().exec(new String[] {"which", "pass"}); | ||||
|             if (!p.waitFor(1000, TimeUnit.MILLISECONDS)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
| @ -12,6 +12,7 @@ import javax.swing.Box; | ||||
| import javax.swing.BoxLayout; | ||||
| import javax.swing.JButton; | ||||
| import javax.swing.JCheckBox; | ||||
| import javax.swing.JComboBox; | ||||
| import javax.swing.JDialog; | ||||
| import javax.swing.JFileChooser; | ||||
| import javax.swing.JLabel; | ||||
| @ -44,6 +45,8 @@ public class LibraryCreateDialog extends JDialog { | ||||
|     private final JTextField usernameField; | ||||
|     private final JLabel passwordLabel; | ||||
|     private final JPasswordField passwordField; | ||||
|     private final JLabel ftpModeLabel; | ||||
|     private final JComboBox<String> ftpModeCombo; | ||||
|     private final JCheckBox defaultPathCheck; | ||||
|     private final JLabel pathLabel; | ||||
|     private final FileChooserField pathField; | ||||
| @ -66,6 +69,8 @@ public class LibraryCreateDialog extends JDialog { | ||||
|         usernameField = new JTextField(10); | ||||
|         passwordLabel = new JLabel("Password:"); | ||||
|         passwordField = new JPasswordField(10); | ||||
|         ftpModeLabel = new JLabel("FTP Mode:"); | ||||
|         ftpModeCombo = new JComboBox<String>(new String[] { "Passive", "Active" }); | ||||
|         defaultPathCheck = new JCheckBox("Use default library location"); | ||||
|         defaultPathCheck.setSelected(true); | ||||
|         pathLabel = new JLabel("Library Path:"); | ||||
| @ -223,12 +228,21 @@ public class LibraryCreateDialog extends JDialog { | ||||
|         entryPanel.add(passwordField, gbc); | ||||
|         gbc.gridy = 5; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         entryPanel.add(ftpModeLabel, gbc); | ||||
|         gbc.gridx = 1; | ||||
|         gbc.fill = GridBagConstraints.HORIZONTAL; | ||||
|         gbc.anchor = GridBagConstraints.LINE_START; | ||||
|         entryPanel.add(ftpModeCombo, gbc); | ||||
|         gbc.gridy = 6; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.anchor = GridBagConstraints.CENTER; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         gbc.gridwidth = 2; | ||||
|         entryPanel.add(defaultPathCheck, gbc); | ||||
|         gbc.gridwidth = 1; | ||||
|         gbc.gridy = 6; | ||||
|         gbc.gridy = 7; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         entryPanel.add(pathLabel, gbc); | ||||
| @ -266,4 +280,8 @@ public class LibraryCreateDialog extends JDialog { | ||||
|         return pathField.getPathField().getText(); | ||||
|     } | ||||
|  | ||||
|     public boolean isFtpPassiveMode() { | ||||
|         return ftpModeCombo.getSelectedItem().equals("Passive"); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,7 @@ import javax.swing.Box; | ||||
| import javax.swing.BoxLayout; | ||||
| import javax.swing.JButton; | ||||
| import javax.swing.JCheckBox; | ||||
| import javax.swing.JComboBox; | ||||
| import javax.swing.JDialog; | ||||
| import javax.swing.JFileChooser; | ||||
| import javax.swing.JLabel; | ||||
| @ -44,6 +45,8 @@ public class LibraryEditDialog extends JDialog { | ||||
|     private final JTextField usernameField; | ||||
|     private final JLabel passwordLabel; | ||||
|     private final JPasswordField passwordField; | ||||
|     private final JLabel ftpModeLabel; | ||||
|     private final JComboBox<String> ftpModeCombo; | ||||
|     private final JCheckBox defaultPathCheck; | ||||
|     private final JLabel pathLabel; | ||||
|     private final FileChooserField pathField; | ||||
| @ -55,7 +58,9 @@ public class LibraryEditDialog extends JDialog { | ||||
|     private final JPanel buttonPanel; | ||||
|     private final JPanel panel; | ||||
|  | ||||
|     public LibraryEditDialog(Window parent, String name, String url, String ftp, String username, String password, String file, Runnable cacheClearCallback) { | ||||
|     public LibraryEditDialog(Window parent, String name, String url, String ftp, | ||||
|         String username, String password, boolean passiveMode, String file, | ||||
|         Runnable cacheClearCallback) { | ||||
|         super(parent, "Edit Library"); | ||||
|         nameLabel = new JLabel("Name:"); | ||||
|         nameField = new JTextField(10); | ||||
| @ -72,6 +77,9 @@ public class LibraryEditDialog extends JDialog { | ||||
|         passwordLabel = new JLabel("Password:"); | ||||
|         passwordField = new JPasswordField(10); | ||||
|         passwordField.setText(password); | ||||
|         ftpModeLabel = new JLabel("FTP Mode:"); | ||||
|         ftpModeCombo = new JComboBox<String>(new String[] { "Passive", "Active" }); | ||||
|         ftpModeCombo.setSelectedIndex(passiveMode ? 0 : 1); | ||||
|         defaultPathCheck = new JCheckBox("Use default library location"); | ||||
|         pathLabel = new JLabel("Library Path:"); | ||||
|         pathField = new FileChooserField(10, file, new File(LibrarySelectFrame.DEFAULT_LIBRARY_PATH)); | ||||
| @ -245,11 +253,20 @@ public class LibraryEditDialog extends JDialog { | ||||
|         gbc.gridy = 5; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         entryPanel.add(ftpModeLabel, gbc); | ||||
|         gbc.gridx = 1; | ||||
|         gbc.fill = GridBagConstraints.HORIZONTAL; | ||||
|         gbc.anchor = GridBagConstraints.LINE_START; | ||||
|         entryPanel.add(ftpModeCombo, gbc); | ||||
|         gbc.gridy = 6; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         gbc.anchor = GridBagConstraints.CENTER; | ||||
|         gbc.gridwidth = 2; | ||||
|         entryPanel.add(defaultPathCheck, gbc); | ||||
|         gbc.gridwidth = 1; | ||||
|         gbc.gridy = 6; | ||||
|         gbc.gridy = 7; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         entryPanel.add(pathLabel, gbc); | ||||
| @ -287,4 +304,8 @@ public class LibraryEditDialog extends JDialog { | ||||
|         return pathField.getPathField().getText(); | ||||
|     } | ||||
|  | ||||
|     public boolean isFtpPassiveMode() { | ||||
|         return ftpModeCombo.getSelectedItem().equals("Passive"); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,7 @@ import java.awt.event.KeyEvent; | ||||
| import javax.swing.Box; | ||||
| import javax.swing.BoxLayout; | ||||
| import javax.swing.JButton; | ||||
| import javax.swing.JComboBox; | ||||
| import javax.swing.JDialog; | ||||
| import javax.swing.JFileChooser; | ||||
| import javax.swing.JLabel; | ||||
| @ -39,6 +40,8 @@ public class LibraryImportDialog extends JDialog { | ||||
|     private final JTextField usernameField; | ||||
|     private final JLabel passwordLabel; | ||||
|     private final JPasswordField passwordField; | ||||
|     private final JLabel ftpModeLabel; | ||||
|     private final JComboBox<String> ftpModeCombo; | ||||
|     private final JLabel fileLabel; | ||||
|     private final FileChooserField fileField; | ||||
|     private final JPanel entryPanel; | ||||
| @ -58,6 +61,8 @@ public class LibraryImportDialog extends JDialog { | ||||
|         usernameField = new JTextField(10); | ||||
|         passwordLabel = new JLabel("Password:"); | ||||
|         passwordField = new JPasswordField(10); | ||||
|         ftpModeLabel = new JLabel("FTP Mode:"); | ||||
|         ftpModeCombo = new JComboBox<String>(new String[] { "Passive", "Active" }); | ||||
|         fileLabel = new JLabel("Source:"); | ||||
|         fileField = new FileChooserField(10); | ||||
|         fileField.getChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); | ||||
| @ -167,6 +172,15 @@ public class LibraryImportDialog extends JDialog { | ||||
|         gbc.gridx = 0; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         entryPanel.add(ftpModeLabel, gbc); | ||||
|         gbc.gridx = 1; | ||||
|         gbc.fill = GridBagConstraints.HORIZONTAL; | ||||
|         gbc.anchor = GridBagConstraints.LINE_START; | ||||
|         entryPanel.add(ftpModeCombo, gbc); | ||||
|         gbc.gridy = 5; | ||||
|         gbc.gridx = 0; | ||||
|         gbc.anchor = GridBagConstraints.LINE_END; | ||||
|         gbc.fill = GridBagConstraints.NONE; | ||||
|         entryPanel.add(fileLabel, gbc); | ||||
|         gbc.gridx = 1; | ||||
|         gbc.fill = GridBagConstraints.HORIZONTAL; | ||||
| @ -198,4 +212,8 @@ public class LibraryImportDialog extends JDialog { | ||||
|         return fileField.getPathField().getText(); | ||||
|     } | ||||
|  | ||||
|     public boolean isFtpPassiveMode() { | ||||
|         return ftpModeCombo.getSelectedItem().equals("Passive"); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -80,12 +80,15 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         public String name; | ||||
|         public String url; | ||||
|         public String ftp; | ||||
|         public boolean passiveMode; | ||||
|         public File file; | ||||
|  | ||||
|         public LibraryEntry(String name, String url, String ftp, File file) { | ||||
|         public LibraryEntry(String name, String url, String ftp, | ||||
|             boolean passiveMode, File file) { | ||||
|             this.name = name; | ||||
|             this.url = url; | ||||
|             this.ftp = ftp; | ||||
|             this.passiveMode = passiveMode; | ||||
|             this.file = file; | ||||
|         } | ||||
|  | ||||
| @ -101,7 +104,9 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         public boolean equals(Object o) { | ||||
|             if (o instanceof LibraryEntry) { | ||||
|                 LibraryEntry e = (LibraryEntry) o; | ||||
|                 return e.name.equals(name) && e.url.equals(url) && e.file.getPath().equals(file.getPath()); | ||||
|                 return e.name.equals(name) && e.url.equals(url) && | ||||
|                        e.file.getPath().equals(file.getPath()) && | ||||
|                        e.passiveMode == passiveMode; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| @ -201,7 +206,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                 nld.setVisible(true); | ||||
|                 if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) { | ||||
|                     createLibrary(nld.getLibraryName(), nld.getURL(), nld.getFTP(), | ||||
|                                   nld.getUsername(), nld.getPassword(), new File(nld.getLibraryFile())); | ||||
|                         nld.getUsername(), nld.getPassword(), | ||||
|                         nld.isFtpPassiveMode(), new File(nld.getLibraryFile())); | ||||
|                 } | ||||
|             }); | ||||
|         importItem = new JMenuItem("Import"); | ||||
| @ -209,7 +215,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                 LibraryImportDialog lid = new LibraryImportDialog(this); | ||||
|                 lid.setVisible(true); | ||||
|                 if (lid.getResponse() == LibraryImportDialog.RESPONSE_IMPORT) { | ||||
|                     importLibrary(lid.getURL(), lid.getFTP(), lid.getUsername(), lid.getPassword(), new File(lid.getFile())); | ||||
|                     importLibrary(lid.getURL(), lid.getFTP(), lid.getUsername(), | ||||
|                         lid.getPassword(), lid.isFtpPassiveMode(), new File(lid.getFile())); | ||||
|                 } | ||||
|             }); | ||||
|         listPopup = new JPopupMenu(); | ||||
| @ -287,7 +294,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                 LibraryImportDialog lid = new LibraryImportDialog(this); | ||||
|                 lid.setVisible(true); | ||||
|                 if (lid.getResponse() == LibraryImportDialog.RESPONSE_IMPORT) { | ||||
|                     importLibrary(lid.getURL(), lid.getFTP(), lid.getUsername(), lid.getPassword(), new File(lid.getFile())); | ||||
|                     importLibrary(lid.getURL(), lid.getFTP(), lid.getUsername(), | ||||
|                         lid.getPassword(), lid.isFtpPassiveMode(), new File(lid.getFile())); | ||||
|                 } | ||||
|             }); | ||||
|         newButton = new JButton("New"); | ||||
| @ -297,7 +305,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                 nld.setVisible(true); | ||||
|                 if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) { | ||||
|                     createLibrary(nld.getLibraryName(), nld.getURL(), nld.getFTP(), | ||||
|                                   nld.getUsername(), nld.getPassword(), new File(nld.getLibraryFile())); | ||||
|                         nld.getUsername(), nld.getPassword(), | ||||
|                         nld.isFtpPassiveMode(), new File(nld.getLibraryFile())); | ||||
|                 } | ||||
|             }); | ||||
|         deleteButton = new JButton("Delete"); | ||||
| @ -468,7 +477,9 @@ public class LibrarySelectFrame extends JFrame { | ||||
|     } | ||||
|  | ||||
|     private String formatLibraryUrl(String url) { | ||||
|         if (!url.matches("^https?\\:\\/\\/.*")) { | ||||
|         if (url.isBlank()) { | ||||
|             return ""; | ||||
|         } else if (!url.matches("^https?\\:\\/\\/.*")) { | ||||
|             return "https://" + url; | ||||
|         } | ||||
|         return url; | ||||
| @ -476,8 +487,9 @@ public class LibrarySelectFrame extends JFrame { | ||||
|  | ||||
|     private void editLibrary(LibraryEntry en) { | ||||
|         Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name); | ||||
|         LibraryEditDialog led = new LibraryEditDialog(this, en.name, en.url, en.ftp, | ||||
|                                                       s.getUsername(), s.getPassword(), en.file.getPath(), | ||||
|         LibraryEditDialog led = new LibraryEditDialog(this, en.name, en.url, | ||||
|             en.ftp, s.getUsername(), s.getPassword(), | ||||
|             en.passiveMode, en.file.getPath(), | ||||
|             () -> clearLibraryCache(en)); | ||||
|         led.setVisible(true); | ||||
|         if (led.getResponse() == LibraryEditDialog.RESPONSE_SAVE) { | ||||
| @ -506,6 +518,7 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                     en.name = led.getLibraryName(); | ||||
|                     en.url = formatLibraryUrl(led.getURL()); | ||||
|                     en.ftp = led.getFTP(); | ||||
|                     en.passiveMode = led.isFtpPassiveMode(); | ||||
|                     en.file = nf; | ||||
|                     saveLibraryList(); | ||||
|                     list.repaint(); | ||||
| @ -548,7 +561,7 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         settingsPutObject("last-library", en); | ||||
|         Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name); | ||||
|         try { | ||||
|             Library lib = new Library(en.file, new URI(en.ftp), s); | ||||
|             Library lib = new Library(en.file, new URI(en.ftp), en.passiveMode, s); | ||||
|             LibrarySyncDialog lsd = new LibrarySyncDialog(null, lib); | ||||
|             if (lsd.sync() == LibrarySyncDialog.STATUS_OK) { | ||||
|                 return lib; | ||||
| @ -622,7 +635,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void importLibrary(String url, String ftp, String username, String password, File dir) { | ||||
|     private void importLibrary(String url, String ftp, String username, | ||||
|         String password, boolean passiveMode, File dir) { | ||||
|         File cf = null; | ||||
|         try { | ||||
|             cf = dir.getCanonicalFile(); | ||||
| @ -640,7 +654,7 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name); | ||||
|         s.setUsername(username); | ||||
|         s.setPassword(password); | ||||
|         LibraryEntry en = new LibraryEntry(name, url, ftp, cf); | ||||
|         LibraryEntry en = new LibraryEntry(name, url, ftp, passiveMode, cf); | ||||
|         LIBRARY_ENTRIES.add(0, en); | ||||
|         openLibrary(en, false); | ||||
|     } | ||||
| @ -702,7 +716,8 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private void createLibrary(String name, String url, String ftp, String username, String password, File file) { | ||||
|     private void createLibrary(String name, String url, String ftp, | ||||
|         String username, String password, boolean passiveMode, File file) { | ||||
|         File cf = null; | ||||
|         try { | ||||
|             cf = file.getCanonicalFile(); | ||||
| @ -726,7 +741,7 @@ public class LibrarySelectFrame extends JFrame { | ||||
|                     recursiveDelete(cf); | ||||
|                     break; | ||||
|                 case LibraryExistsDialog.RESPONSE_IMPORT: | ||||
|                     importLibrary(url, ftp, username, password, file); | ||||
|                     importLibrary(url, ftp, username, password, passiveMode, file); | ||||
|                     return; | ||||
|                 default: | ||||
|                     return; | ||||
| @ -756,7 +771,7 @@ public class LibrarySelectFrame extends JFrame { | ||||
|         Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name); | ||||
|         s.setUsername(username); | ||||
|         s.setPassword(password); | ||||
|         LibraryEntry en = new LibraryEntry(name, url, ftp, cf); | ||||
|         LibraryEntry en = new LibraryEntry(name, url, ftp, passiveMode, cf); | ||||
|         LIBRARY_ENTRIES.add(0, en); | ||||
|         openLibrary(en, false); | ||||
|     } | ||||
|  | ||||
| @ -3,6 +3,8 @@ package zander.ui.media.map; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.net.URL; | ||||
| import java.net.URLConnection; | ||||
| import java.net.URLEncoder; | ||||
| @ -128,9 +130,12 @@ public class OSMLocationEncoder implements LocationEncoder { | ||||
|  | ||||
|     private static URL getURLForQuery(String query) { | ||||
|         try { | ||||
|             final String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8); | ||||
|             return new URL("https://nominatim.openstreetmap.org/search.php?format=jsonv2&q=" + encodedQuery); | ||||
|         } catch (MalformedURLException e) { | ||||
|             final String encodedQuery = URLEncoder.encode(query, | ||||
|                 StandardCharsets.UTF_8); | ||||
|             return new URI( | ||||
|                 "https://nominatim.openstreetmap.org/search.php?format=jsonv2&q=" + | ||||
|                 encodedQuery).toURL(); | ||||
|         } catch (URISyntaxException | MalformedURLException e) { | ||||
|             LOGGER.error("Could not generate url for query: '{}'", query, e); | ||||
|             throw new Error("Could not create URL!", e); | ||||
|         } | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 28 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 29 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 19 KiB | 
| @ -4,18 +4,22 @@ | ||||
|     <h1 style="text-align: center">Local Library Settings</h1> | ||||
|     <h2>Overview</h2> | ||||
|     <p> | ||||
|       These dialogs create, import or alter the settings of libraries. These settings are primarily | ||||
|       for use of Curator and will not affect the Art Museum website. | ||||
|       These dialogs create, import or alter the settings of libraries. These | ||||
|       settings are primarily for use of Curator and will not affect the Art | ||||
|       Museum website. | ||||
|     </p> | ||||
|     <p> | ||||
|       <b>Local vs Remote Library</b> | ||||
|       <br> | ||||
|       Remore libraries are instances of the Art Museum website. They are connected to by FTP. | ||||
|       Any changes made to them will be reflected in their respective Art Museum instance. | ||||
|       Remore libraries are instances of the Art Museum website. They are | ||||
|       connected to by FTP.  Any changes made to them will be reflected in their | ||||
|       respective Art Museum instance. | ||||
|       <br> | ||||
|       Local libraries, or caches, are instances of libraries located on your computer. When you connect | ||||
|       to a remote library, a local library is automatically created and sync with its remote counterpart. | ||||
|       Every time you connect to a remote library, its local counterpart is updated in this way. | ||||
|       Local libraries, or caches, are instances of libraries located on your | ||||
|       computer. When you connect to a remote library, a local library is | ||||
|       automatically created and sync with its remote counterpart.  Every time | ||||
|       you connect to a remote library, its local counterpart is updated in this | ||||
|       way. | ||||
|     </p> | ||||
|     <img width="500" src="library-create-dialog.png"></img> | ||||
|     <p>The library creation and remote import dialog.</p> | ||||
| @ -29,16 +33,25 @@ | ||||
|     <p>The local library import dialog.</p> | ||||
|     <h2>Options</h2> | ||||
|     <ul> | ||||
|       <li><b>Name</b>: library name in the select dialog. Does not affect website.</li> | ||||
|       <li><b>URL</b>: url in the select dialog. Can be blank. Does not affect the website.</li> | ||||
|       <li><b>FTP</b>: FTP server to connect to. Must be in the format of 'ftp://hostname:port/path/to/library'. | ||||
|         Protocol can also be FTPS by replacing 'ftp://' with 'ftps://'.</li> | ||||
|       <li><b>Username & Password</b>: username and password to use to connect to FTP server.</li> | ||||
|       <li><b>Library Location (Source)</b>: location to save caches in. If 'User default library location' | ||||
|         is checked, it will be stored in the directory set in the global settings menu. | ||||
|       <li><b>Name</b>: library name in the select dialog. Does not affect | ||||
|         website.</li> | ||||
|       <li><b>URL</b>: url in the select dialog. Can be blank. Does not affect | ||||
|         the website.</li> | ||||
|       <li><b>FTP</b>: FTP server to connect to. Must be in the format of | ||||
|         'ftp://hostname:port/path/to/library'. Encryption is supported via | ||||
|         FTPS. To enable it, replace 'ftp://' with 'ftps://'.</li> | ||||
|       <li><b>Username & Password</b>: username and password to use to connect to | ||||
|         FTP server.</li> | ||||
|       <li><b>FTP Mode</b>: Whether to use active (PORT) or passive (PASV) FTP | ||||
|         mode. If you are unsure, it's best to start with passive and change to | ||||
|         active if you are having trouble connecting.</li> | ||||
|       <li><b>Library Location (Source)</b>: location to save caches in. If 'User | ||||
|         default library location' is checked, it will be stored in the directory | ||||
|         set in the global settings menu. | ||||
|         <a href="help:Libraries/Global Settings">See: Global Settings</a></li> | ||||
|       <li><b>Clear Cahce</b>: clear library cahce. This does <b>NOT</b> affect the remote library. It only | ||||
|         clears the local cache. Doing this will cause a full re-download of the remote library next time it is | ||||
|       <li><b>Clear Cahce</b>: clear library cahce. This does <b>NOT</b> affect | ||||
|         the remote library. It only clears the local cache. Doing this will | ||||
|         cause a full re-download of the remote library next time it is | ||||
|         oppened.</li> | ||||
|     </ul> | ||||
|   </body> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user