Put all import code in StorageImporter

Get rid of StorageImporterEncryptedXml and IStorageImporter. Also
AsyncUIProcessor is now obsolete.
This commit is contained in:
cketti 2011-03-30 21:00:34 +02:00
parent 45afa3a747
commit d5197fdc56
4 changed files with 85 additions and 284 deletions

View File

@ -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);
}
}
}
}

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}
}