Support for ftps

This commit is contained in:
Alexander Rosenberg 2024-09-14 23:51:17 -07:00
parent 240e7f3677
commit d76fda9bfd
Signed by: Zander671
GPG Key ID: 5FD0394ADBD72730
8 changed files with 262 additions and 109 deletions

View File

@ -117,8 +117,9 @@ public class Library {
private LocalCache localCache; private LocalCache localCache;
private RemoteStore remoteStore; 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 = new RemoteStore(remote, secrets);
remoteStore.setPassiveMode(passiveMode);
localCache = new LocalCache(local); localCache = new LocalCache(local);
} }

View File

@ -7,6 +7,7 @@ import java.net.ProtocolException;
import java.net.URI; import java.net.URI;
import java.util.concurrent.atomic.AtomicReference; 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.FTP;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
@ -34,6 +35,7 @@ public class RemoteStore {
private final FTPClient ftp; private final FTPClient ftp;
private int connectionLevel = 0; private int connectionLevel = 0;
private boolean ignoreManifest = false; private boolean ignoreManifest = false;
private boolean passiveMode;
public RemoteStoreFileTypeHandler fileTypeHandler = new RemoteStoreFileTypeHandler(); public RemoteStoreFileTypeHandler fileTypeHandler = new RemoteStoreFileTypeHandler();
@ -42,10 +44,13 @@ public class RemoteStore {
if (!url.isAbsolute() || url.getScheme().equals("ftp")) { if (!url.isAbsolute() || url.getScheme().equals("ftp")) {
ftp = new FTPClient(); ftp = new FTPClient();
} else if (url.getScheme().equals("ftps")) { } else if (url.getScheme().equals("ftps")) {
ftp = new FTPSClient(false); ftp = new FTPSClient("TLS", false);
((FTPSClient) ftp).setEndpointCheckingEnabled(true);
} else { } else {
throw new ProtocolException("unknown protocol: '" + url.getScheme() + "'"); throw new ProtocolException("unknown protocol: '" + url.getScheme() + "'");
} }
ftp.addProtocolCommandListener(new PrintCommandListener(System.out, true));
ftp.setListHiddenFiles(true);
this.secrets = secrets; this.secrets = secrets;
} }
@ -61,6 +66,24 @@ public class RemoteStore {
this.ignoreManifest = ignoreManifest; 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 { public void fetchManifest() throws IOException {
doFtpActions(() -> { doFtpActions(() -> {
FTPFile info = fileInformation(MANIFEST_PATH); FTPFile info = fileInformation(MANIFEST_PATH);
@ -199,10 +222,31 @@ public class RemoteStore {
return fileInformation(path) != null; return fileInformation(path) != null;
} }
private boolean isRootDir(String path) {
return path.matches("^(/+\\.{0,2})+$");
}
public FTPFile fileInformation(String path) throws IOException { public FTPFile fileInformation(String path) throws IOException {
if (isRootDir(path)) {
return null;
}
AtomicReference<FTPFile> file = new AtomicReference<FTPFile>(); AtomicReference<FTPFile> file = new AtomicReference<FTPFile>();
doFtpActions(() -> { 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);
System.out.println("STAT " + name + " in " + pp);
for (FTPFile f : files) {
System.out.println(
(f.isDirectory() ? "D " : "F ") +
f.getName());
if (f.getName().equals(name)) {
file.set(f);
}
}
}); });
return file.get(); return file.get();
} }
@ -216,6 +260,14 @@ public class RemoteStore {
throw new IOException("Invalid ftp secrets! Username: '" + secrets.getUsername() + "'"); throw new IOException("Invalid ftp secrets! Username: '" + secrets.getUsername() + "'");
} }
LOGGER.info("Logged info ftp as user '{}'", 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 +359,10 @@ public class RemoteStore {
pb.append("/"); pb.append("/");
ftp.makeDirectory(pb.toString()); 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); LOGGER.info("Created directory: {}", pp);
} else if (!info.isDirectory()) { } else if (!info.isDirectory()) {
throw new IOException("Not a directory: " + pp); throw new IOException("Not a directory: " + pp);
@ -319,8 +374,15 @@ public class RemoteStore {
if (ftp.isConnected()) { if (ftp.isConnected()) {
int r = ftp.getReplyCode(); int r = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(r)) { if (!FTPReply.isPositiveCompletion(r)) {
LOGGER.info(error); String replyString = ftp.getReplyString();
throw new IOException(error); 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 +427,19 @@ public class RemoteStore {
if (i == -1) { if (i == -1) {
return null; 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);
} }
} }

View File

@ -33,7 +33,7 @@ public class PassSecretsFactory extends SecretsFactory {
public static boolean isBackendSupported() { public static boolean isBackendSupported() {
try { try {
Process p = Runtime.getRuntime().exec("which pass"); Process p = Runtime.getRuntime().exec(new String[] {"which", "pass"});
if (!p.waitFor(1000, TimeUnit.MILLISECONDS)) { if (!p.waitFor(1000, TimeUnit.MILLISECONDS)) {
return false; return false;
} }

View File

@ -12,6 +12,7 @@ import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JLabel; import javax.swing.JLabel;
@ -44,6 +45,8 @@ public class LibraryCreateDialog extends JDialog {
private final JTextField usernameField; private final JTextField usernameField;
private final JLabel passwordLabel; private final JLabel passwordLabel;
private final JPasswordField passwordField; private final JPasswordField passwordField;
private final JLabel ftpModeLabel;
private final JComboBox<String> ftpModeCombo;
private final JCheckBox defaultPathCheck; private final JCheckBox defaultPathCheck;
private final JLabel pathLabel; private final JLabel pathLabel;
private final FileChooserField pathField; private final FileChooserField pathField;
@ -66,6 +69,8 @@ public class LibraryCreateDialog extends JDialog {
usernameField = new JTextField(10); usernameField = new JTextField(10);
passwordLabel = new JLabel("Password:"); passwordLabel = new JLabel("Password:");
passwordField = new JPasswordField(10); passwordField = new JPasswordField(10);
ftpModeLabel = new JLabel("FTP Mode:");
ftpModeCombo = new JComboBox<String>(new String[] { "Active", "Passive" });
defaultPathCheck = new JCheckBox("Use default library location"); defaultPathCheck = new JCheckBox("Use default library location");
defaultPathCheck.setSelected(true); defaultPathCheck.setSelected(true);
pathLabel = new JLabel("Library Path:"); pathLabel = new JLabel("Library Path:");
@ -223,12 +228,21 @@ public class LibraryCreateDialog extends JDialog {
entryPanel.add(passwordField, gbc); entryPanel.add(passwordField, gbc);
gbc.gridy = 5; gbc.gridy = 5;
gbc.gridx = 0; 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.anchor = GridBagConstraints.CENTER;
gbc.fill = GridBagConstraints.NONE; gbc.fill = GridBagConstraints.NONE;
gbc.gridwidth = 2; gbc.gridwidth = 2;
entryPanel.add(defaultPathCheck, gbc); entryPanel.add(defaultPathCheck, gbc);
gbc.gridwidth = 1; gbc.gridwidth = 1;
gbc.gridy = 6; gbc.gridy = 7;
gbc.gridx = 0; gbc.gridx = 0;
gbc.anchor = GridBagConstraints.LINE_END; gbc.anchor = GridBagConstraints.LINE_END;
entryPanel.add(pathLabel, gbc); entryPanel.add(pathLabel, gbc);
@ -266,4 +280,8 @@ public class LibraryCreateDialog extends JDialog {
return pathField.getPathField().getText(); return pathField.getPathField().getText();
} }
public boolean isFtpPassiveMode() {
return ftpModeCombo.getSelectedItem().equals("Passive");
}
} }

View File

@ -12,6 +12,7 @@ import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JLabel; import javax.swing.JLabel;
@ -44,6 +45,8 @@ public class LibraryEditDialog extends JDialog {
private final JTextField usernameField; private final JTextField usernameField;
private final JLabel passwordLabel; private final JLabel passwordLabel;
private final JPasswordField passwordField; private final JPasswordField passwordField;
private final JLabel ftpModeLabel;
private final JComboBox<String> ftpModeCombo;
private final JCheckBox defaultPathCheck; private final JCheckBox defaultPathCheck;
private final JLabel pathLabel; private final JLabel pathLabel;
private final FileChooserField pathField; private final FileChooserField pathField;
@ -55,7 +58,9 @@ public class LibraryEditDialog extends JDialog {
private final JPanel buttonPanel; private final JPanel buttonPanel;
private final JPanel panel; 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"); super(parent, "Edit Library");
nameLabel = new JLabel("Name:"); nameLabel = new JLabel("Name:");
nameField = new JTextField(10); nameField = new JTextField(10);
@ -72,6 +77,9 @@ public class LibraryEditDialog extends JDialog {
passwordLabel = new JLabel("Password:"); passwordLabel = new JLabel("Password:");
passwordField = new JPasswordField(10); passwordField = new JPasswordField(10);
passwordField.setText(password); passwordField.setText(password);
ftpModeLabel = new JLabel("FTP Mode:");
ftpModeCombo = new JComboBox<String>(new String[] { "Active", "Passive" });
ftpModeCombo.setSelectedIndex(passiveMode ? 1 : 0);
defaultPathCheck = new JCheckBox("Use default library location"); defaultPathCheck = new JCheckBox("Use default library location");
pathLabel = new JLabel("Library Path:"); pathLabel = new JLabel("Library Path:");
pathField = new FileChooserField(10, file, new File(LibrarySelectFrame.DEFAULT_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.gridy = 5;
gbc.gridx = 0; gbc.gridx = 0;
gbc.fill = GridBagConstraints.NONE; 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.anchor = GridBagConstraints.CENTER;
gbc.gridwidth = 2; gbc.gridwidth = 2;
entryPanel.add(defaultPathCheck, gbc); entryPanel.add(defaultPathCheck, gbc);
gbc.gridwidth = 1; gbc.gridwidth = 1;
gbc.gridy = 6; gbc.gridy = 7;
gbc.gridx = 0; gbc.gridx = 0;
gbc.anchor = GridBagConstraints.LINE_END; gbc.anchor = GridBagConstraints.LINE_END;
entryPanel.add(pathLabel, gbc); entryPanel.add(pathLabel, gbc);
@ -287,4 +304,8 @@ public class LibraryEditDialog extends JDialog {
return pathField.getPathField().getText(); return pathField.getPathField().getText();
} }
public boolean isFtpPassiveMode() {
return ftpModeCombo.getSelectedItem().equals("Passive");
}
} }

View File

@ -10,6 +10,7 @@ import java.awt.event.KeyEvent;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JLabel; import javax.swing.JLabel;
@ -39,6 +40,8 @@ public class LibraryImportDialog extends JDialog {
private final JTextField usernameField; private final JTextField usernameField;
private final JLabel passwordLabel; private final JLabel passwordLabel;
private final JPasswordField passwordField; private final JPasswordField passwordField;
private final JLabel ftpModeLabel;
private final JComboBox<String> ftpModeCombo;
private final JLabel fileLabel; private final JLabel fileLabel;
private final FileChooserField fileField; private final FileChooserField fileField;
private final JPanel entryPanel; private final JPanel entryPanel;
@ -58,6 +61,8 @@ public class LibraryImportDialog extends JDialog {
usernameField = new JTextField(10); usernameField = new JTextField(10);
passwordLabel = new JLabel("Password:"); passwordLabel = new JLabel("Password:");
passwordField = new JPasswordField(10); passwordField = new JPasswordField(10);
ftpModeLabel = new JLabel("FTP Mode:");
ftpModeCombo = new JComboBox<String>(new String[] { "Active", "Passive" });
fileLabel = new JLabel("Source:"); fileLabel = new JLabel("Source:");
fileField = new FileChooserField(10); fileField = new FileChooserField(10);
fileField.getChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileField.getChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
@ -167,6 +172,15 @@ public class LibraryImportDialog extends JDialog {
gbc.gridx = 0; gbc.gridx = 0;
gbc.anchor = GridBagConstraints.LINE_END; gbc.anchor = GridBagConstraints.LINE_END;
gbc.fill = GridBagConstraints.NONE; 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); entryPanel.add(fileLabel, gbc);
gbc.gridx = 1; gbc.gridx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
@ -198,4 +212,8 @@ public class LibraryImportDialog extends JDialog {
return fileField.getPathField().getText(); return fileField.getPathField().getText();
} }
public boolean isFtpPassiveMode() {
return ftpModeCombo.getSelectedItem().equals("Passive");
}
} }

View File

@ -80,12 +80,15 @@ public class LibrarySelectFrame extends JFrame {
public String name; public String name;
public String url; public String url;
public String ftp; public String ftp;
public boolean passiveMode;
public File file; 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.name = name;
this.url = url; this.url = url;
this.ftp = ftp; this.ftp = ftp;
this.passiveMode = passiveMode;
this.file = file; this.file = file;
} }
@ -101,7 +104,9 @@ public class LibrarySelectFrame extends JFrame {
public boolean equals(Object o) { public boolean equals(Object o) {
if (o instanceof LibraryEntry) { if (o instanceof LibraryEntry) {
LibraryEntry e = (LibraryEntry) o; 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; return false;
} }
@ -201,7 +206,8 @@ public class LibrarySelectFrame extends JFrame {
nld.setVisible(true); nld.setVisible(true);
if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) { if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) {
createLibrary(nld.getLibraryName(), nld.getURL(), nld.getFTP(), 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"); importItem = new JMenuItem("Import");
@ -209,7 +215,8 @@ public class LibrarySelectFrame extends JFrame {
LibraryImportDialog lid = new LibraryImportDialog(this); LibraryImportDialog lid = new LibraryImportDialog(this);
lid.setVisible(true); lid.setVisible(true);
if (lid.getResponse() == LibraryImportDialog.RESPONSE_IMPORT) { 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(); listPopup = new JPopupMenu();
@ -287,7 +294,8 @@ public class LibrarySelectFrame extends JFrame {
LibraryImportDialog lid = new LibraryImportDialog(this); LibraryImportDialog lid = new LibraryImportDialog(this);
lid.setVisible(true); lid.setVisible(true);
if (lid.getResponse() == LibraryImportDialog.RESPONSE_IMPORT) { 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"); newButton = new JButton("New");
@ -297,7 +305,8 @@ public class LibrarySelectFrame extends JFrame {
nld.setVisible(true); nld.setVisible(true);
if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) { if (nld.getResponse() == LibraryCreateDialog.RESPONSE_CREATE) {
createLibrary(nld.getLibraryName(), nld.getURL(), nld.getFTP(), 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"); deleteButton = new JButton("Delete");
@ -468,7 +477,9 @@ public class LibrarySelectFrame extends JFrame {
} }
private String formatLibraryUrl(String url) { private String formatLibraryUrl(String url) {
if (!url.matches("^https?\\:\\/\\/.*")) { if (url.isBlank()) {
return "";
} else if (!url.matches("^https?\\:\\/\\/.*")) {
return "https://" + url; return "https://" + url;
} }
return url; return url;
@ -476,8 +487,9 @@ public class LibrarySelectFrame extends JFrame {
private void editLibrary(LibraryEntry en) { private void editLibrary(LibraryEntry en) {
Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name); Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name);
LibraryEditDialog led = new LibraryEditDialog(this, en.name, en.url, en.ftp, LibraryEditDialog led = new LibraryEditDialog(this, en.name, en.url,
s.getUsername(), s.getPassword(), en.file.getPath(), en.ftp, s.getUsername(), s.getPassword(),
en.passiveMode, en.file.getPath(),
() -> clearLibraryCache(en)); () -> clearLibraryCache(en));
led.setVisible(true); led.setVisible(true);
if (led.getResponse() == LibraryEditDialog.RESPONSE_SAVE) { if (led.getResponse() == LibraryEditDialog.RESPONSE_SAVE) {
@ -506,6 +518,7 @@ public class LibrarySelectFrame extends JFrame {
en.name = led.getLibraryName(); en.name = led.getLibraryName();
en.url = formatLibraryUrl(led.getURL()); en.url = formatLibraryUrl(led.getURL());
en.ftp = led.getFTP(); en.ftp = led.getFTP();
en.passiveMode = led.isFtpPassiveMode();
en.file = nf; en.file = nf;
saveLibraryList(); saveLibraryList();
list.repaint(); list.repaint();
@ -548,7 +561,7 @@ public class LibrarySelectFrame extends JFrame {
settingsPutObject("last-library", en); settingsPutObject("last-library", en);
Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name); Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + en.name);
try { 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); LibrarySyncDialog lsd = new LibrarySyncDialog(null, lib);
if (lsd.sync() == LibrarySyncDialog.STATUS_OK) { if (lsd.sync() == LibrarySyncDialog.STATUS_OK) {
return lib; 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; File cf = null;
try { try {
cf = dir.getCanonicalFile(); cf = dir.getCanonicalFile();
@ -640,7 +654,7 @@ public class LibrarySelectFrame extends JFrame {
Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name); Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name);
s.setUsername(username); s.setUsername(username);
s.setPassword(password); 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); LIBRARY_ENTRIES.add(0, en);
openLibrary(en, false); openLibrary(en, false);
} }
@ -702,7 +716,8 @@ public class LibrarySelectFrame extends JFrame {
return true; 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; File cf = null;
try { try {
cf = file.getCanonicalFile(); cf = file.getCanonicalFile();
@ -726,7 +741,7 @@ public class LibrarySelectFrame extends JFrame {
recursiveDelete(cf); recursiveDelete(cf);
break; break;
case LibraryExistsDialog.RESPONSE_IMPORT: case LibraryExistsDialog.RESPONSE_IMPORT:
importLibrary(url, ftp, username, password, file); importLibrary(url, ftp, username, password, passiveMode, file);
return; return;
default: default:
return; return;
@ -756,7 +771,7 @@ public class LibrarySelectFrame extends JFrame {
Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name); Secrets s = SECRETS_FACTORY.createSecrets(SECRETS_KEY + name);
s.setUsername(username); s.setUsername(username);
s.setPassword(password); 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); LIBRARY_ENTRIES.add(0, en);
openLibrary(en, false); openLibrary(en, false);
} }

View File

@ -3,6 +3,8 @@ package zander.ui.media.map;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLEncoder; import java.net.URLEncoder;
@ -128,9 +130,12 @@ public class OSMLocationEncoder implements LocationEncoder {
private static URL getURLForQuery(String query) { private static URL getURLForQuery(String query) {
try { try {
final String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8); final String encodedQuery = URLEncoder.encode(query,
return new URL("https://nominatim.openstreetmap.org/search.php?format=jsonv2&q=" + encodedQuery); StandardCharsets.UTF_8);
} catch (MalformedURLException e) { 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); LOGGER.error("Could not generate url for query: '{}'", query, e);
throw new Error("Could not create URL!", e); throw new Error("Could not create URL!", e);
} }