001/* 002 * Syncany, www.syncany.org 003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package org.syncany.config; 019 020import java.io.File; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.List; 024import java.util.logging.Level; 025import java.util.logging.Logger; 026 027import org.syncany.config.to.DaemonConfigTO; 028import org.syncany.config.to.FolderTO; 029import org.syncany.config.to.UserTO; 030import org.syncany.crypto.CipherUtil; 031import org.syncany.operations.watch.WatchOperationOptions; 032import org.syncany.util.FileUtil; 033 034import com.google.common.base.Predicate; 035import com.google.common.collect.Iterables; 036import com.google.common.primitives.Ints; 037 038/** 039 * The daemon helper provides helper functions to read and/or write the 040 * daemon configuration file as defined by {@link DaemonConfigTO}. 041 * 042 * @author Vincent Wiencek (vwiencek@gmail.com) 043 * @author Philipp C. Heckel (philipp.heckel@gmail.com) 044 */ 045public class DaemonConfigHelper { 046 private static final Logger logger = Logger.getLogger(DaemonConfigHelper.class.getSimpleName()); 047 048 public static UserTO getFirstDaemonUser(DaemonConfigTO daemonConfig) { 049 List<UserTO> users = readWebSocketServerUsers(daemonConfig); 050 051 if (users.size() > 0) { 052 return users.get(0); 053 } 054 else { 055 return null; 056 } 057 } 058 059 /** 060 * Adds the given folder to the user-specific daemon configuration (<code>daemon.xml</code>). 061 * 062 * <p>The method first reads the daemon configuration, checks if the folder is already present 063 * and adds it if it is not. If no daemon config file exists, a new default config file is created 064 * via {@link #createAndWriteDefaultDaemonConfig(File)}. If the folder is already present in 065 * the current daemon config, <code>false</code> is returned. If an error occurs (e.g. an I/O error 066 * or an invalid XML file), a {@link ConfigException} is thrown. If the folder was successfully added, 067 * <code>true</code> is returned. 068 * 069 * @param localDir Absolute path of the local folder to add to the daemon config 070 * @return Returns <code>true</code> if the folder was successfully added to the daemon config, 071 * <code>false</code> otherwise 072 * @throws ConfigException If an error occurs, e.g. an I/O error or an invalid XML file 073 */ 074 public static boolean addFolder(File localDir) throws ConfigException { 075 File daemonConfigFile = new File(UserConfig.getUserConfigDir(), UserConfig.DAEMON_FILE); 076 077 if (daemonConfigFile.exists()) { 078 DaemonConfigTO daemonConfigTO = DaemonConfigTO.load(daemonConfigFile); 079 String localDirPath = FileUtil.getCanonicalFile(localDir).getAbsolutePath(); 080 081 // Check if folder already exists 082 boolean folderExists = false; 083 084 for (FolderTO folderTO : daemonConfigTO.getFolders()) { 085 if (localDirPath.equals(folderTO.getPath())) { 086 folderExists = true; 087 break; 088 } 089 } 090 091 // Add to config if it's not already in there 092 if (!folderExists) { 093 logger.log(Level.INFO, "Adding folder to daemon config: " + localDirPath + ", and saving config at " + daemonConfigFile); 094 095 daemonConfigTO.getFolders().add(new FolderTO(localDirPath)); 096 daemonConfigTO.save(daemonConfigFile); 097 098 return true; 099 } 100 else { 101 return false; 102 } 103 } 104 else { 105 FolderTO localDirFolderTO = new FolderTO(localDir.getAbsolutePath()); 106 createAndWriteDaemonConfig(daemonConfigFile, Arrays.asList(new FolderTO[] { localDirFolderTO })); 107 108 return true; 109 } 110 } 111 112 public static boolean removeFolder(File localDir) throws ConfigException { 113 return removeFolder(localDir.getAbsolutePath()); 114 } 115 116 public static boolean removeFolder(String localDirIdentifier) throws ConfigException { 117 File daemonConfigFile = new File(UserConfig.getUserConfigDir(), UserConfig.DAEMON_FILE); 118 119 if (daemonConfigFile.exists()) { 120 DaemonConfigTO daemonConfigTO = DaemonConfigTO.load(daemonConfigFile); 121 122 // Is index? 123 Integer localDirIndex = Ints.tryParse(localDirIdentifier); 124 boolean isLocalDirIndex = localDirIndex != null; 125 boolean folderRemoved = false; 126 127 // Remove by index 128 if (isLocalDirIndex) { 129 localDirIndex--; 130 131 if (localDirIndex >= 0 && localDirIndex < daemonConfigTO.getFolders().size()) { 132 logger.log(Level.INFO, "Given identifier (" + localDirIndex + ") is a valid index for " + daemonConfigTO.getFolders().get(localDirIndex).getPath() + ". REMOVING."); 133 folderRemoved = null != daemonConfigTO.getFolders().remove((int) localDirIndex); 134 } 135 else { 136 logger.log(Level.INFO, "Given identifier (" + localDirIndex + ") is a INVALID index. NOT REMOVING."); 137 } 138 } 139 140 // Remove by name/path 141 else { 142 final String localDirPath = FileUtil.getCanonicalFile(new File(localDirIdentifier)).getAbsolutePath(); 143 144 folderRemoved = Iterables.removeIf(daemonConfigTO.getFolders(), new Predicate<FolderTO>() { 145 @Override 146 public boolean apply(FolderTO folder) { 147 return folder.getPath().equals(localDirPath); 148 } 149 }); 150 } 151 152 // Save (if removed) 153 if (folderRemoved) { 154 logger.log(Level.INFO, "Folder was removed. Saving daemon.xml ..."); 155 156 daemonConfigTO.save(daemonConfigFile); 157 return true; 158 } 159 else { 160 return false; 161 } 162 } 163 else { 164 createAndWriteDaemonConfig(daemonConfigFile, Arrays.asList(new FolderTO[] { })); 165 return true; 166 } 167 } 168 169 public static DaemonConfigTO createAndWriteDefaultDaemonConfig(File daemonConfigFile) throws ConfigException { 170 return createAndWriteDaemonConfig(daemonConfigFile, new ArrayList<FolderTO>()); 171 } 172 173 public static DaemonConfigTO createAndWriteExampleDaemonConfig(File daemonConfigFile) throws ConfigException { 174 File defaultFolder = new File(System.getProperty("user.home"), UserConfig.DEFAULT_FOLDER); 175 176 FolderTO defaultFolderTO = new FolderTO(); 177 defaultFolderTO.setPath(defaultFolder.getAbsolutePath()); 178 defaultFolderTO.setWatchOptions(new WatchOperationOptions()); 179 180 return createAndWriteDaemonConfig(daemonConfigFile, Arrays.asList(new FolderTO[] { defaultFolderTO })); 181 } 182 183 public static DaemonConfigTO createAndWriteDaemonConfig(File configFile, List<FolderTO> folders) throws ConfigException { 184 UserTO defaultUserTO = new UserTO(); 185 defaultUserTO.setUsername(UserConfig.USER_ADMIN); 186 defaultUserTO.setPassword(CipherUtil.createRandomAlphabeticString(12)); 187 188 ArrayList<UserTO> users = new ArrayList<>(); 189 users.add(defaultUserTO); 190 191 DaemonConfigTO defaultDaemonConfigTO = new DaemonConfigTO(); 192 defaultDaemonConfigTO.setFolders(new ArrayList<>(folders)); 193 defaultDaemonConfigTO.setUsers(users); 194 195 defaultDaemonConfigTO.save(configFile); 196 197 return defaultDaemonConfigTO; 198 } 199 200 private static List<UserTO> readWebSocketServerUsers(DaemonConfigTO daemonConfigTO) { 201 List<UserTO> users = daemonConfigTO.getUsers(); 202 203 if (users == null) { 204 users = new ArrayList<UserTO>(); 205 } 206 207 // Add CLI credentials 208 if (daemonConfigTO.getPortTO() != null) { 209 users.add(daemonConfigTO.getPortTO().getUser()); 210 } 211 212 return users; 213 } 214}