package esmska.update;
import com.csvreader.CsvReader;
import esmska.Context;
import esmska.data.Config;
import esmska.data.CountryPrefix;
import esmska.data.Keyring;
import esmska.data.Signature;
import esmska.data.Signatures;
import esmska.data.Tuple;
import esmska.persistence.ContinuousSaveManager;
import esmska.persistence.PersistenceManager;
import java.io.File;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
/** Class for updating from older to newer versions of the program.
* Makes the needed changes when user updates his version.
* @author ripper
*/
public class LegacyUpdater {
private static final Logger logger = Logger.getLogger(LegacyUpdater.class.getName());
/** Checks if some update is needed to be done and executes it if neccessary */
public static void update() throws Exception {
String version = Config.getInstance().getVersion();
if (StringUtils.isEmpty(version)) {
//program is started for the first time, no update neccessary
return;
}
if (ObjectUtils.equals(version, Config.getLatestVersion())) { //already updated
return;
}
logger.log(Level.INFO, "Updating from legacy version {0} to current version {1}",
new Object[]{version, Config.getLatestVersion()});
//changes to 0.8.0
if (Config.compareProgramVersions(version, "0.8.0") < 0) {
//set country prefix from locale
if (StringUtils.isEmpty(Config.getInstance().getCountryPrefix())) {
Config.getInstance().setCountryPrefix(
CountryPrefix.getCountryPrefix(Locale.getDefault().getCountry()));
}
}
//changes to 0.17.0
if (Config.compareProgramVersions(version, "0.16.0") <= 0) {
//keyring encryption changed from AES to XOR
logger.fine("Updating keyring file to newer encryption...");
try {
byte[] passphrase = new byte[]{
-53, -103, 123, -53, -119, -12, -27, -82,
3, -115, 119, -101, 86, 92, 92, 28
};
SecretKeySpec keySpec = new SecretKeySpec(passphrase, "AES");
String CIPHER_TRANSFORMATION = "AES/ECB/PKCS5Padding";
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
Field keyringFileField = PersistenceManager.class.getDeclaredField("keyringFile");
keyringFileField.setAccessible(true);
File keyringFile = (File) keyringFileField.get(null);
ContinuousSaveManager.disableKeyring();
Keyring keyring = Keyring.getInstance();
keyring.clearKeys();
CsvReader reader = new CsvReader(keyringFile.getPath(), ',', Charset.forName("UTF-8"));
reader.setUseComments(true);
while (reader.readRecord()) {
String gatewayName = reader.get(0);
String login = reader.get(1);
String password = reader.get(2);
byte[] ciphertext = Base64.decodeBase64(password.getBytes("UTF-8"));
byte[] cleartext = cipher.doFinal(ciphertext);
password = new String(cleartext, "UTF-8");
Tuple<String, String> key = new Tuple<String, String>(login, password);
keyring.putKey(gatewayName, key);
}
reader.close();
ContinuousSaveManager.enableKeyring();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Updating keyring file failed", ex);
}
}
//changes to 0.22.0
if (Config.compareProgramVersions(version, "0.21") <= 0) {
//transfer senderName and senderNumber settings
Field configFileField = PersistenceManager.class.getDeclaredField("configFile");
configFileField.setAccessible(true);
File configFile = (File) configFileField.get(null);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
Document doc = db.parse(configFile);
String senderNumber = xpath.evaluate("//void[@property='senderNumber']/string", doc);
String senderName = xpath.evaluate("//void[@property='senderName']/string", doc);
Signature defaultSig = Signatures.getInstance().get(Signature.DEFAULT.getProfileName());
if (StringUtils.isNotEmpty(senderName)) {
defaultSig.setUserName(senderName);
}
if (StringUtils.isNotEmpty(senderNumber)) {
defaultSig.setUserNumber(senderNumber);
}
}
//changes to 1.4
if (Config.compareProgramVersions(version, "1.4") < 0) {
//add message ID to queue
logger.fine("Updating queue to add message IDs...");
try {
Field queueFileField = PersistenceManager.class.getDeclaredField("queueFile");
queueFileField.setAccessible(true);
File queueFile = (File) queueFileField.get(null);
List<String> lines = FileUtils.readLines(queueFile, "UTF-8");
ArrayList<String> newLines = new ArrayList<String>();
for (String line : lines) {
newLines.add(line + ",");
}
FileUtils.writeLines(queueFile, "UTF-8", newLines);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Updating queue file failed", ex);
}
}
//changes to 1.7
if (Config.compareProgramVersions(version, "1.6") <= 0) {
// change signature suffix to signature prefix -> append a colon
// to the signature
logger.fine("Updating signature suffix to prefix...");
Context.persistenceManager.loadGateways();
Context.persistenceManager.loadGatewayProperties();
ArrayList<Signature> sigList = new ArrayList<Signature>();
sigList.addAll(Signatures.getInstance().getAll());
sigList.addAll(Signatures.getInstance().getSpecial());
for (Signature signature : sigList) {
String userName = signature.getUserName();
if (StringUtils.isNotEmpty(userName)) {
signature.setUserName(userName + ":");
}
}
Context.persistenceManager.saveGatewayProperties();
}
if (Config.compareProgramVersions(version, "1.6.99") <= 0) {
//add message ID to history
logger.fine("Updating history to add sms IDs...");
try {
Field queueFileField = PersistenceManager.class.getDeclaredField("historyFile");
queueFileField.setAccessible(true);
File queueFile = (File) queueFileField.get(null);
List<String> lines = FileUtils.readLines(queueFile, "UTF-8");
ArrayList<String> newLines = new ArrayList<String>();
for (String line : lines) {
newLines.add(line + ",");
}
FileUtils.writeLines(queueFile, "UTF-8", newLines);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Updating history file failed", ex);
}
}
}
}