mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-24 02:12:15 -05:00
Merge branch 'issue549'
Conflicts: src/com/fsck/k9/Account.java src/com/fsck/k9/K9.java src/com/fsck/k9/Preferences.java src/com/fsck/k9/activity/Accounts.java src/com/fsck/k9/activity/ActivityListener.java src/com/fsck/k9/activity/ChooseFolder.java src/com/fsck/k9/activity/FolderInfoHolder.java src/com/fsck/k9/activity/FolderList.java src/com/fsck/k9/activity/K9Activity.java src/com/fsck/k9/activity/K9ListActivity.java src/com/fsck/k9/activity/MessageList.java src/com/fsck/k9/activity/MessageReference.java src/com/fsck/k9/activity/MessageView.java src/com/fsck/k9/activity/setup/AccountSettings.java src/com/fsck/k9/controller/MessagingController.java src/com/fsck/k9/crypto/Apg.java src/com/fsck/k9/helper/DateFormatter.java src/com/fsck/k9/helper/DomainNameChecker.java src/com/fsck/k9/mail/Address.java src/com/fsck/k9/mail/internet/MimeHeader.java src/com/fsck/k9/mail/internet/MimeMessage.java src/com/fsck/k9/mail/internet/MimeUtility.java src/com/fsck/k9/mail/store/ImapStore.java src/com/fsck/k9/mail/store/LocalStore.java src/com/fsck/k9/mail/store/WebDavStore.java src/com/fsck/k9/mail/transport/SmtpTransport.java src/com/fsck/k9/view/AttachmentView.java
This commit is contained in:
commit
932d178679
@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.fsck.k9.activity.Accounts"
|
android:name="com.fsck.k9.activity.Accounts"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleTask"
|
||||||
android:configChanges="locale"
|
android:configChanges="locale"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -269,6 +269,10 @@
|
|||||||
android:name="com.fsck.k9.activity.AccessibleEmailContentActivity"
|
android:name="com.fsck.k9.activity.AccessibleEmailContentActivity"
|
||||||
>
|
>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="com.fsck.k9.activity.ImportSettingsActivity"
|
||||||
|
>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<receiver android:name="com.fsck.k9.service.BootReceiver"
|
<receiver android:name="com.fsck.k9.service.BootReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
|
21
res/layout/password_entry_dialog.xml
Normal file
21
res/layout/password_entry_dialog.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
>
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/password_text_box"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="6dip"
|
||||||
|
android:layout_marginRight="6dip"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="@android:color/primary_text_light"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -6,8 +6,17 @@
|
|||||||
android:title="@string/check_mail_action" />
|
android:title="@string/check_mail_action" />
|
||||||
<item android:id="@+id/empty_trash"
|
<item android:id="@+id/empty_trash"
|
||||||
android:title="@string/empty_trash_action" />
|
android:title="@string/empty_trash_action" />
|
||||||
<item android:id="@+id/edit_account"
|
<item
|
||||||
android:title="@string/account_settings_action" />
|
android:id="@+id/settings"
|
||||||
|
android:title="@string/preferences_action"
|
||||||
|
android:icon="@drawable/ic_menu_preferences">
|
||||||
|
<menu>
|
||||||
|
<item android:id="@+id/edit_account"
|
||||||
|
android:title="@string/account_settings_action" />
|
||||||
|
<item android:id="@+id/export"
|
||||||
|
android:title="@string/settings_export_account" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
<item android:id="@+id/advanced"
|
<item android:id="@+id/advanced"
|
||||||
android:title="@string/advanced">
|
android:title="@string/advanced">
|
||||||
<menu>
|
<menu>
|
||||||
|
@ -31,8 +31,16 @@
|
|||||||
<item android:id="@+id/search"
|
<item android:id="@+id/search"
|
||||||
android:title="@string/search_action" />
|
android:title="@string/search_action" />
|
||||||
-->
|
-->
|
||||||
<item android:id="@+id/edit_prefs"
|
<item android:id="@+id/settings"
|
||||||
android:title="@string/preferences_action"
|
android:title="@string/preferences_action"
|
||||||
android:icon="@android:drawable/ic_menu_preferences"
|
android:icon="@android:drawable/ic_menu_preferences">
|
||||||
/>
|
<menu>
|
||||||
|
<item android:id="@+id/edit_prefs"
|
||||||
|
android:title="@string/global_settings_action" />
|
||||||
|
<item android:id="@+id/export_all"
|
||||||
|
android:title="@string/settings_export_all" />
|
||||||
|
<item android:id="@+id/import_settings"
|
||||||
|
android:title="@string/settings_import" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -70,6 +70,10 @@
|
|||||||
android:title="@string/global_settings_action"
|
android:title="@string/global_settings_action"
|
||||||
android:icon="@android:drawable/ic_menu_preferences"
|
android:icon="@android:drawable/ic_menu_preferences"
|
||||||
/>
|
/>
|
||||||
|
<item android:id="@+id/export"
|
||||||
|
android:title="@string/settings_export_account" />
|
||||||
|
<item android:id="@+id/export_all"
|
||||||
|
android:title="@string/settings_export_all" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
|
@ -151,6 +151,10 @@
|
|||||||
android:title="@string/global_settings_action"
|
android:title="@string/global_settings_action"
|
||||||
android:icon="@android:drawable/ic_menu_preferences"
|
android:icon="@android:drawable/ic_menu_preferences"
|
||||||
/>
|
/>
|
||||||
|
<item android:id="@+id/export"
|
||||||
|
android:title="@string/settings_export_account" />
|
||||||
|
<item android:id="@+id/export_all"
|
||||||
|
android:title="@string/settings_export_all" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
|
@ -79,9 +79,9 @@
|
|||||||
<string name="search_results">Search results</string>
|
<string name="search_results">Search results</string>
|
||||||
<string name="preferences_action">Settings</string>
|
<string name="preferences_action">Settings</string>
|
||||||
<string name="open_action">Open</string>
|
<string name="open_action">Open</string>
|
||||||
<string name="account_settings_action">Account settings</string>
|
<string name="account_settings_action">Edit account settings</string>
|
||||||
<string name="folder_settings_action">Folder settings</string>
|
<string name="folder_settings_action">Edit folder settings</string>
|
||||||
<string name="global_settings_action">Global settings</string>
|
<string name="global_settings_action">Edit global settings</string>
|
||||||
<string name="remove_account_action">Remove account</string>
|
<string name="remove_account_action">Remove account</string>
|
||||||
<string name="clear_pending_action">Clear pending actions (danger!)</string>
|
<string name="clear_pending_action">Clear pending actions (danger!)</string>
|
||||||
|
|
||||||
@ -1028,4 +1028,17 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
|||||||
<string name="messagelist_sent_to_me_sigil">»</string>
|
<string name="messagelist_sent_to_me_sigil">»</string>
|
||||||
<string name="messagelist_sent_cc_me_sigil">›</string>
|
<string name="messagelist_sent_cc_me_sigil">›</string>
|
||||||
<string name="error_unable_to_connect">Unable to connect.</string>
|
<string name="error_unable_to_connect">Unable to connect.</string>
|
||||||
|
|
||||||
|
<string name="settings_encryption_password_prompt">Enter settings encryption password:</string>
|
||||||
|
<string name="settings_export_account">Export account settings</string>
|
||||||
|
<string name="settings_export_all">Export all settings</string>
|
||||||
|
<string name="settings_import">Import settings</string>
|
||||||
|
<string name="settings_exporting">Exporting settings...</string>
|
||||||
|
<string name="settings_importing">Importing settings...</string>
|
||||||
|
<string name="settings_export_success">Exported settings to <xliff:g id="filename">%s</xliff:g></string>
|
||||||
|
<string name="settings_import_success">Imported <xliff:g id="numAccounts">%s</xliff:g> accounts from <xliff:g id="filename">%s</xliff:g></string>
|
||||||
|
<string name="settings_export_failure">Failed to export settings: <xliff:g id="reason">%s</xliff:g></string>
|
||||||
|
<string name="settings_import_failure">Failed from import settings from <xliff:g id="filename">%s</xliff:g>:<xliff:g id="reason">%s</xliff:g></string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -21,7 +21,9 @@ import com.fsck.k9.view.ColorChip;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@ -435,6 +437,32 @@ public class Account implements BaseAccount {
|
|||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int findNewAccountNumber(List<Integer> accountNumbers) {
|
||||||
|
int newAccountNumber = -1;
|
||||||
|
Collections.sort(accountNumbers);
|
||||||
|
for (int accountNumber : accountNumbers) {
|
||||||
|
if (accountNumber > newAccountNumber + 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newAccountNumber = accountNumber;
|
||||||
|
}
|
||||||
|
newAccountNumber++;
|
||||||
|
return newAccountNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Integer> getExistingAccountNumbers(Preferences preferences) {
|
||||||
|
Account[] accounts = preferences.getAccounts();
|
||||||
|
List<Integer> accountNumbers = new LinkedList<Integer>();
|
||||||
|
for (int i = 0; i < accounts.length; i++) {
|
||||||
|
accountNumbers.add(accounts[i].getAccountNumber());
|
||||||
|
}
|
||||||
|
return accountNumbers;
|
||||||
|
}
|
||||||
|
public static int generateAccountNumber(Preferences preferences) {
|
||||||
|
List<Integer> accountNumbers = getExistingAccountNumbers(preferences);
|
||||||
|
return findNewAccountNumber(accountNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void save(Preferences preferences) {
|
public synchronized void save(Preferences preferences) {
|
||||||
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||||
|
|
||||||
@ -450,19 +478,7 @@ public class Account implements BaseAccount {
|
|||||||
*
|
*
|
||||||
* I bet there is a much smarter way to do this. Anyone like to suggest it?
|
* I bet there is a much smarter way to do this. Anyone like to suggest it?
|
||||||
*/
|
*/
|
||||||
Account[] accounts = preferences.getAccounts();
|
mAccountNumber = generateAccountNumber(preferences);
|
||||||
int[] accountNumbers = new int[accounts.length];
|
|
||||||
for (int i = 0; i < accounts.length; i++) {
|
|
||||||
accountNumbers[i] = accounts[i].getAccountNumber();
|
|
||||||
}
|
|
||||||
Arrays.sort(accountNumbers);
|
|
||||||
for (int accountNumber : accountNumbers) {
|
|
||||||
if (accountNumber > mAccountNumber + 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mAccountNumber = accountNumber;
|
|
||||||
}
|
|
||||||
mAccountNumber++;
|
|
||||||
|
|
||||||
String accountUuids = preferences.getPreferences().getString("accountUuids", "");
|
String accountUuids = preferences.getPreferences().getString("accountUuids", "");
|
||||||
accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid;
|
accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid;
|
||||||
|
@ -447,17 +447,9 @@ public class K9 extends Application {
|
|||||||
fontSizes.save(editor);
|
fontSizes.save(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static void loadPrefs(Preferences prefs) {
|
||||||
public void onCreate() {
|
|
||||||
maybeSetupStrictMode();
|
|
||||||
super.onCreate();
|
|
||||||
app = this;
|
|
||||||
|
|
||||||
|
|
||||||
galleryBuggy = checkForBuggyGallery();
|
|
||||||
|
|
||||||
Preferences prefs = Preferences.getPreferences(this);
|
|
||||||
SharedPreferences sprefs = prefs.getPreferences();
|
SharedPreferences sprefs = prefs.getPreferences();
|
||||||
|
|
||||||
DEBUG = sprefs.getBoolean("enableDebugLogging", false);
|
DEBUG = sprefs.getBoolean("enableDebugLogging", false);
|
||||||
DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false);
|
DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false);
|
||||||
mAnimations = sprefs.getBoolean("animations", true);
|
mAnimations = sprefs.getBoolean("animations", true);
|
||||||
@ -505,7 +497,18 @@ public class K9 extends Application {
|
|||||||
|
|
||||||
K9.setK9Language(sprefs.getString("language", ""));
|
K9.setK9Language(sprefs.getString("language", ""));
|
||||||
K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
|
K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
maybeSetupStrictMode();
|
||||||
|
super.onCreate();
|
||||||
|
app = this;
|
||||||
|
|
||||||
|
|
||||||
|
galleryBuggy = checkForBuggyGallery();
|
||||||
|
|
||||||
|
loadPrefs(Preferences.getPreferences(this));
|
||||||
/*
|
/*
|
||||||
* We have to give MimeMessage a temp directory because File.createTempFile(String, String)
|
* We have to give MimeMessage a temp directory because File.createTempFile(String, String)
|
||||||
* doesn't work in Android and MimeMessage does not have access to a Context.
|
* doesn't work in Android and MimeMessage does not have access to a Context.
|
||||||
|
@ -3,7 +3,12 @@ package com.fsck.k9;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.util.Config;
|
import android.util.Config;
|
||||||
@ -29,7 +34,8 @@ public class Preferences {
|
|||||||
|
|
||||||
|
|
||||||
private Storage mStorage;
|
private Storage mStorage;
|
||||||
private List<Account> accounts;
|
private Map<String, Account> accounts = null;
|
||||||
|
private List<Account> accountsInOrder = null;
|
||||||
private Account newAccount;
|
private Account newAccount;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
@ -45,16 +51,35 @@ public class Preferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void loadAccounts() {
|
private synchronized void loadAccounts() {
|
||||||
|
accounts = new HashMap<String, Account>();
|
||||||
|
refreshAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void refreshAccounts() {
|
||||||
|
Map<String, Account> newAccountMap = new HashMap<String, Account>();
|
||||||
|
accountsInOrder = new LinkedList<Account>();
|
||||||
String accountUuids = getPreferences().getString("accountUuids", null);
|
String accountUuids = getPreferences().getString("accountUuids", null);
|
||||||
if ((accountUuids != null) && (accountUuids.length() != 0)) {
|
if ((accountUuids != null) && (accountUuids.length() != 0)) {
|
||||||
String[] uuids = accountUuids.split(",");
|
String[] uuids = accountUuids.split(",");
|
||||||
accounts = new ArrayList<Account>(uuids.length);
|
|
||||||
for (String uuid : uuids) {
|
for (String uuid : uuids) {
|
||||||
accounts.add(new Account(this, uuid));
|
Account account = accounts.get(uuid);
|
||||||
|
if (account != null) {
|
||||||
|
newAccountMap.put(uuid, account);
|
||||||
|
accountsInOrder.add(account);
|
||||||
|
} else {
|
||||||
|
Account newAccount = new Account(this, uuid);
|
||||||
|
newAccountMap.put(uuid, newAccount);
|
||||||
|
accountsInOrder.add(newAccount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
accounts = new ArrayList<Account>();
|
|
||||||
}
|
}
|
||||||
|
if ((newAccount != null) && newAccount.getAccountNumber() != -1) {
|
||||||
|
newAccountMap.put(newAccount.getUuid(), newAccount);
|
||||||
|
accountsInOrder.add(newAccount);
|
||||||
|
newAccount = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts = newAccountMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,12 +92,7 @@ public class Preferences {
|
|||||||
loadAccounts();
|
loadAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((newAccount != null) && newAccount.getAccountNumber() != -1) {
|
return accountsInOrder.toArray(EMPTY_ACCOUNT_ARRAY);
|
||||||
accounts.add(newAccount);
|
|
||||||
newAccount = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return accounts.toArray(EMPTY_ACCOUNT_ARRAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,16 +101,9 @@ public class Preferences {
|
|||||||
* @return all accounts with {@link Account#isAvailable(Context)}
|
* @return all accounts with {@link Account#isAvailable(Context)}
|
||||||
*/
|
*/
|
||||||
public synchronized Collection<Account> getAvailableAccounts() {
|
public synchronized Collection<Account> getAvailableAccounts() {
|
||||||
if (accounts == null) {
|
Account[] allAccounts = getAccounts();
|
||||||
loadAccounts();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((newAccount != null) && newAccount.getAccountNumber() != -1) {
|
|
||||||
accounts.add(newAccount);
|
|
||||||
newAccount = null;
|
|
||||||
}
|
|
||||||
Collection<Account> retval = new ArrayList<Account>(accounts.size());
|
Collection<Account> retval = new ArrayList<Account>(accounts.size());
|
||||||
for (Account account : accounts) {
|
for (Account account : allAccounts) {
|
||||||
if (account.isAvailable(mContext)) {
|
if (account.isAvailable(mContext)) {
|
||||||
retval.add(account);
|
retval.add(account);
|
||||||
}
|
}
|
||||||
@ -103,28 +116,22 @@ public class Preferences {
|
|||||||
if (accounts == null) {
|
if (accounts == null) {
|
||||||
loadAccounts();
|
loadAccounts();
|
||||||
}
|
}
|
||||||
|
Account account = accounts.get(uuid);
|
||||||
|
|
||||||
for (Account account : accounts) {
|
return account;
|
||||||
if (account.getUuid().equals(uuid)) {
|
|
||||||
return account;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((newAccount != null) && newAccount.getUuid().equals(uuid)) {
|
|
||||||
return newAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Account newAccount() {
|
public synchronized Account newAccount() {
|
||||||
newAccount = new Account(K9.app);
|
newAccount = new Account(K9.app);
|
||||||
|
accounts.put(newAccount.getUuid(), newAccount);
|
||||||
|
accountsInOrder.add(newAccount);
|
||||||
|
|
||||||
return newAccount;
|
return newAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void deleteAccount(Account account) {
|
public synchronized void deleteAccount(Account account) {
|
||||||
accounts.remove(account);
|
accounts.remove(account.getUuid());
|
||||||
|
accountsInOrder.remove(account);
|
||||||
account.delete(this);
|
account.delete(this);
|
||||||
|
|
||||||
if (newAccount == account) {
|
if (newAccount == account) {
|
||||||
|
@ -3,11 +3,13 @@ package com.fsck.k9.activity;
|
|||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -29,6 +31,8 @@ import com.fsck.k9.controller.MessagingListener;
|
|||||||
import com.fsck.k9.mail.Flag;
|
import com.fsck.k9.mail.Flag;
|
||||||
import com.fsck.k9.view.ColorChip;
|
import com.fsck.k9.view.ColorChip;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@ -60,6 +64,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
private SearchAccount integratedInboxAccount = null;
|
private SearchAccount integratedInboxAccount = null;
|
||||||
private FontSizes mFontSizes = K9.getFontSizes();
|
private FontSizes mFontSizes = K9.getFontSizes();
|
||||||
|
|
||||||
|
private static final int ACTIVITY_REQUEST_PICK_SETTINGS_FILE = 1;
|
||||||
|
|
||||||
class AccountsHandler extends Handler {
|
class AccountsHandler extends Handler {
|
||||||
private void setViewTitle() {
|
private void setViewTitle() {
|
||||||
String dispString = mListener.formatHeader(Accounts.this, getString(R.string.accounts_title), mUnreadMessageCount, getTimeFormat());
|
String dispString = mListener.formatHeader(Accounts.this, getString(R.string.accounts_title), mUnreadMessageCount, getTimeFormat());
|
||||||
@ -130,6 +136,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProgress(boolean progress)
|
||||||
|
{
|
||||||
|
mHandler.progress(progress);
|
||||||
|
}
|
||||||
|
|
||||||
ActivityListener mListener = new ActivityListener() {
|
ActivityListener mListener = new ActivityListener() {
|
||||||
@Override
|
@Override
|
||||||
public void informUserOfStatus() {
|
public void informUserOfStatus() {
|
||||||
@ -582,6 +593,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
case R.id.recreate:
|
case R.id.recreate:
|
||||||
onRecreate(realAccount);
|
onRecreate(realAccount);
|
||||||
break;
|
break;
|
||||||
|
case R.id.export:
|
||||||
|
onExport(realAccount);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -628,6 +642,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
case R.id.search:
|
case R.id.search:
|
||||||
onSearchRequested();
|
onSearchRequested();
|
||||||
break;
|
break;
|
||||||
|
case R.id.export_all:
|
||||||
|
onExport(null);
|
||||||
|
break;
|
||||||
|
case R.id.import_settings:
|
||||||
|
onImport();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
@ -742,6 +762,97 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onImport()
|
||||||
|
{
|
||||||
|
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
i.setType("*/*");
|
||||||
|
startActivityForResult(Intent.createChooser(i, null), ACTIVITY_REQUEST_PICK_SETTINGS_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
|
{
|
||||||
|
Log.i(K9.LOG_TAG, "onActivityResult requestCode = " + requestCode + ", resultCode = " + resultCode + ", data = " + data);
|
||||||
|
if (resultCode != RESULT_OK)
|
||||||
|
return;
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (requestCode)
|
||||||
|
{
|
||||||
|
case ACTIVITY_REQUEST_PICK_SETTINGS_FILE:
|
||||||
|
onImport(data.getData());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onImport(Uri uri)
|
||||||
|
{
|
||||||
|
Log.i(K9.LOG_TAG, "onImport importing from URI " + uri.getPath());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final String fileName = uri.getPath();
|
||||||
|
ContentResolver resolver = getContentResolver();
|
||||||
|
final InputStream is = resolver.openInputStream(uri);
|
||||||
|
|
||||||
|
PasswordEntryDialog dialog = new PasswordEntryDialog(this, getString(R.string.settings_encryption_password_prompt),
|
||||||
|
new PasswordEntryDialog.PasswordEntryListener()
|
||||||
|
{
|
||||||
|
public void passwordChosen(String chosenPassword)
|
||||||
|
{
|
||||||
|
String toastText = Accounts.this.getString(R.string.settings_importing );
|
||||||
|
Toast toast = Toast.makeText(Accounts.this.getApplication(), toastText, Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
|
mHandler.progress(true);
|
||||||
|
AsyncUIProcessor.getInstance(Accounts.this.getApplication()).importSettings(is, chosenPassword, new ImportListener()
|
||||||
|
{
|
||||||
|
public void failure(final String message, Exception e)
|
||||||
|
{
|
||||||
|
Accounts.this.runOnUiThread(new Runnable()
|
||||||
|
{
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mHandler.progress(false);
|
||||||
|
String toastText = Accounts.this.getString(R.string.settings_import_failure, fileName, message );
|
||||||
|
Toast toast = Toast.makeText(Accounts.this.getApplication(), toastText, 1);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importSuccess(final int numAccounts)
|
||||||
|
{
|
||||||
|
Accounts.this.runOnUiThread(new Runnable()
|
||||||
|
{
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mHandler.progress(false);
|
||||||
|
String toastText = Accounts.this.getString(R.string.settings_import_success, numAccounts, fileName );
|
||||||
|
Toast toast = Toast.makeText(Accounts.this.getApplication(), toastText, 1);
|
||||||
|
toast.show();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException fnfe)
|
||||||
|
{
|
||||||
|
String toastText = Accounts.this.getString(R.string.settings_import_failure, uri.getPath(), fnfe.getMessage() );
|
||||||
|
Toast toast = Toast.makeText(Accounts.this.getApplication(), toastText, 1);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AccountsAdapter extends ArrayAdapter<BaseAccount> {
|
class AccountsAdapter extends ArrayAdapter<BaseAccount> {
|
||||||
public AccountsAdapter(BaseAccount[] accounts) {
|
public AccountsAdapter(BaseAccount[] accounts) {
|
||||||
super(Accounts.this, 0, accounts);
|
super(Accounts.this, 0, accounts);
|
||||||
|
@ -204,7 +204,6 @@ public class ActivityListener extends MessagingListener {
|
|||||||
return mFolderCompleted;
|
return mFolderCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getFolderTotal() {
|
public int getFolderTotal() {
|
||||||
return mFolderTotal;
|
return mFolderTotal;
|
||||||
}
|
}
|
||||||
|
100
src/com/fsck/k9/activity/AsyncUIProcessor.java
Normal file
100
src/com/fsck/k9/activity/AsyncUIProcessor.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.helper.Utility;
|
||||||
|
import com.fsck.k9.preferences.StorageExporter;
|
||||||
|
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 exportSettings(final String uuid, final String encryptionKey, final ExportListener listener) {
|
||||||
|
threadPool.execute(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// Do not store with application files. Settings exports should *not* be
|
||||||
|
// deleted when the application is uninstalled
|
||||||
|
File dir = new File(Environment.getExternalStorageDirectory() + File.separator
|
||||||
|
+ mApplication.getPackageName());
|
||||||
|
dir.mkdirs();
|
||||||
|
File file = Utility.createUniqueFile(dir, "settings.k9s");
|
||||||
|
String fileName = file.getAbsolutePath();
|
||||||
|
StorageExporter.exportPreferences(mApplication, uuid, fileName, encryptionKey);
|
||||||
|
if (listener != null) {
|
||||||
|
listener.exportSuccess(fileName);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
listener.failure(e.getLocalizedMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
public void importSettings(final String fileName, final String encryptionKey, final ImportListener listener) {
|
||||||
|
threadPool.execute(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
int numAccounts = StorageImporter.importPreferences(mApplication, fileName, encryptionKey);
|
||||||
|
K9.setServicesEnabled(mApplication);
|
||||||
|
if (listener != null) {
|
||||||
|
listener.importSuccess(numAccounts);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
listener.failure(e.getLocalizedMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
public void importSettings(final InputStream inputStream, final String encryptionKey, final ImportListener listener) {
|
||||||
|
threadPool.execute(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
int numAccounts = StorageImporter.importPreferences(mApplication, inputStream, encryptionKey);
|
||||||
|
K9.setServicesEnabled(mApplication);
|
||||||
|
if (listener != null) {
|
||||||
|
listener.importSuccess(numAccounts);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
listener.failure(e.getLocalizedMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
src/com/fsck/k9/activity/ExportHelper.java
Normal file
54
src/com/fsck/k9/activity/ExportHelper.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.fsck.k9.Account;
|
||||||
|
import com.fsck.k9.R;
|
||||||
|
|
||||||
|
public class ExportHelper {
|
||||||
|
public static void exportSettings(final Activity activity, final Progressable progressable, final Account account) {
|
||||||
|
PasswordEntryDialog dialog = new PasswordEntryDialog(activity, activity.getString(R.string.settings_encryption_password_prompt),
|
||||||
|
new PasswordEntryDialog.PasswordEntryListener() {
|
||||||
|
public void passwordChosen(String chosenPassword) {
|
||||||
|
String toastText = activity.getString(R.string.settings_exporting);
|
||||||
|
Toast toast = Toast.makeText(activity, toastText, Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
|
progressable.setProgress(true);
|
||||||
|
String uuid = null;
|
||||||
|
if (account != null) {
|
||||||
|
uuid = account.getUuid();
|
||||||
|
}
|
||||||
|
AsyncUIProcessor.getInstance(activity.getApplication()).exportSettings(uuid, chosenPassword,
|
||||||
|
new ExportListener() {
|
||||||
|
public void failure(final String message, Exception e) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
progressable.setProgress(false);
|
||||||
|
String toastText = activity.getString(R.string.settings_export_failure, message);
|
||||||
|
Toast toast = Toast.makeText(activity.getApplication(), toastText, Toast.LENGTH_LONG);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportSuccess(final String fileName) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
progressable.setProgress(false);
|
||||||
|
String toastText = activity.getString(R.string.settings_export_success, fileName);
|
||||||
|
Toast toast = Toast.makeText(activity.getApplication(), toastText, Toast.LENGTH_LONG);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/com/fsck/k9/activity/ExportListener.java
Normal file
8
src/com/fsck/k9/activity/ExportListener.java
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
public interface ExportListener {
|
||||||
|
public void exportSuccess(String fileName);
|
||||||
|
|
||||||
|
public void failure(String message, Exception e);
|
||||||
|
|
||||||
|
}
|
@ -151,6 +151,11 @@ public class FolderList extends K9ListActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProgress(boolean progress)
|
||||||
|
{
|
||||||
|
mHandler.progress(progress);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for reloading the list of local messages for a
|
* This class is responsible for reloading the list of local messages for a
|
||||||
* given folder, notifying the adapter that the message have been loaded and
|
* given folder, notifying the adapter that the message have been loaded and
|
||||||
@ -539,6 +544,14 @@ public class FolderList extends K9ListActivity {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case R.id.export:
|
||||||
|
onExport(mAccount);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case R.id.export_all:
|
||||||
|
onExport(null);
|
||||||
|
return true;
|
||||||
|
|
||||||
case R.id.display_1st_class: {
|
case R.id.display_1st_class: {
|
||||||
setDisplayMode(FolderMode.FIRST_CLASS);
|
setDisplayMode(FolderMode.FIRST_CLASS);
|
||||||
return true;
|
return true;
|
||||||
|
8
src/com/fsck/k9/activity/ImportListener.java
Normal file
8
src/com/fsck/k9/activity/ImportListener.java
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
public interface ImportListener {
|
||||||
|
public void importSuccess(int numAccounts);
|
||||||
|
|
||||||
|
public void failure(String message, Exception e);
|
||||||
|
|
||||||
|
}
|
@ -15,11 +15,13 @@ import android.view.animation.AccelerateInterpolator;
|
|||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.TranslateAnimation;
|
import android.view.animation.TranslateAnimation;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
import com.fsck.k9.Account;
|
||||||
import com.fsck.k9.K9;
|
import com.fsck.k9.K9;
|
||||||
import com.fsck.k9.helper.DateFormatter;
|
import com.fsck.k9.helper.DateFormatter;
|
||||||
|
|
||||||
|
|
||||||
public class K9Activity extends Activity {
|
public class K9Activity extends Activity implements Progressable {
|
||||||
private GestureDetector gestureDetector;
|
private GestureDetector gestureDetector;
|
||||||
|
|
||||||
protected ScrollView mTopView;
|
protected ScrollView mTopView;
|
||||||
@ -161,6 +163,11 @@ public class K9Activity extends Activity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void setProgress(boolean progress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onExport(final Account account) {
|
||||||
|
ExportHelper.exportSettings(this, this, account);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package com.fsck.k9.activity;
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.os.Bundle;
|
|
||||||
|
import com.fsck.k9.Account;
|
||||||
import com.fsck.k9.K9;
|
import com.fsck.k9.K9;
|
||||||
import com.fsck.k9.helper.DateFormatter;
|
import com.fsck.k9.helper.DateFormatter;
|
||||||
|
|
||||||
public class K9ListActivity extends ListActivity {
|
public class K9ListActivity extends ListActivity implements Progressable {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
K9Activity.setLanguage(this, K9.getK9Language());
|
K9Activity.setLanguage(this, K9.getK9Language());
|
||||||
@ -87,4 +89,12 @@ public class K9ListActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
return super.onKeyUp(keyCode, event);
|
return super.onKeyUp(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProgress(boolean progress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onExport(final Account account) {
|
||||||
|
ExportHelper.exportSettings(this, this, account);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -519,6 +519,11 @@ public class MessageList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProgress(boolean progress)
|
||||||
|
{
|
||||||
|
mHandler.progress(progress);
|
||||||
|
}
|
||||||
|
|
||||||
public static void actionHandleFolder(Context context, Account account, String folder) {
|
public static void actionHandleFolder(Context context, Account account, String folder) {
|
||||||
Intent intent = actionHandleFolderIntent(context, account, folder);
|
Intent intent = actionHandleFolderIntent(context, account, folder);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
@ -1397,6 +1402,14 @@ public class MessageList
|
|||||||
onEditPrefs();
|
onEditPrefs();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case R.id.export: {
|
||||||
|
onExport(mAccount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.export_all: {
|
||||||
|
onExport(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mQueryString != null) {
|
if (mQueryString != null) {
|
||||||
|
78
src/com/fsck/k9/activity/PasswordEntryDialog.java
Normal file
78
src/com/fsck/k9/activity/PasswordEntryDialog.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
import com.fsck.k9.R;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.AlertDialog.Builder;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
public class PasswordEntryDialog {
|
||||||
|
public interface PasswordEntryListener {
|
||||||
|
void passwordChosen(String chosenPassword);
|
||||||
|
void cancel();
|
||||||
|
}
|
||||||
|
PasswordEntryListener listener;
|
||||||
|
private EditText passwordView;
|
||||||
|
AlertDialog dialog;
|
||||||
|
public PasswordEntryDialog(Context context, String headerText, PasswordEntryListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
View view = LayoutInflater.from(context).inflate(R.layout.password_entry_dialog, null);
|
||||||
|
Builder builder = new AlertDialog.Builder(context);
|
||||||
|
passwordView = (EditText)view.findViewById(R.id.password_text_box);
|
||||||
|
|
||||||
|
builder.setView(view);
|
||||||
|
builder.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (PasswordEntryDialog.this.listener != null) {
|
||||||
|
String chosenPassword = passwordView.getText().toString();
|
||||||
|
PasswordEntryDialog.this.listener.passwordChosen(chosenPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.cancel_action, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (PasswordEntryDialog.this.listener != null) {
|
||||||
|
PasswordEntryDialog.this.listener.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialog = builder.create();
|
||||||
|
passwordView.addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable arg0) { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
|
||||||
|
int arg3) {
|
||||||
|
|
||||||
|
Button okButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||||
|
String chosenPassword = passwordView.getText().toString();
|
||||||
|
okButton.setEnabled(chosenPassword.length() > 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.setMessage(headerText);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public void show() {
|
||||||
|
dialog.show();
|
||||||
|
Button okButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||||
|
okButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
src/com/fsck/k9/activity/Progressable.java
Normal file
5
src/com/fsck/k9/activity/Progressable.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package com.fsck.k9.activity;
|
||||||
|
|
||||||
|
public interface Progressable {
|
||||||
|
public void setProgress(boolean progress);
|
||||||
|
}
|
@ -75,6 +75,10 @@ public class DateFormatter {
|
|||||||
return sChosenFormat;
|
return sChosenFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void clearChosenFormat() {
|
||||||
|
sChosenFormat = null;
|
||||||
|
}
|
||||||
|
|
||||||
public static DateFormat getDateFormat(Context context) {
|
public static DateFormat getDateFormat(Context context) {
|
||||||
String formatString = getFormat(context);
|
String formatString = getFormat(context);
|
||||||
return getDateFormat(context, formatString);
|
return getDateFormat(context, formatString);
|
||||||
|
9
src/com/fsck/k9/preferences/IStorageImporter.java
Normal file
9
src/com/fsck/k9/preferences/IStorageImporter.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
import com.fsck.k9.Preferences;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
public interface IStorageImporter {
|
||||||
|
public abstract int importPreferences(Preferences preferences, SharedPreferences.Editor context, String data, String encryptionKey) throws StorageImportExportException;
|
||||||
|
}
|
90
src/com/fsck/k9/preferences/SimpleCrypto.java
Normal file
90
src/com/fsck/k9/preferences/SimpleCrypto.java
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* package net.sf.andhsli.hotspotlogin;
|
||||||
|
* Usage:
|
||||||
|
* <pre>
|
||||||
|
* String crypto = SimpleCrypto.encrypt(masterpassword, cleartext)
|
||||||
|
* ...
|
||||||
|
* String cleartext = SimpleCrypto.decrypt(masterpassword, crypto)
|
||||||
|
* </pre>
|
||||||
|
* @author ferenc.hechler
|
||||||
|
*/
|
||||||
|
public class SimpleCrypto {
|
||||||
|
|
||||||
|
public static String encrypt(String seed, String cleartext, Base64 base64) throws Exception {
|
||||||
|
byte[] rawKey = getRawKey(seed.getBytes());
|
||||||
|
byte[] result = encrypt(rawKey, cleartext.getBytes());
|
||||||
|
return new String(base64.encode(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String decrypt(String seed, String encrypted, Base64 base64) throws Exception {
|
||||||
|
byte[] rawKey = getRawKey(seed.getBytes());
|
||||||
|
byte[] enc = base64.decode(encrypted.getBytes());
|
||||||
|
byte[] result = decrypt(rawKey, enc);
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getRawKey(byte[] seed) throws Exception {
|
||||||
|
KeyGenerator kgen = KeyGenerator.getInstance("AES");
|
||||||
|
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
sr.setSeed(seed);
|
||||||
|
kgen.init(128, sr); // 192 and 256 bits may not be available
|
||||||
|
SecretKey skey = kgen.generateKey();
|
||||||
|
byte[] raw = skey.getEncoded();
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
|
||||||
|
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
Cipher cipher = Cipher.getInstance("AES");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||||
|
byte[] encrypted = cipher.doFinal(clear);
|
||||||
|
return encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
|
||||||
|
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
Cipher cipher = Cipher.getInstance("AES");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
|
||||||
|
byte[] decrypted = cipher.doFinal(encrypted);
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// public static byte[] toByte(String hexString) {
|
||||||
|
// int len = hexString.length()/2;
|
||||||
|
// byte[] result = new byte[len];
|
||||||
|
// for (int i = 0; i < len; i++)
|
||||||
|
// result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static String toHex(byte[] buf) {
|
||||||
|
// if (buf == null)
|
||||||
|
// return "";
|
||||||
|
// StringBuffer result = new StringBuffer(2*buf.length);
|
||||||
|
// for (int i = 0; i < buf.length; i++) {
|
||||||
|
// appendHex(result, buf[i]);
|
||||||
|
// }
|
||||||
|
// return result.toString();
|
||||||
|
// }
|
||||||
|
// private final static String HEX = "0123456789ABCDEF";
|
||||||
|
// private static void appendHex(StringBuffer sb, byte b) {
|
||||||
|
// sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
91
src/com/fsck/k9/preferences/StorageExporter.java
Normal file
91
src/com/fsck/k9/preferences/StorageExporter.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import com.fsck.k9.Account;
|
||||||
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.Preferences;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class StorageExporter {
|
||||||
|
//public static String VALIDITY = "K-9MailExport"; // Does outputting a fixed string in a known location make the encrypted data easier to break?
|
||||||
|
public static void exportPreferences(Context context, String uuid, String fileName, String encryptionKey) throws StorageImportExportException {
|
||||||
|
try {
|
||||||
|
Base64 base64 = new Base64();
|
||||||
|
File outFile = new File(fileName);
|
||||||
|
PrintWriter pf = new PrintWriter(outFile);
|
||||||
|
long keysEvaluated = 0;
|
||||||
|
long keysExported = 0;
|
||||||
|
pf.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||||
|
|
||||||
|
// String testval = SimpleCrypto.encrypt(encryptionKey, VALIDITY);
|
||||||
|
|
||||||
|
pf.print("<k9settings version=\"1\"");
|
||||||
|
//pf.print(" validity=\"" + testval + "\"");
|
||||||
|
pf.println(">");
|
||||||
|
Log.i(K9.LOG_TAG, "Exporting preferences for account " + uuid + " to file " + fileName);
|
||||||
|
|
||||||
|
Preferences preferences = Preferences.getPreferences(context);
|
||||||
|
SharedPreferences storage = preferences.getPreferences();
|
||||||
|
|
||||||
|
Account[] accounts = preferences.getAccounts();
|
||||||
|
Set<String> accountUuids = new HashSet<String>();
|
||||||
|
for (Account account : accounts) {
|
||||||
|
accountUuids.add(account.getUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map < String, ? extends Object > prefs = storage.getAll();
|
||||||
|
for (Map.Entry < String, ? extends Object > entry : prefs.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue().toString();
|
||||||
|
//Log.i(K9.LOG_TAG, "Evaluating key " + key);
|
||||||
|
keysEvaluated++;
|
||||||
|
if (uuid != null) {
|
||||||
|
String[] comps = key.split("\\.");
|
||||||
|
String keyUuid = comps[0];
|
||||||
|
//Log.i(K9.LOG_TAG, "Got key uuid " + keyUuid);
|
||||||
|
if (uuid.equals(keyUuid) == false) {
|
||||||
|
//Log.i(K9.LOG_TAG, "Skipping key " + key + " which is for another account or global");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String[] comps = key.split("\\.");
|
||||||
|
if (comps.length > 1) {
|
||||||
|
String keyUuid = comps[0];
|
||||||
|
if (accountUuids.contains(keyUuid) == false) {
|
||||||
|
Log.i(K9.LOG_TAG, "Skipping key " + key + " which is not for any current account");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String keyEnc = SimpleCrypto.encrypt(encryptionKey, key, base64);
|
||||||
|
String valueEnc = SimpleCrypto.encrypt(encryptionKey, value, base64);
|
||||||
|
String output = keyEnc + ":" + valueEnc;
|
||||||
|
//Log.i(K9.LOG_TAG, "For key " + key + ", output is " + output);
|
||||||
|
pf.println(output);
|
||||||
|
keysExported++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pf.println("</k9settings>");
|
||||||
|
pf.close();
|
||||||
|
|
||||||
|
Log.i(K9.LOG_TAG, "Exported " + keysExported + " settings of " + keysEvaluated
|
||||||
|
+ " total for preferences for account " + uuid + " to file " + fileName + " which is size " + outFile.length());
|
||||||
|
} catch (IOException ie) {
|
||||||
|
throw new StorageImportExportException("Unable to export settings", ie);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new StorageImportExportException("Unable to encrypt settings", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
public class StorageImportExportException extends Exception {
|
||||||
|
|
||||||
|
public StorageImportExportException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageImportExportException(String detailMessage, Throwable throwable) {
|
||||||
|
super(detailMessage, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageImportExportException(String detailMessage) {
|
||||||
|
super(detailMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageImportExportException(Throwable throwable) {
|
||||||
|
super(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
141
src/com/fsck/k9/preferences/StorageImporter.java
Normal file
141
src/com/fsck/k9/preferences/StorageImporter.java
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.Preferences;
|
||||||
|
import com.fsck.k9.helper.DateFormatter;
|
||||||
|
|
||||||
|
public class StorageImporter {
|
||||||
|
public static int importPreferences(Context context, String fileName, String encryptionKey) throws StorageImportExportException {
|
||||||
|
try {
|
||||||
|
InputStream is = new FileInputStream(fileName);
|
||||||
|
return importPreferences(context, is, encryptionKey);
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
throw new StorageImportExportException("Failure reading settings file " + fileName, fnfe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static int importPreferences(Context context, InputStream is, String encryptionKey) throws StorageImportExportException {
|
||||||
|
try {
|
||||||
|
Preferences preferences = Preferences.getPreferences(context);
|
||||||
|
SharedPreferences storage = preferences.getPreferences();
|
||||||
|
SharedPreferences.Editor editor = storage.edit();
|
||||||
|
|
||||||
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
|
SAXParser sp = spf.newSAXParser();
|
||||||
|
XMLReader xr = sp.getXMLReader();
|
||||||
|
StorageImporterHandler handler = new StorageImporterHandler();
|
||||||
|
xr.setContentHandler(handler);
|
||||||
|
|
||||||
|
xr.parse(new InputSource(is));
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
Element dataset = handler.getRootElement();
|
||||||
|
String version = dataset.attributes.get("version");
|
||||||
|
Log.i(K9.LOG_TAG, "Got settings file version " + version);
|
||||||
|
|
||||||
|
|
||||||
|
IStorageImporter storageImporter = null;
|
||||||
|
if ("1".equals(version)) {
|
||||||
|
storageImporter = new StorageImporterVersion1();
|
||||||
|
} else {
|
||||||
|
throw new StorageImportExportException("Unable to read file of version " + version
|
||||||
|
+ "; (only version 1 is readable)");
|
||||||
|
}
|
||||||
|
int numAccounts = 0;
|
||||||
|
if (storageImporter != null) {
|
||||||
|
String data = dataset.data.toString();
|
||||||
|
numAccounts = storageImporter.importPreferences(preferences, editor, data, encryptionKey);
|
||||||
|
}
|
||||||
|
editor.commit();
|
||||||
|
Preferences.getPreferences(context).refreshAccounts();
|
||||||
|
DateFormatter.clearChosenFormat();
|
||||||
|
K9.loadPrefs(Preferences.getPreferences(context));
|
||||||
|
return numAccounts;
|
||||||
|
} catch (SAXException se) {
|
||||||
|
throw new StorageImportExportException("Failure reading settings file", se);
|
||||||
|
} catch (IOException ie) {
|
||||||
|
throw new StorageImportExportException("Failure reading settings file", ie);
|
||||||
|
} catch (ParserConfigurationException pce) {
|
||||||
|
throw new StorageImportExportException("Failure reading settings file", pce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Element {
|
||||||
|
String name;
|
||||||
|
Map<String, String> attributes = new HashMap<String, String>();
|
||||||
|
Map<String, Element> subElements = new HashMap<String, Element>();
|
||||||
|
StringBuilder data = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StorageImporterHandler extends DefaultHandler {
|
||||||
|
private Element rootElement = new Element();
|
||||||
|
private Stack<Element> mOpenTags = new Stack<Element>();
|
||||||
|
|
||||||
|
public Element getRootElement() {
|
||||||
|
return this.rootElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startDocument() throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endDocument() throws SAXException {
|
||||||
|
/* Do nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String namespaceURI, String localName,
|
||||||
|
String qName, Attributes attributes) throws SAXException {
|
||||||
|
Log.i(K9.LOG_TAG, "Starting element " + localName);
|
||||||
|
Element element = new Element();
|
||||||
|
element.name = localName;
|
||||||
|
mOpenTags.push(element);
|
||||||
|
for (int i = 0; i < attributes.getLength(); i++) {
|
||||||
|
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
|
||||||
|
public void endElement(String namespaceURI, String localName, String qName) {
|
||||||
|
Log.i(K9.LOG_TAG, "Ending element " + localName);
|
||||||
|
Element element = mOpenTags.pop();
|
||||||
|
Element superElement = mOpenTags.empty() ? null : mOpenTags.peek();
|
||||||
|
if (superElement != null) {
|
||||||
|
superElement.subElements.put(element.name, element);
|
||||||
|
} else {
|
||||||
|
rootElement = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void characters(char ch[], int start, int length) {
|
||||||
|
String value = new String(ch, start, length);
|
||||||
|
mOpenTags.peek().data.append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
src/com/fsck/k9/preferences/StorageImporterVersion1.java
Normal file
88
src/com/fsck/k9/preferences/StorageImporterVersion1.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
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 org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.fsck.k9.Account;
|
||||||
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.Preferences;
|
||||||
|
|
||||||
|
public class StorageImporterVersion1 implements IStorageImporter {
|
||||||
|
public int importPreferences(Preferences preferences, SharedPreferences.Editor editor, String data, String encryptionKey) throws StorageImportExportException {
|
||||||
|
try {
|
||||||
|
Base64 base64 = new Base64();
|
||||||
|
List<Integer> accountNumbers = Account.getExistingAccountNumbers(preferences);
|
||||||
|
Log.i(K9.LOG_TAG, "Existing accountNumbers = " + accountNumbers);
|
||||||
|
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;
|
||||||
|
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 = SimpleCrypto.decrypt(encryptionKey, keyEnc, base64);
|
||||||
|
String value = SimpleCrypto.decrypt(encryptionKey, valueEnc, base64);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user