2011-02-26 12:31:56 -05:00
|
|
|
package com.fsck.k9.preferences;
|
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
import java.io.BufferedReader;
|
2011-02-26 12:31:56 -05:00
|
|
|
import java.io.InputStream;
|
2011-03-30 15:00:34 -04:00
|
|
|
import java.io.StringReader;
|
2011-02-26 12:31:56 -05:00
|
|
|
import java.util.HashMap;
|
2011-03-30 15:00:34 -04:00
|
|
|
import java.util.List;
|
2011-02-26 12:31:56 -05:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Stack;
|
2011-03-30 15:00:34 -04:00
|
|
|
import java.util.UUID;
|
2011-02-26 12:31:56 -05:00
|
|
|
|
|
|
|
import javax.xml.parsers.SAXParser;
|
|
|
|
import javax.xml.parsers.SAXParserFactory;
|
|
|
|
|
|
|
|
import org.xml.sax.Attributes;
|
|
|
|
import org.xml.sax.InputSource;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
import org.xml.sax.XMLReader;
|
|
|
|
import org.xml.sax.helpers.DefaultHandler;
|
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
import android.content.Context;
|
2011-02-26 12:31:56 -05:00
|
|
|
import android.content.SharedPreferences;
|
|
|
|
import android.util.Log;
|
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
import com.fsck.k9.Account;
|
2011-02-26 12:31:56 -05:00
|
|
|
import com.fsck.k9.K9;
|
|
|
|
import com.fsck.k9.Preferences;
|
2011-02-26 20:28:47 -05:00
|
|
|
import com.fsck.k9.helper.DateFormatter;
|
2011-02-26 12:31:56 -05:00
|
|
|
|
2011-02-26 19:39:06 -05:00
|
|
|
public class StorageImporter {
|
2011-03-03 11:14:19 -05:00
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
public static void importPreferences(Context context, InputStream is, String encryptionKey,
|
|
|
|
boolean globalSettings, String[] importAccountUuids, boolean overwrite)
|
|
|
|
throws StorageImportExportException {
|
|
|
|
|
2011-03-03 11:14:19 -05:00
|
|
|
try {
|
2011-02-26 12:31:56 -05:00
|
|
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
|
|
|
SAXParser sp = spf.newSAXParser();
|
|
|
|
XMLReader xr = sp.getXMLReader();
|
|
|
|
StorageImporterHandler handler = new StorageImporterHandler();
|
|
|
|
xr.setContentHandler(handler);
|
2011-02-26 19:39:06 -05:00
|
|
|
|
2011-02-26 12:31:56 -05:00
|
|
|
xr.parse(new InputSource(is));
|
2011-02-26 19:39:06 -05:00
|
|
|
|
2011-03-20 12:52:13 -04:00
|
|
|
ImportElement dataset = handler.getRootElement();
|
2011-03-26 02:19:20 -04:00
|
|
|
String storageFormat = dataset.attributes.get("version");
|
|
|
|
Log.i(K9.LOG_TAG, "Got settings file version " + storageFormat);
|
2011-02-26 19:39:06 -05:00
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
Preferences preferences = Preferences.getPreferences(context);
|
|
|
|
SharedPreferences storage = preferences.getPreferences();
|
|
|
|
SharedPreferences.Editor editor = storage.edit();
|
|
|
|
|
|
|
|
String data = dataset.data.toString();
|
|
|
|
List<Integer> accountNumbers = Account.getExistingAccountNumbers(preferences);
|
|
|
|
Log.i(K9.LOG_TAG, "Existing accountNumbers = " + accountNumbers);
|
|
|
|
/**
|
|
|
|
* We translate UUIDs in the import file into new UUIDs in the local instance for the following reasons:
|
|
|
|
* 1) Accidentally importing the same file twice cannot damage settings in an existing account.
|
|
|
|
* (Say, an account that was imported two months ago and has since had significant settings changes.)
|
|
|
|
* 2) Importing a single file multiple times allows for creating multiple accounts from the same template.
|
|
|
|
* 3) Exporting an account and importing back into the same instance is a poor-man's account copy (until a real
|
|
|
|
* copy function is created, if ever)
|
|
|
|
*/
|
|
|
|
Map<String, String> uuidMapping = new HashMap<String, String>();
|
|
|
|
String accountUuids = preferences.getPreferences().getString("accountUuids", null);
|
|
|
|
|
|
|
|
StringReader sr = new StringReader(data);
|
|
|
|
BufferedReader br = new BufferedReader(sr);
|
|
|
|
String line = null;
|
|
|
|
int settingsImported = 0;
|
|
|
|
int numAccounts = 0;
|
|
|
|
K9Krypto krypto = new K9Krypto(encryptionKey, K9Krypto.MODE.DECRYPT);
|
|
|
|
do {
|
|
|
|
line = br.readLine();
|
|
|
|
if (line != null) {
|
|
|
|
//Log.i(K9.LOG_TAG, "Got line " + line);
|
|
|
|
String[] comps = line.split(":");
|
|
|
|
if (comps.length > 1) {
|
|
|
|
String keyEnc = comps[0];
|
|
|
|
String valueEnc = comps[1];
|
|
|
|
String key = krypto.decrypt(keyEnc);
|
|
|
|
String value = krypto.decrypt(valueEnc);
|
|
|
|
String[] keyParts = key.split("\\.");
|
|
|
|
if (keyParts.length > 1) {
|
|
|
|
String oldUuid = keyParts[0];
|
|
|
|
String newUuid = uuidMapping.get(oldUuid);
|
|
|
|
if (newUuid == null) {
|
|
|
|
newUuid = UUID.randomUUID().toString();
|
|
|
|
uuidMapping.put(oldUuid, newUuid);
|
|
|
|
|
|
|
|
Log.i(K9.LOG_TAG, "Mapping oldUuid " + oldUuid + " to newUuid " + newUuid);
|
|
|
|
}
|
|
|
|
keyParts[0] = newUuid;
|
|
|
|
if ("accountNumber".equals(keyParts[1])) {
|
|
|
|
int accountNumber = Account.findNewAccountNumber(accountNumbers);
|
|
|
|
accountNumbers.add(accountNumber);
|
|
|
|
value = Integer.toString(accountNumber);
|
|
|
|
accountUuids += (accountUuids.length() != 0 ? "," : "") + newUuid;
|
|
|
|
numAccounts++;
|
|
|
|
}
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
for (String part : keyParts) {
|
|
|
|
if (builder.length() > 0) {
|
|
|
|
builder.append(".");
|
2011-03-20 12:52:13 -04:00
|
|
|
}
|
2011-03-30 15:00:34 -04:00
|
|
|
builder.append(part);
|
2011-03-20 12:52:13 -04:00
|
|
|
}
|
2011-03-30 15:00:34 -04:00
|
|
|
key = builder.toString();
|
2011-03-20 16:21:24 -04:00
|
|
|
}
|
2011-03-30 15:00:34 -04:00
|
|
|
//Log.i(K9.LOG_TAG, "Setting " + key + " = " + value);
|
|
|
|
settingsImported++;
|
|
|
|
editor.putString(key, value);
|
2011-03-20 16:21:24 -04:00
|
|
|
}
|
2011-03-30 15:00:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
} while (line != null);
|
2011-03-20 16:21:24 -04:00
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
editor.putString("accountUuids", accountUuids);
|
|
|
|
Log.i(K9.LOG_TAG, "Imported " + settingsImported + " settings and " + numAccounts + " accounts");
|
2011-03-20 16:21:24 -04:00
|
|
|
|
2011-03-30 15:00:34 -04:00
|
|
|
editor.commit();
|
|
|
|
Preferences.getPreferences(context).refreshAccounts();
|
|
|
|
DateFormatter.clearChosenFormat();
|
|
|
|
K9.loadPrefs(Preferences.getPreferences(context));
|
|
|
|
K9.setServicesEnabled(context);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new StorageImportExportException();
|
|
|
|
}
|
|
|
|
}
|
2011-03-20 16:21:24 -04:00
|
|
|
|
2011-02-26 19:39:06 -05:00
|
|
|
|
2011-03-20 12:52:13 -04:00
|
|
|
public static class ImportElement {
|
2011-02-26 12:31:56 -05:00
|
|
|
String name;
|
|
|
|
Map<String, String> attributes = new HashMap<String, String>();
|
2011-03-20 12:52:13 -04:00
|
|
|
Map<String, ImportElement> subElements = new HashMap<String, ImportElement>();
|
2011-02-26 12:31:56 -05:00
|
|
|
StringBuilder data = new StringBuilder();
|
|
|
|
}
|
2011-02-26 19:39:06 -05:00
|
|
|
|
|
|
|
private static class StorageImporterHandler extends DefaultHandler {
|
2011-03-20 12:52:13 -04:00
|
|
|
private ImportElement rootElement = new ImportElement();
|
|
|
|
private Stack<ImportElement> mOpenTags = new Stack<ImportElement>();
|
2011-02-26 12:31:56 -05:00
|
|
|
|
2011-03-20 12:52:13 -04:00
|
|
|
public ImportElement getRootElement() {
|
2011-02-26 12:31:56 -05:00
|
|
|
return this.rootElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-26 19:39:06 -05:00
|
|
|
public void startDocument() throws SAXException {
|
2011-02-26 12:31:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-26 19:39:06 -05:00
|
|
|
public void endDocument() throws SAXException {
|
2011-02-26 12:31:56 -05:00
|
|
|
/* Do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void startElement(String namespaceURI, String localName,
|
2011-02-26 19:39:06 -05:00
|
|
|
String qName, Attributes attributes) throws SAXException {
|
2011-02-26 12:31:56 -05:00
|
|
|
Log.i(K9.LOG_TAG, "Starting element " + localName);
|
2011-03-20 12:52:13 -04:00
|
|
|
ImportElement element = new ImportElement();
|
2011-02-26 12:31:56 -05:00
|
|
|
element.name = localName;
|
|
|
|
mOpenTags.push(element);
|
2011-02-26 19:39:06 -05:00
|
|
|
for (int i = 0; i < attributes.getLength(); i++) {
|
2011-02-26 12:31:56 -05:00
|
|
|
String key = attributes.getLocalName(i);
|
|
|
|
String value = attributes.getValue(i);
|
|
|
|
Log.i(K9.LOG_TAG, "Got attribute " + key + " = " + value);
|
|
|
|
element.attributes.put(key, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-26 19:39:06 -05:00
|
|
|
public void endElement(String namespaceURI, String localName, String qName) {
|
2011-02-26 12:31:56 -05:00
|
|
|
Log.i(K9.LOG_TAG, "Ending element " + localName);
|
2011-03-20 12:52:13 -04:00
|
|
|
ImportElement element = mOpenTags.pop();
|
|
|
|
ImportElement superElement = mOpenTags.empty() ? null : mOpenTags.peek();
|
2011-02-26 19:39:06 -05:00
|
|
|
if (superElement != null) {
|
2011-02-26 12:31:56 -05:00
|
|
|
superElement.subElements.put(element.name, element);
|
2011-02-26 19:39:06 -05:00
|
|
|
} else {
|
2011-02-26 12:31:56 -05:00
|
|
|
rootElement = element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-26 19:39:06 -05:00
|
|
|
public void characters(char ch[], int start, int length) {
|
2011-02-26 12:31:56 -05:00
|
|
|
String value = new String(ch, start, length);
|
|
|
|
mOpenTags.peek().data.append(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|