mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-24 08:38:51 -05:00
Put all import code in StorageImporter
Get rid of StorageImporterEncryptedXml and IStorageImporter. Also AsyncUIProcessor is now obsolete.
This commit is contained in:
parent
45afa3a747
commit
d5197fdc56
@ -1,104 +0,0 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.preferences.StorageImporter;
|
||||
|
||||
/**
|
||||
* The class should be used to run long-running processes invoked from the UI that
|
||||
* do not affect the Stores. There are probably pieces of MessagingController
|
||||
* that can be moved here.
|
||||
*
|
||||
*/
|
||||
public class AsyncUIProcessor {
|
||||
|
||||
private final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
private Application mApplication;
|
||||
private static AsyncUIProcessor inst = null;
|
||||
private AsyncUIProcessor(Application application) {
|
||||
mApplication = application;
|
||||
}
|
||||
public synchronized static AsyncUIProcessor getInstance(Application application) {
|
||||
if (inst == null) {
|
||||
inst = new AsyncUIProcessor(application);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
public void execute(Runnable runnable) {
|
||||
threadPool.execute(runnable);
|
||||
}
|
||||
|
||||
public void importSettings(final Activity activity, final Uri uri, final ImportListener listener) {
|
||||
threadPool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
InputStream is = null;
|
||||
try {
|
||||
ContentResolver resolver = mApplication.getContentResolver();
|
||||
is = resolver.openInputStream(uri);
|
||||
} catch (Exception e) {
|
||||
Log.w(K9.LOG_TAG, "Exception while resolving Uri to InputStream", e);
|
||||
if (listener != null) {
|
||||
listener.failure(e.getLocalizedMessage(), e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
final InputStream myIs = is;
|
||||
StorageImporter.importPreferences(activity, is, null, new ImportListener() {
|
||||
@Override
|
||||
public void failure(String message, Exception e) {
|
||||
quietClose(myIs);
|
||||
if (listener != null) {
|
||||
listener.failure(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void success(int numAccounts) {
|
||||
quietClose(myIs);
|
||||
if (listener != null) {
|
||||
listener.success(numAccounts);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void canceled() {
|
||||
quietClose(myIs);
|
||||
if (listener != null) {
|
||||
listener.canceled();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started() {
|
||||
if (listener != null) {
|
||||
listener.started();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void quietClose(InputStream is) {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
Log.w(K9.LOG_TAG, "Unable to close inputStream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package com.fsck.k9.preferences;
|
||||
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.preferences.StorageImporter.ImportElement;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public interface IStorageImporter {
|
||||
public boolean needsKey();
|
||||
public abstract int importPreferences(Preferences preferences, SharedPreferences.Editor context, ImportElement dataset, String encryptionKey) throws StorageImportExportException;
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
package com.fsck.k9.preferences;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
@ -14,21 +18,21 @@ import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.activity.AsyncUIProcessor;
|
||||
import com.fsck.k9.activity.ImportListener;
|
||||
import com.fsck.k9.activity.PasswordEntryDialog;
|
||||
import com.fsck.k9.helper.DateFormatter;
|
||||
|
||||
public class StorageImporter {
|
||||
|
||||
public static void importPreferences(Activity activity, InputStream is, String providedEncryptionKey, ImportListener listener) {
|
||||
public static void importPreferences(Context context, InputStream is, String encryptionKey,
|
||||
boolean globalSettings, String[] importAccountUuids, boolean overwrite)
|
||||
throws StorageImportExportException {
|
||||
|
||||
try {
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
SAXParser sp = spf.newSAXParser();
|
||||
@ -42,74 +46,88 @@ public class StorageImporter {
|
||||
String storageFormat = dataset.attributes.get("version");
|
||||
Log.i(K9.LOG_TAG, "Got settings file version " + storageFormat);
|
||||
|
||||
IStorageImporter storageImporter = new StorageImporterEncryptedXml();
|
||||
if (storageImporter.needsKey() && providedEncryptionKey == null) {
|
||||
gatherPassword(activity, storageImporter, dataset, listener);
|
||||
} else {
|
||||
finishImport(activity, storageImporter, dataset, providedEncryptionKey, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (listener != null) {
|
||||
listener.failure(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Preferences preferences = Preferences.getPreferences(context);
|
||||
SharedPreferences storage = preferences.getPreferences();
|
||||
SharedPreferences.Editor editor = storage.edit();
|
||||
|
||||
private static void finishImport(Activity context, IStorageImporter storageImporter, ImportElement dataset, String encryptionKey, ImportListener listener) throws StorageImportExportException {
|
||||
if (listener != null) {
|
||||
listener.started();
|
||||
}
|
||||
Preferences preferences = Preferences.getPreferences(context);
|
||||
SharedPreferences storage = preferences.getPreferences();
|
||||
SharedPreferences.Editor editor = storage.edit();
|
||||
int numAccounts = 0;
|
||||
if (storageImporter != null) {
|
||||
numAccounts = storageImporter.importPreferences(preferences, editor, dataset, encryptionKey);
|
||||
}
|
||||
editor.commit();
|
||||
Preferences.getPreferences(context).refreshAccounts();
|
||||
DateFormatter.clearChosenFormat();
|
||||
K9.loadPrefs(Preferences.getPreferences(context));
|
||||
K9.setServicesEnabled(context);
|
||||
if (listener != null) {
|
||||
listener.success(numAccounts);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
private static void gatherPassword(final Activity activity, final IStorageImporter storageImporter, final ImportElement dataset, final ImportListener listener) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PasswordEntryDialog dialog = new PasswordEntryDialog(activity, activity.getString(R.string.settings_import_encryption_password_prompt),
|
||||
new PasswordEntryDialog.PasswordEntryListener() {
|
||||
public void passwordChosen(final String chosenPassword) {
|
||||
AsyncUIProcessor.getInstance(activity.getApplication()).execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
finishImport(activity, storageImporter, dataset, chosenPassword, listener);
|
||||
} catch (Exception e) {
|
||||
Log.w(K9.LOG_TAG, "Failure during import", e);
|
||||
if (listener != null) {
|
||||
listener.failure(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (listener != null) {
|
||||
listener.canceled();
|
||||
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(".");
|
||||
}
|
||||
builder.append(part);
|
||||
}
|
||||
key = builder.toString();
|
||||
}
|
||||
//Log.i(K9.LOG_TAG, "Setting " + key + " = " + value);
|
||||
settingsImported++;
|
||||
editor.putString(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
} while (line != null);
|
||||
|
||||
};
|
||||
editor.putString("accountUuids", accountUuids);
|
||||
Log.i(K9.LOG_TAG, "Imported " + settingsImported + " settings and " + numAccounts + " accounts");
|
||||
|
||||
editor.commit();
|
||||
Preferences.getPreferences(context).refreshAccounts();
|
||||
DateFormatter.clearChosenFormat();
|
||||
K9.loadPrefs(Preferences.getPreferences(context));
|
||||
K9.setServicesEnabled(context);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new StorageImportExportException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ImportElement {
|
||||
|
@ -1,102 +0,0 @@
|
||||
package com.fsck.k9.preferences;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.preferences.StorageImporter.ImportElement;
|
||||
|
||||
public class StorageImporterEncryptedXml implements IStorageImporter {
|
||||
public int importPreferences(Preferences preferences, SharedPreferences.Editor editor, ImportElement dataset, String encryptionKey) throws StorageImportExportException {
|
||||
try {
|
||||
|
||||
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(".");
|
||||
}
|
||||
builder.append(part);
|
||||
}
|
||||
key = builder.toString();
|
||||
}
|
||||
//Log.i(K9.LOG_TAG, "Setting " + key + " = " + value);
|
||||
settingsImported++;
|
||||
editor.putString(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
} while (line != null);
|
||||
|
||||
editor.putString("accountUuids", accountUuids);
|
||||
Log.i(K9.LOG_TAG, "Imported " + settingsImported + " settings and " + numAccounts + " accounts");
|
||||
return numAccounts;
|
||||
} catch (IOException ie) {
|
||||
throw new StorageImportExportException("Unable to import settings", ie);
|
||||
} catch (Exception e) {
|
||||
throw new StorageImportExportException("Unable to decrypt settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsKey() {
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user