/* * Syncany, www.syncany.org * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.syncany.cli; import java.util.List; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; import org.syncany.config.to.ConfigTO; import org.syncany.operations.OperationResult; import org.syncany.operations.init.ConnectOperation; import org.syncany.operations.init.ConnectOperationOptions; import org.syncany.operations.init.ConnectOperationOptions.ConnectOptionsStrategy; import org.syncany.operations.init.ConnectOperationResult; import org.syncany.operations.init.ConnectOperationResult.ConnectResultCode; import org.syncany.plugins.transfer.StorageTestResult; import org.syncany.plugins.transfer.TransferSettings; import static java.util.Arrays.asList; public class ConnectCommand extends AbstractInitCommand { public ConnectCommand() { super(); } @Override public CommandScope getRequiredCommandScope() { return CommandScope.UNINITIALIZED_LOCALDIR; } @Override public boolean canExecuteInDaemonScope() { return false; } @Override public int execute(String[] operationArgs) throws Exception { boolean retryNeeded = true; boolean performOperation = true; ConnectOperationOptions operationOptions = parseOptions(operationArgs); while (retryNeeded && performOperation) { ConnectOperationResult operationResult = new ConnectOperation(operationOptions, this).execute(); printResults(operationResult); retryNeeded = operationResult.getResultCode() != ConnectResultCode.OK && operationResult.getResultCode() != ConnectResultCode.NOK_DECRYPT_ERROR; if (retryNeeded) { performOperation = isInteractive && askRetryConnection(); if (performOperation) { updateTransferSettings(operationOptions.getConfigTO().getTransferSettings()); } } } return 0; } @Override public ConnectOperationOptions parseOptions(String[] operationArgs) throws Exception { ConnectOperationOptions operationOptions = new ConnectOperationOptions(); OptionParser parser = new OptionParser(); OptionSpec<String> optionPlugin = parser.acceptsAll(asList("P", "plugin")).withRequiredArg(); OptionSpec<String> optionPluginOpts = parser.acceptsAll(asList("o", "plugin-option")).withRequiredArg(); OptionSpec<Void> optionAddDaemon = parser.acceptsAll(asList("n", "add-daemon")); OptionSpec<String> optionPassword = parser.acceptsAll(asList("password")).withRequiredArg(); OptionSet options = parser.parse(operationArgs); List<?> nonOptionArgs = options.nonOptionArguments(); // Set interactivity mode isInteractive = !options.has(optionPlugin) && !options.has(optionPassword); // Plugin TransferSettings transferSettings = null; if (nonOptionArgs.size() == 1) { String connectLink = (String) nonOptionArgs.get(0); operationOptions.setStrategy(ConnectOptionsStrategy.CONNECTION_LINK); operationOptions.setConnectLink(connectLink); transferSettings = null; } else if (nonOptionArgs.size() == 0) { operationOptions.setStrategy(ConnectOptionsStrategy.CONNECTION_TO); operationOptions.setConnectLink(null); transferSettings = createTransferSettingsFromOptions(options, optionPlugin, optionPluginOpts); } else { throw new Exception("Invalid syntax."); } ConfigTO configTO = createConfigTO(transferSettings); operationOptions.setLocalDir(localDir); operationOptions.setConfigTO(configTO); operationOptions.setDaemon(options.has(optionAddDaemon)); operationOptions.setPassword(validateAndGetPassword(options, optionPassword)); return operationOptions; } private String validateAndGetPassword(OptionSet options, OptionSpec<String> optionPassword) { if (!isInteractive) { if (options.has(optionPassword)) { return options.valueOf(optionPassword); } else { return null; // No encryption, no password. } } else { return null; // Will be set in callback! } } @Override public void printResults(OperationResult operationResult) { ConnectOperationResult concreteOperationResult = (ConnectOperationResult) operationResult; if (concreteOperationResult.getResultCode() == ConnectResultCode.OK) { out.println(); out.println("Repository connected, and local folder initialized."); out.println("You can now use 'sy up' and 'sy down' to sync your files."); out.println(); if (concreteOperationResult.isAddedToDaemon()) { out.println("To automatically sync this folder, simply restart the daemon with 'sy daemon restart'."); out.println(); } } else if (concreteOperationResult.getResultCode() == ConnectResultCode.NOK_TEST_FAILED) { StorageTestResult testResult = concreteOperationResult.getTestResult(); out.println(); if (!testResult.isTargetCanConnect()) { out.println("ERROR: Cannot connect to the repository, because the connection to the storage backend failed."); out.println(" Possible reasons for this could be connectivity issues (are you connect to the Internet?),"); out.println(" or invalid user credentials (are username/password valid?)."); } else if (!testResult.isTargetExists()) { out.println("ERROR: Cannot connect to the repository, because the target does not exist."); out.println(" Please check if it really exists and if you can read from it / write to it."); } else if (!testResult.isTargetCanWrite()) { out.println("ERROR: Cannot connect to the repository, because the target is not writable. This is probably"); out.println(" a permission issue (does the user have write permissions to the target?)."); } else if (!testResult.isRepoFileExists()) { out.println("ERROR: Cannot connect to the repository, because no repo file was found ('syncany' file)."); out.println(" Are you sure that this is a valid Syncany repository? Use 'sy init' to create a new one."); } else { out.println("ERROR: Cannot connect to the repository."); } out.println(); printTestResult(testResult); } else if (concreteOperationResult.getResultCode() == ConnectResultCode.NOK_DECRYPT_ERROR) { out.println(); out.println("ERROR: Invalid password or corrupt ciphertext."); out.println(); out.println("The reason for this might be an invalid password, or that the"); out.println("link/files have been tampered with."); out.println(); } else { out.println(); out.println("ERROR: Cannot connect to repository. Unknown error code: " + operationResult); out.println(); } } }