aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src')
-rw-r--r--OpenPGP-Keychain/src/main/AndroidManifest.xml141
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpCallback.aidl45
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl39
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl143
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpData.aidl20
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl20
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl20
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiCallback.aidl24
-rw-r--r--OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiService.aidl48
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpConstants.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpData.java127
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpError.java81
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpHelper.java52
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java201
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java93
-rw-r--r--OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java110
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java782
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java5
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java1154
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java605
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java5
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java28
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java85
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java11
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java122
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java833
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java217
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java177
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java)2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SignKeyActivity.java)26
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java211
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java)13
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java91
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java)19
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java186
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java17
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java15
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java20
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java82
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java42
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java371
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java4
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java92
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java313
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java17
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java4
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java39
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java8
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java12
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java84
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java13
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java99
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java136
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java9
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml44
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml26
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml216
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_apps_adapter_list_item.xml20
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml (renamed from OpenPGP-Keychain/src/main/res/layout/sign_key_activity.xml)4
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml57
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/drawer_list_item.xml25
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_item.xml24
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml45
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml10
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml32
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml224
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml38
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml3
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml226
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml7
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_view.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_about.html43
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html108
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html6
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/nfc_beam_share.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_about.html43
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html108
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html6
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html6
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_about.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_start.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_about.html9
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_changelog.html4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_start.html26
-rw-r--r--OpenPGP-Keychain/src/main/res/values-de/strings.xml47
-rw-r--r--OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml11
-rw-r--r--OpenPGP-Keychain/src/main/res/values-es/strings.xml393
-rw-r--r--OpenPGP-Keychain/src/main/res/values-fr/strings.xml49
-rw-r--r--OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml3
-rw-r--r--OpenPGP-Keychain/src/main/res/values-ja/strings.xml381
-rw-r--r--OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml18
-rw-r--r--OpenPGP-Keychain/src/main/res/values-ru/strings.xml44
-rw-r--r--OpenPGP-Keychain/src/main/res/values-tr/strings.xml14
-rw-r--r--OpenPGP-Keychain/src/main/res/values-uk/strings.xml46
-rw-r--r--OpenPGP-Keychain/src/main/res/values-zh/strings.xml138
-rw-r--r--OpenPGP-Keychain/src/main/res/values/static_strings.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/values/strings.xml63
159 files changed, 5427 insertions, 4828 deletions
diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml
index 3ef04e4f6..480acdbd8 100644
--- a/OpenPGP-Keychain/src/main/AndroidManifest.xml
+++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml
@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.keychain"
android:installLocation="auto"
- android:versionCode="22001"
- android:versionName="2.2">
+ android:versionCode="23100"
+ android:versionName="2.3.1">
<!--
General remarks
@@ -30,7 +30,7 @@
-->
<uses-sdk
- android:minSdkVersion="8"
+ android:minSdkVersion="9"
android:targetSdkVersion="19" />
<uses-feature
@@ -153,12 +153,19 @@
android:windowSoftInputMode="stateHidden">
<!-- Keychain's own Actions -->
+ <!-- ENCRYPT with text as extra -->
<intent-filter>
<action android:name="org.sufficientlysecure.keychain.action.ENCRYPT" />
<category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <!-- ENCRYPT with data Uri -->
+ <intent-filter>
+ <action android:name="org.sufficientlysecure.keychain.action.ENCRYPT" />
- <data android:mimeType="*/*" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <!-- TODO: accept other schemes! -->
+ <data android:scheme="file" />
</intent-filter>
<!-- Android's Send Action -->
<intent-filter android:label="@string/intent_send_encrypt">
@@ -175,13 +182,40 @@
android:label="@string/title_decrypt"
android:windowSoftInputMode="stateHidden">
+ <!--&lt;!&ndash; VIEW with mimeType: TODO (from email app) &ndash;&gt;-->
+ <!--<intent-filter android:label="@string/intent_import_key">-->
+ <!--<action android:name="android.intent.action.VIEW" />-->
+
+ <!--<category android:name="android.intent.category.BROWSABLE" />-->
+ <!--<category android:name="android.intent.category.DEFAULT" />-->
+
+ <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
+ <!--<data android:mimeType="application/pgp-signature" />-->
+ <!--</intent-filter>-->
+ <!--&lt;!&ndash; VIEW with mimeType: TODO (from email app) &ndash;&gt;-->
+ <!--<intent-filter android:label="@string/intent_import_key">-->
+ <!--<action android:name="android.intent.action.VIEW" />-->
+
+ <!--<category android:name="android.intent.category.BROWSABLE" />-->
+ <!--<category android:name="android.intent.category.DEFAULT" />-->
+
+ <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
+ <!--<data android:mimeType="application/pgp-encrypted" />-->
+ <!--</intent-filter>-->
<!-- Keychain's own Actions -->
+ <!-- DECRYPT with text as extra -->
<intent-filter>
<action android:name="org.sufficientlysecure.keychain.action.DECRYPT" />
<category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <!-- DECRYPT with data Uri -->
+ <intent-filter>
+ <action android:name="org.sufficientlysecure.keychain.action.DECRYPT" />
- <data android:mimeType="*/*" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <!-- TODO: accept other schemes! -->
+ <data android:scheme="file" />
</intent-filter>
<!-- Android's Send Action -->
<intent-filter android:label="@string/intent_send_decrypt">
@@ -249,17 +283,19 @@
android:label="@string/title_key_server_preference"
android:windowSoftInputMode="stateHidden" />
<activity
- android:name=".ui.SignKeyActivity"
+ android:name=".ui.CertifyKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_sign_key" />
+ android:label="@string/title_certify_key" />
<activity
android:name=".ui.ImportKeysActivity"
+ android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_import_keys"
android:launchMode="singleTop"
android:windowSoftInputMode="stateHidden">
- <!-- Handle URIs with fingerprints when scanning directly from Barcode Scanner -->
- <intent-filter>
+ <!-- VIEW with fingerprint scheme:
+ Handle URIs with fingerprints when scanning directly from Barcode Scanner -->
+ <intent-filter android:label="@string/intent_import_key">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -272,31 +308,25 @@
<data android:scheme="OpenPGP4Fpr" />
<data android:scheme="OpenPGP4fpr" />
</intent-filter>
- <!-- Handle NFC tags detected from outside our application -->
- <intent-filter>
- <action android:name="android.nfc.action.NDEF_DISCOVERED" />
-
- <category android:name="android.intent.category.DEFAULT" />
- <!-- mime type as defined in http://tools.ietf.org/html/rfc3156, section 7 -->
- <data android:mimeType="application/pgp-keys" />
- </intent-filter>
- <!-- Keychain's own Actions -->
+ <!-- VIEW with mimeType: Allows to import keys (attached to emails) from email apps -->
<intent-filter android:label="@string/intent_import_key">
- <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" />
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="*/*" />
+ <!-- mime type as defined in http://tools.ietf.org/html/rfc3156 -->
+ <data android:mimeType="application/pgp-keys" />
</intent-filter>
- <!-- IMPORT again without mimeType to also allow data only without filename -->
- <intent-filter android:label="@string/intent_import_key">
- <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" />
- <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_QR_CODE" />
- <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_KEY_SERVER" />
+ <!-- NFC: Handle NFC tags detected from outside our application -->
+ <intent-filter>
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
+ <!-- mime type as defined in http://tools.ietf.org/html/rfc3156 -->
+ <data android:mimeType="application/pgp-keys" />
</intent-filter>
- <!-- Linking "Import key" to file types -->
+ <!-- VIEW with file endings: *.gpg (e.g. to import from OI File Manager) -->
<intent-filter android:label="@string/intent_import_key">
<action android:name="android.intent.action.VIEW" />
@@ -317,6 +347,7 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
</intent-filter>
+ <!-- VIEW with file endings: *.asc -->
<intent-filter android:label="@string/intent_import_key">
<action android:name="android.intent.action.VIEW" />
@@ -338,6 +369,31 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
</intent-filter>
+ <!-- Keychain's own Actions -->
+ <!-- IMPORT_KEY with files TODO: does this work? -->
+ <intent-filter android:label="@string/intent_import_key">
+ <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data android:mimeType="*/*" />
+ </intent-filter>
+ <!-- IMPORT_KEY with mimeType 'application/pgp-keys' -->
+ <intent-filter>
+ <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <!-- mime type as defined in http://tools.ietf.org/html/rfc3156, section 7 -->
+ <data android:mimeType="application/pgp-keys" />
+ </intent-filter>
+ <!-- IMPORT_KEY without mimeType to allow import with extras Bundle -->
+ <intent-filter android:label="@string/intent_import_key">
+ <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" />
+ <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_QR_CODE" />
+ <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_KEYSERVER" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
<activity
android:name=".ui.HelpActivity"
@@ -361,10 +417,9 @@
<activity
android:name="org.sufficientlysecure.keychain.service.remote.RemoteServiceActivity"
android:exported="false"
- android:label="@string/app_name"
- android:launchMode="singleTop"
- android:process=":remote_api"
- android:taskAffinity=":remote_api" />
+ android:label="@string/app_name" />
+ <!--android:launchMode="singleTop"-->
+ <!--android:process=":remote_api"-->
<activity
android:name="org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
@@ -391,19 +446,19 @@
</service>
<!-- Extended Remote API -->
- <service
- android:name="org.sufficientlysecure.keychain.service.remote.ExtendedApiService"
- android:enabled="true"
- android:exported="true"
- android:process=":remote_api">
- <intent-filter>
- <action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />
- </intent-filter>
-
- <meta-data
- android:name="api_version"
- android:value="1" />
- </service>
+ <!--<service-->
+ <!--android:name="org.sufficientlysecure.keychain.service.remote.ExtendedApiService"-->
+ <!--android:enabled="true"-->
+ <!--android:exported="true"-->
+ <!--android:process=":remote_api">-->
+ <!--<intent-filter>-->
+ <!--<action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />-->
+ <!--</intent-filter>-->
+
+ <!--<meta-data-->
+ <!--android:name="api_version"-->
+ <!--android:value="1" />-->
+ <!--</service>-->
<!-- TODO: authority! Make this API with content provider uris -->
<!-- <provider -->
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpCallback.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpCallback.aidl
deleted file mode 100644
index ba41de1ba..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpCallback.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import org.openintents.openpgp.OpenPgpData;
-import org.openintents.openpgp.OpenPgpSignatureResult;
-import org.openintents.openpgp.OpenPgpError;
-
-interface IOpenPgpCallback {
-
- /**
- * onSuccess returns on successful OpenPGP operations.
- *
- * @param output
- * contains resulting output (decrypted content (when input was encrypted)
- * or content without signature (when input was signed-only))
- * @param signatureResult
- * signatureResult is only non-null if decryptAndVerify() was called and the content
- * was encrypted or signed-and-encrypted.
- */
- oneway void onSuccess(in OpenPgpData output, in OpenPgpSignatureResult signatureResult);
-
- /**
- * onError returns on errors or when allowUserInteraction was set to false, but user interaction
- * was required execute an OpenPGP operation.
- *
- * @param error
- * See OpenPgpError class for more information.
- */
- oneway void onError(in OpenPgpError error);
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl
deleted file mode 100644
index 4ca356fad..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import org.openintents.openpgp.OpenPgpError;
-
-interface IOpenPgpKeyIdsCallback {
-
- /**
- * onSuccess returns on successful getKeyIds operations.
- *
- * @param keyIds
- * returned key ids
- */
- oneway void onSuccess(in long[] keyIds);
-
- /**
- * onError returns on errors or when allowUserInteraction was set to false, but user interaction
- * was required execute an OpenPGP operation.
- *
- * @param error
- * See OpenPgpError class for more information.
- */
- oneway void onError(in OpenPgpError error);
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl
deleted file mode 100644
index 8f9e8a0fd..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import org.openintents.openpgp.OpenPgpData;
-import org.openintents.openpgp.IOpenPgpCallback;
-import org.openintents.openpgp.IOpenPgpKeyIdsCallback;
-
-/**
- * All methods are oneway, which means they are asynchronous and non-blocking.
- * Results are returned to the callback, which has to be implemented on client side.
- */
-interface IOpenPgpService {
-
- /**
- * Sign
- *
- * After successful signing, callback's onSuccess will contain the resulting output.
- *
- * @param input
- * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri
- * @param output
- * Request output format by defining OpenPgpData object
- *
- * new OpenPgpData(OpenPgpData.TYPE_STRING)
- * Returns as String
- * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
- * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY)
- * Returns as byte[]
- * new OpenPgpData(uri)
- * Writes output to given Uri
- * new OpenPgpData(fileDescriptor)
- * Writes output to given ParcelFileDescriptor
- * @param callback
- * Callback where to return results
- */
- oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback);
-
- /**
- * Encrypt
- *
- * After successful encryption, callback's onSuccess will contain the resulting output.
- *
- * @param input
- * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri
- * @param output
- * Request output format by defining OpenPgpData object
- *
- * new OpenPgpData(OpenPgpData.TYPE_STRING)
- * Returns as String
- * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
- * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY)
- * Returns as byte[]
- * new OpenPgpData(uri)
- * Writes output to given Uri
- * new OpenPgpData(fileDescriptor)
- * Writes output to given ParcelFileDescriptor
- * @param keyIds
- * Key Ids of recipients. Can be retrieved with getKeyIds()
- * @param callback
- * Callback where to return results
- */
- oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback);
-
- /**
- * Sign then encrypt
- *
- * After successful signing and encryption, callback's onSuccess will contain the resulting output.
- *
- * @param input
- * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri
- * @param output
- * Request output format by defining OpenPgpData object
- *
- * new OpenPgpData(OpenPgpData.TYPE_STRING)
- * Returns as String
- * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
- * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY)
- * Returns as byte[]
- * new OpenPgpData(uri)
- * Writes output to given Uri
- * new OpenPgpData(fileDescriptor)
- * Writes output to given ParcelFileDescriptor
- * @param keyIds
- * Key Ids of recipients. Can be retrieved with getKeyIds()
- * @param callback
- * Callback where to return results
- */
- oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback);
-
- /**
- * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted,
- * and also signed-only input.
- *
- * After successful decryption/verification, callback's onSuccess will contain the resulting output.
- * The signatureResult in onSuccess is only non-null if signed-and-encrypted or signed-only inputBytes were given.
- *
- * @param input
- * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri
- * @param output
- * Request output format by defining OpenPgpData object
- *
- * new OpenPgpData(OpenPgpData.TYPE_STRING)
- * Returns as String
- * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
- * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY)
- * Returns as byte[]
- * new OpenPgpData(uri)
- * Writes output to given Uri
- * new OpenPgpData(fileDescriptor)
- * Writes output to given ParcelFileDescriptor
- * @param callback
- * Callback where to return results
- */
- oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback);
-
- /**
- * Get available key ids based on given user ids
- *
- * @param ids
- * User Ids (emails) of recipients OR key ids
- * @param allowUserInteraction
- * Enable user interaction to lookup and import unknown keys
- * @param callback
- * Callback where to return results (different type than callback in other functions!)
- */
- oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback);
-
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpData.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpData.aidl
deleted file mode 100644
index 3711e4fb4..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpData.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-// Declare OpenPgpData so AIDL can find it and knows that it implements the parcelable protocol.
-parcelable OpenPgpData; \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl
deleted file mode 100644
index 7a6bed1e6..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-// Declare OpenPgpError so AIDL can find it and knows that it implements the parcelable protocol.
-parcelable OpenPgpError; \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl b/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl
deleted file mode 100644
index e246792d0..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-// Declare OpenPgpSignatureResult so AIDL can find it and knows that it implements the parcelable protocol.
-parcelable OpenPgpSignatureResult; \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiCallback.aidl b/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiCallback.aidl
deleted file mode 100644
index f69f66fd7..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.sufficientlysecure.keychain.service.remote;
-
-interface IExtendedApiCallback {
-
- oneway void onSuccess(in byte[] outputBytes);
-
- oneway void onError(in String error);
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiService.aidl b/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiService.aidl
deleted file mode 100644
index 669bd31b5..000000000
--- a/OpenPGP-Keychain/src/main/aidl/org/sufficientlysecure/keychain/service/remote/IExtendedApiService.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.sufficientlysecure.keychain.service.remote;
-
-import org.sufficientlysecure.keychain.service.remote.IExtendedApiCallback;
-
-/**
- * All methods are oneway, which means they are asynchronous and non-blocking.
- * Results are returned to the callback, which has to be implemented on client side.
- */
-interface IExtendedApiService {
-
- /**
- * Symmetric Encrypt
- *
- * @param inputBytes
- * Byte array you want to encrypt
- * @param passphrase
- * symmetric passhprase
- * @param callback
- * Callback where to return results
- */
- oneway void encrypt(in byte[] inputBytes, in String passphrase, in IExtendedApiCallback callback);
-
- /**
- * Generates self signed X509 certificate signed by OpenPGP private key (from app settings)
- *
- * @param subjAltNameURI
- * @param callback
- * Callback where to return results
- */
- oneway void selfSignedX509Cert(in String subjAltNameURI, in IExtendedApiCallback callback);
-
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpConstants.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpConstants.java
deleted file mode 100644
index b1ca1bfe6..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpConstants.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.openintents.openpgp;
-
-public class OpenPgpConstants {
-
- public static final String TAG = "OpenPgp API";
-
- public static final int REQUIRED_API_VERSION = 1;
- public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpData.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpData.java
deleted file mode 100644
index 6615c2146..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpData.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-
-public class OpenPgpData implements Parcelable {
- public static final int TYPE_STRING = 0;
- public static final int TYPE_BYTE_ARRAY = 1;
- public static final int TYPE_FILE_DESCRIPTOR = 2;
- public static final int TYPE_URI = 3;
-
- int type;
-
- String string;
- byte[] bytes = new byte[0];
- ParcelFileDescriptor fileDescriptor;
- Uri uri;
-
- public int getType() {
- return type;
- }
-
- public String getString() {
- return string;
- }
-
- public byte[] getBytes() {
- return bytes;
- }
-
- public ParcelFileDescriptor getFileDescriptor() {
- return fileDescriptor;
- }
-
- public Uri getUri() {
- return uri;
- }
-
- public OpenPgpData() {
-
- }
-
- /**
- * Not a real constructor. This can be used to define requested output type.
- *
- * @param type
- */
- public OpenPgpData(int type) {
- this.type = type;
- }
-
- public OpenPgpData(String string) {
- this.string = string;
- this.type = TYPE_STRING;
- }
-
- public OpenPgpData(byte[] bytes) {
- this.bytes = bytes;
- this.type = TYPE_BYTE_ARRAY;
- }
-
- public OpenPgpData(ParcelFileDescriptor fileDescriptor) {
- this.fileDescriptor = fileDescriptor;
- this.type = TYPE_FILE_DESCRIPTOR;
- }
-
- public OpenPgpData(Uri uri) {
- this.uri = uri;
- this.type = TYPE_URI;
- }
-
- public OpenPgpData(OpenPgpData b) {
- this.string = b.string;
- this.bytes = b.bytes;
- this.fileDescriptor = b.fileDescriptor;
- this.uri = b.uri;
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(type);
- dest.writeString(string);
- dest.writeInt(bytes.length);
- dest.writeByteArray(bytes);
- dest.writeParcelable(fileDescriptor, 0);
- dest.writeParcelable(uri, 0);
- }
-
- public static final Creator<OpenPgpData> CREATOR = new Creator<OpenPgpData>() {
- public OpenPgpData createFromParcel(final Parcel source) {
- OpenPgpData vr = new OpenPgpData();
- vr.type = source.readInt();
- vr.string = source.readString();
- vr.bytes = new byte[source.readInt()];
- source.readByteArray(vr.bytes);
- vr.fileDescriptor = source.readParcelable(ParcelFileDescriptor.class.getClassLoader());
- vr.fileDescriptor = source.readParcelable(Uri.class.getClassLoader());
- return vr;
- }
-
- public OpenPgpData[] newArray(final int size) {
- return new OpenPgpData[size];
- }
- };
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpError.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpError.java
deleted file mode 100644
index f108d3169..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpError.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class OpenPgpError implements Parcelable {
- public static final int GENERIC_ERROR = 0;
- public static final int NO_OR_WRONG_PASSPHRASE = 1;
- public static final int NO_USER_IDS = 2;
- public static final int USER_INTERACTION_REQUIRED = 3;
-
- int errorId;
- String message;
-
- public OpenPgpError() {
- }
-
- public OpenPgpError(int errorId, String message) {
- this.errorId = errorId;
- this.message = message;
- }
-
- public OpenPgpError(OpenPgpError b) {
- this.errorId = b.errorId;
- this.message = b.message;
- }
-
- public int getErrorId() {
- return errorId;
- }
-
- public void setErrorId(int errorId) {
- this.errorId = errorId;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(errorId);
- dest.writeString(message);
- }
-
- public static final Creator<OpenPgpError> CREATOR = new Creator<OpenPgpError>() {
- public OpenPgpError createFromParcel(final Parcel source) {
- OpenPgpError error = new OpenPgpError();
- error.errorId = source.readInt();
- error.message = source.readString();
- return error;
- }
-
- public OpenPgpError[] newArray(final int size) {
- return new OpenPgpError[size];
- }
- };
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpHelper.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpHelper.java
deleted file mode 100644
index 7305c47ce..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpHelper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-
-public class OpenPgpHelper {
- private Context context;
-
- public static Pattern PGP_MESSAGE = Pattern.compile(
- ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
-
- public static Pattern PGP_SIGNED_MESSAGE = Pattern
- .compile(
- ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
- Pattern.DOTALL);
-
- public OpenPgpHelper(Context context) {
- super();
- this.context = context;
- }
-
- public boolean isAvailable() {
- Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT);
- List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);
- if (!resInfo.isEmpty()) {
- return true;
- } else {
- return false;
- }
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java
deleted file mode 100644
index 4ddd97485..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.AlertDialog.Builder;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.graphics.drawable.Drawable;
-import android.preference.DialogPreference;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-public class OpenPgpListPreference extends DialogPreference {
- ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>();
- private String mSelectedPackage;
-
- public OpenPgpListPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(
- new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA);
- if (!resInfo.isEmpty()) {
- for (ResolveInfo resolveInfo : resInfo) {
- if (resolveInfo.serviceInfo == null)
- continue;
-
- String packageName = resolveInfo.serviceInfo.packageName;
- String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context
- .getPackageManager()));
- Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager());
-
- // get api version
- ServiceInfo si = resolveInfo.serviceInfo;
- int apiVersion = si.metaData.getInt("api_version");
-
- mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon,
- apiVersion));
- }
- }
- }
-
- public OpenPgpListPreference(Context context) {
- this(context, null);
- }
-
- /**
- * Can be used to add "no selection"
- *
- * @param packageName
- * @param simpleName
- * @param icon
- */
- public void addProvider(int position, String packageName, String simpleName, Drawable icon,
- int apiVersion) {
- mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon,
- apiVersion));
- }
-
- @Override
- protected void onPrepareDialogBuilder(Builder builder) {
- // Init ArrayAdapter with OpenPGP Providers
- ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
- android.R.layout.select_dialog_singlechoice, android.R.id.text1, mProviderList) {
- public View getView(int position, View convertView, ViewGroup parent) {
- // User super class to create the View
- View v = super.getView(position, convertView, parent);
- TextView tv = (TextView) v.findViewById(android.R.id.text1);
-
- // Put the image on the TextView
- tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null,
- null, null);
-
- // Add margin between image and text (support various screen densities)
- int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f);
- tv.setCompoundDrawablePadding(dp10);
-
- // disable if it has the wrong api_version
- if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_API_VERSION) {
- tv.setEnabled(true);
- } else {
- tv.setEnabled(false);
- tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion
- + ", needs v" + OpenPgpConstants.REQUIRED_API_VERSION + ")");
- }
-
- return v;
- }
- };
-
- builder.setSingleChoiceItems(adapter, getIndexOfProviderList(getValue()),
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mSelectedPackage = mProviderList.get(which).packageName;
-
- /*
- * Clicking on an item simulates the positive button click, and dismisses
- * the dialog.
- */
- OpenPgpListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
- dialog.dismiss();
- }
- });
-
- /*
- * The typical interaction for list-based dialogs is to have click-on-an-item dismiss the
- * dialog instead of the user having to press 'Ok'.
- */
- builder.setPositiveButton(null, null);
- }
-
- @Override
- protected void onDialogClosed(boolean positiveResult) {
- super.onDialogClosed(positiveResult);
-
- if (positiveResult && (mSelectedPackage != null)) {
- if (callChangeListener(mSelectedPackage)) {
- setValue(mSelectedPackage);
- }
- }
- }
-
- private int getIndexOfProviderList(String packageName) {
- for (OpenPgpProviderEntry app : mProviderList) {
- if (app.packageName.equals(packageName)) {
- return mProviderList.indexOf(app);
- }
- }
-
- return -1;
- }
-
- public void setValue(String packageName) {
- mSelectedPackage = packageName;
- persistString(packageName);
- }
-
- public String getValue() {
- return mSelectedPackage;
- }
-
- public String getEntry() {
- return getEntryByValue(mSelectedPackage);
- }
-
- public String getEntryByValue(String packageName) {
- for (OpenPgpProviderEntry app : mProviderList) {
- if (app.packageName.equals(packageName)) {
- return app.simpleName;
- }
- }
-
- return null;
- }
-
- private static class OpenPgpProviderEntry {
- private String packageName;
- private String simpleName;
- private Drawable icon;
- private int apiVersion;
-
- public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon,
- int apiVersion) {
- this.packageName = packageName;
- this.simpleName = simpleName;
- this.icon = icon;
- this.apiVersion = apiVersion;
- }
-
- @Override
- public String toString() {
- return simpleName;
- }
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java
deleted file mode 100644
index f7ba06aaf..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import org.openintents.openpgp.IOpenPgpService;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.util.Log;
-
-public class OpenPgpServiceConnection {
- private Context mApplicationContext;
-
- private IOpenPgpService mService;
- private boolean mBound;
- private String mCryptoProviderPackageName;
-
- public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) {
- this.mApplicationContext = context.getApplicationContext();
- this.mCryptoProviderPackageName = cryptoProviderPackageName;
- }
-
- public IOpenPgpService getService() {
- return mService;
- }
-
- public boolean isBound() {
- return mBound;
- }
-
- private ServiceConnection mCryptoServiceConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IOpenPgpService.Stub.asInterface(service);
- Log.d(OpenPgpConstants.TAG, "connected to service");
- mBound = true;
- }
-
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- Log.d(OpenPgpConstants.TAG, "disconnected from service");
- mBound = false;
- }
- };
-
- /**
- * If not already bound, bind!
- *
- * @return
- */
- public boolean bindToService() {
- if (mService == null && !mBound) { // if not already connected
- try {
- Log.d(OpenPgpConstants.TAG, "not bound yet");
-
- Intent serviceIntent = new Intent();
- serviceIntent.setAction(IOpenPgpService.class.getName());
- serviceIntent.setPackage(mCryptoProviderPackageName);
- mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection,
- Context.BIND_AUTO_CREATE);
-
- return true;
- } catch (Exception e) {
- Log.d(OpenPgpConstants.TAG, "Exception on binding", e);
- return false;
- }
- } else {
- Log.d(OpenPgpConstants.TAG, "already bound");
- return true;
- }
- }
-
- public void unbindFromService() {
- mApplicationContext.unbindService(mCryptoServiceConnection);
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java
deleted file mode 100644
index 829f8f8cf..000000000
--- a/OpenPGP-Keychain/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.openintents.openpgp;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class OpenPgpSignatureResult implements Parcelable {
- // generic error on signature verification
- public static final int SIGNATURE_ERROR = 0;
- // successfully verified signature, with trusted public key
- public static final int SIGNATURE_SUCCESS_TRUSTED = 1;
- // no public key was found for this signature verification
- // you can retrieve the key with
- // getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback)
- public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;
- // successfully verified signature, but with untrusted public key
- public static final int SIGNATURE_SUCCESS_UNTRUSTED = 3;
-
- int status;
- boolean signatureOnly;
- String userId;
- long keyId;
-
- public int getStatus() {
- return status;
- }
-
- public boolean isSignatureOnly() {
- return signatureOnly;
- }
-
- public String getUserId() {
- return userId;
- }
-
- public long getKeyId() {
- return keyId;
- }
-
- public OpenPgpSignatureResult() {
-
- }
-
- public OpenPgpSignatureResult(int signatureStatus, String signatureUserId,
- boolean signatureOnly, long keyId) {
- this.status = signatureStatus;
- this.signatureOnly = signatureOnly;
- this.userId = signatureUserId;
- this.keyId = keyId;
- }
-
- public OpenPgpSignatureResult(OpenPgpSignatureResult b) {
- this.status = b.status;
- this.userId = b.userId;
- this.signatureOnly = b.signatureOnly;
- this.keyId = b.keyId;
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(status);
- dest.writeByte((byte) (signatureOnly ? 1 : 0));
- dest.writeString(userId);
- dest.writeLong(keyId);
- }
-
- public static final Creator<OpenPgpSignatureResult> CREATOR = new Creator<OpenPgpSignatureResult>() {
- public OpenPgpSignatureResult createFromParcel(final Parcel source) {
- OpenPgpSignatureResult vr = new OpenPgpSignatureResult();
- vr.status = source.readInt();
- vr.signatureOnly = source.readByte() == 1;
- vr.userId = source.readString();
- vr.keyId = source.readLong();
- return vr;
- }
-
- public OpenPgpSignatureResult[] newArray(final int size) {
- return new OpenPgpSignatureResult[size];
- }
- };
-
- @Override
- public String toString() {
- String out = new String();
- out += "\nstatus: " + status;
- out += "\nuserId: " + userId;
- out += "\nsignatureOnly: " + signatureOnly;
- out += "\nkeyId: " + keyId;
- return out;
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
index 22f30cb1f..a1571e491 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
@@ -78,7 +78,7 @@ public final class Id {
public static final int filename = 0x00007003;
// public static final int output_filename = 0x00007004;
public static final int key_server_preference = 0x00007005;
- public static final int look_up_key_id = 0x00007006;
+// public static final int look_up_key_id = 0x00007006;
public static final int export_to_server = 0x00007007;
public static final int import_from_qr_code = 0x00007008;
public static final int sign_key = 0x00007009;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
new file mode 100644
index 000000000..fb97f3a5c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.pgp;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import org.spongycastle.bcpg.ArmoredInputStream;
+import org.spongycastle.bcpg.SignatureSubpacketTags;
+import org.spongycastle.openpgp.PGPCompressedData;
+import org.spongycastle.openpgp.PGPEncryptedData;
+import org.spongycastle.openpgp.PGPEncryptedDataList;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPLiteralData;
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPOnePassSignature;
+import org.spongycastle.openpgp.PGPOnePassSignatureList;
+import org.spongycastle.openpgp.PGPPBEEncryptedData;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.util.InputData;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SignatureException;
+import java.util.Iterator;
+
+/**
+ * This class uses a Builder pattern!
+ */
+public class PgpDecryptVerify {
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ private ProgressDialogUpdater progress;
+ boolean assumeSymmetric;
+ String passphrase;
+
+ private PgpDecryptVerify(Builder builder) {
+ // private Constructor can only be called from Builder
+ this.context = builder.context;
+ this.data = builder.data;
+ this.outStream = builder.outStream;
+
+ this.progress = builder.progress;
+ this.assumeSymmetric = builder.assumeSymmetric;
+ this.passphrase = builder.passphrase;
+ }
+
+ public static class Builder {
+ // mandatory parameter
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ // optional
+ private ProgressDialogUpdater progress = null;
+ private boolean assumeSymmetric = false;
+ private String passphrase = "";
+
+ public Builder(Context context, InputData data, OutputStream outStream) {
+ this.context = context;
+ this.data = data;
+ this.outStream = outStream;
+ }
+
+ public Builder progress(ProgressDialogUpdater progress) {
+ this.progress = progress;
+ return this;
+ }
+
+ public Builder assumeSymmetric(boolean assumeSymmetric) {
+ this.assumeSymmetric = assumeSymmetric;
+ return this;
+ }
+
+ public Builder passphrase(String passphrase) {
+ this.passphrase = passphrase;
+ return this;
+ }
+
+ public PgpDecryptVerify build() {
+ return new PgpDecryptVerify(this);
+ }
+ }
+
+ public void updateProgress(int message, int current, int total) {
+ if (progress != null) {
+ progress.setProgress(message, current, total);
+ }
+ }
+
+ public void updateProgress(int current, int total) {
+ if (progress != null) {
+ progress.setProgress(current, total);
+ }
+ }
+
+ public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
+ throws PgpGeneralException, IOException {
+ InputStream in = PGPUtil.getDecoderStream(inputStream);
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+
+ // the first object might be a PGP marker packet.
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
+ }
+
+ Iterator<?> it = enc.getEncryptedDataObjects();
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Decrypts and/or verifies data based on parameters of class
+ *
+ * @return
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws SignatureException
+ */
+ public Bundle execute()
+ throws IOException, PgpGeneralException, PGPException, SignatureException {
+
+ // automatically works with ascii armor input and binary
+ InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
+ if (in instanceof ArmoredInputStream) {
+ ArmoredInputStream aIn = (ArmoredInputStream) in;
+ // it is ascii armored
+ Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
+
+ if (aIn.isClearText()) {
+ // a cleartext signature, verify it with the other method
+ return verifyCleartextSignature(aIn);
+ }
+ // else: ascii armored encryption! go on...
+ }
+
+ return decryptVerify(in);
+ }
+
+ /**
+ * Decrypt and/or verifies binary or ascii armored pgp
+ *
+ * @param in
+ * @return
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws SignatureException
+ */
+ private Bundle decryptVerify(InputStream in)
+ throws IOException, PgpGeneralException, PGPException, SignatureException {
+ Bundle returnData = new Bundle();
+
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+
+ int currentProgress = 0;
+ updateProgress(R.string.progress_reading_data, currentProgress, 100);
+
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
+ }
+
+ InputStream clear;
+ PGPEncryptedData encryptedData;
+
+ currentProgress += 5;
+
+ // TODO: currently we always only look at the first known key or symmetric encryption,
+ // there might be more...
+ if (assumeSymmetric) {
+ PGPPBEEncryptedData pbe = null;
+ Iterator<?> it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ pbe = (PGPPBEEncryptedData) obj;
+ break;
+ }
+ }
+
+ if (pbe == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_no_symmetric_encryption_packet));
+ }
+
+ updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
+
+ PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
+ PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
+ digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ passphrase.toCharArray());
+
+ clear = pbe.getDataStream(decryptorFactory);
+
+ encryptedData = pbe;
+ currentProgress += 5;
+ } else {
+ updateProgress(R.string.progress_finding_key, currentProgress, 100);
+
+ PGPPublicKeyEncryptedData pbe = null;
+ PGPSecretKey secretKey = null;
+ Iterator<?> it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPublicKeyEncryptedData) {
+ PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
+ secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
+ if (secretKey != null) {
+ pbe = encData;
+ break;
+ }
+ }
+ }
+
+ if (secretKey == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found));
+ }
+
+ currentProgress += 5;
+ updateProgress(R.string.progress_extracting_key, currentProgress, 100);
+ PGPPrivateKey privateKey = null;
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ passphrase.toCharArray());
+ privateKey = secretKey.extractPrivateKey(keyDecryptor);
+ } catch (PGPException e) {
+ throw new PGPException(context.getString(R.string.error_wrong_passphrase));
+ }
+ if (privateKey == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_could_not_extract_private_key));
+ }
+ currentProgress += 5;
+ updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
+
+ PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
+
+ clear = pbe.getDataStream(decryptorFactory);
+
+ encryptedData = pbe;
+ currentProgress += 5;
+ }
+
+ PGPObjectFactory plainFact = new PGPObjectFactory(clear);
+ Object dataChunk = plainFact.nextObject();
+ PGPOnePassSignature signature = null;
+ PGPPublicKey signatureKey = null;
+ int signatureIndex = -1;
+
+ if (dataChunk instanceof PGPCompressedData) {
+ updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
+
+ PGPObjectFactory fact = new PGPObjectFactory(
+ ((PGPCompressedData) dataChunk).getDataStream());
+ dataChunk = fact.nextObject();
+ plainFact = fact;
+ currentProgress += 10;
+ }
+
+ long signatureKeyId = 0;
+ if (dataChunk instanceof PGPOnePassSignatureList) {
+ updateProgress(R.string.progress_processing_signature, currentProgress, 100);
+
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
+ PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
+ for (int i = 0; i < sigList.size(); ++i) {
+ signature = sigList.get(i);
+ signatureKey = ProviderHelper
+ .getPGPPublicKeyByKeyId(context, signature.getKeyID());
+ if (signatureKeyId == 0) {
+ signatureKeyId = signature.getKeyID();
+ }
+ if (signatureKey == null) {
+ signature = null;
+ } else {
+ signatureIndex = i;
+ signatureKeyId = signature.getKeyID();
+ String userId = null;
+ PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(
+ context, signatureKeyId);
+ if (signKeyRing != null) {
+ userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
+ }
+ returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
+ break;
+ }
+ }
+
+ returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
+
+ if (signature != null) {
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ signature.init(contentVerifierBuilderProvider, signatureKey);
+ } else {
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
+ }
+
+ dataChunk = plainFact.nextObject();
+ currentProgress += 10;
+ }
+
+ if (dataChunk instanceof PGPSignatureList) {
+ dataChunk = plainFact.nextObject();
+ }
+
+ if (dataChunk instanceof PGPLiteralData) {
+ updateProgress(R.string.progress_decrypting, currentProgress, 100);
+
+ PGPLiteralData literalData = (PGPLiteralData) dataChunk;
+
+ byte[] buffer = new byte[1 << 16];
+ InputStream dataIn = literalData.getInputStream();
+
+ int startProgress = currentProgress;
+ int endProgress = 100;
+ if (signature != null) {
+ endProgress = 90;
+ } else if (encryptedData.isIntegrityProtected()) {
+ endProgress = 95;
+ }
+
+ int n;
+ // TODO: progress calculation is broken here! Try to rework it based on commented code!
+// int progress = 0;
+ long startPos = data.getStreamPosition();
+ while ((n = dataIn.read(buffer)) > 0) {
+ outStream.write(buffer, 0, n);
+// progress += n;
+ if (signature != null) {
+ try {
+ signature.update(buffer, 0, n);
+ } catch (SignatureException e) {
+ returnData
+ .putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
+ signature = null;
+ }
+ }
+ // TODO: dead code?!
+ // unknown size, but try to at least have a moving, slowing down progress bar
+// currentProgress = startProgress + (endProgress - startProgress) * progress
+// / (progress + 100000);
+ if (data.getSize() - startPos == 0) {
+ currentProgress = endProgress;
+ } else {
+ currentProgress = (int) (startProgress + (endProgress - startProgress)
+ * (data.getStreamPosition() - startPos) / (data.getSize() - startPos));
+ }
+ updateProgress(currentProgress, 100);
+ }
+
+ if (signature != null) {
+ updateProgress(R.string.progress_verifying_signature, 90, 100);
+
+ PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
+ PGPSignature messageSignature = signatureList.get(signatureIndex);
+
+ // these are not cleartext signatures!
+ returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
+
+ //Now check binding signatures
+ boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey);
+ boolean sig_isok = signature.verify(messageSignature);
+
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok);
+ }
+ }
+
+ // TODO: test if this integrity really check works!
+ if (encryptedData.isIntegrityProtected()) {
+ updateProgress(R.string.progress_verifying_integrity, 95, 100);
+
+ if (encryptedData.verify()) {
+ // passed
+ Log.d(Constants.TAG, "Integrity verification: success!");
+ } else {
+ // failed
+ Log.d(Constants.TAG, "Integrity verification: failed!");
+ throw new PgpGeneralException(context.getString(R.string.error_integrity_check_failed));
+ }
+ } else {
+ // no integrity check
+ Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
+ }
+
+ updateProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ /**
+ * This method verifies cleartext signatures
+ * as defined in http://tools.ietf.org/html/rfc4880#section-7
+ * <p/>
+ * The method is heavily based on
+ * pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
+ *
+ * @return
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws SignatureException
+ */
+ private Bundle verifyCleartextSignature(ArmoredInputStream aIn)
+ throws IOException, PgpGeneralException, PGPException, SignatureException {
+ Bundle returnData = new Bundle();
+ // cleartext signatures are never encrypted ;)
+ returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ updateProgress(R.string.progress_done, 0, 100);
+
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
+
+ byte[] line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+
+ while (lookAhead != -1 && aIn.isClearText()) {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+ }
+
+ out.close();
+
+ byte[] clearText = out.toByteArray();
+ outStream.write(clearText);
+
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
+
+ updateProgress(R.string.progress_processing_signature, 60, 100);
+ PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
+
+ PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
+ if (sigList == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_corrupt_data));
+ }
+ PGPSignature signature = null;
+ long signatureKeyId = 0;
+ PGPPublicKey signatureKey = null;
+ for (int i = 0; i < sigList.size(); ++i) {
+ signature = sigList.get(i);
+ signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(context, signature.getKeyID());
+ if (signatureKeyId == 0) {
+ signatureKeyId = signature.getKeyID();
+ }
+
+ if (signatureKey == null) {
+ signature = null;
+ } else {
+ signatureKeyId = signature.getKeyID();
+ String userId = null;
+ PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
+ signatureKeyId);
+ if (signKeyRing != null) {
+ userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
+ }
+ returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
+ break;
+ }
+ }
+
+ returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
+
+ if (signature == null) {
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
+ updateProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ signature.init(contentVerifierBuilderProvider, signatureKey);
+
+ InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
+
+ lookAhead = readInputLine(lineOut, sigIn);
+
+ processLine(signature, lineOut.toByteArray());
+
+ if (lookAhead != -1) {
+ do {
+ lookAhead = readInputLine(lineOut, lookAhead, sigIn);
+
+ signature.update((byte) '\r');
+ signature.update((byte) '\n');
+
+ processLine(signature, lineOut.toByteArray());
+ } while (lookAhead != -1);
+ }
+
+ boolean sig_isok = signature.verify();
+
+ //Now check binding signatures
+ boolean keyBinding_isok = verifyKeyBinding(context, signature, signatureKey);
+
+ returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok);
+
+ updateProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
+ long signatureKeyId = signature.getKeyID();
+ boolean keyBinding_isok = false;
+ String userId = null;
+ PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
+ signatureKeyId);
+ PGPPublicKey mKey = null;
+ if (signKeyRing != null) {
+ mKey = PgpKeyHelper.getMasterKey(signKeyRing);
+ }
+ if (signature.getKeyID() != mKey.getKeyID()) {
+ keyBinding_isok = verifyKeyBinding(mKey, signatureKey);
+ } else { //if the key used to make the signature was the master key, no need to check binding sigs
+ keyBinding_isok = true;
+ }
+ return keyBinding_isok;
+ }
+
+ private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
+ boolean subkeyBinding_isok = false;
+ boolean tmp_subkeyBinding_isok = false;
+ boolean primkeyBinding_isok = false;
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
+
+ subkeyBinding_isok = false;
+ tmp_subkeyBinding_isok = false;
+ primkeyBinding_isok = false;
+ while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
+ //gpg has an invalid subkey binding error on key import I think, but doesn't shout
+ //about keys without subkey signing. Can't get it to import a slightly broken one
+ //either, so we will err on bad subkey binding here.
+ PGPSignature sig = itr.next();
+ if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
+ //check and if ok, check primary key binding.
+ try {
+ sig.init(contentVerifierBuilderProvider, masterPublicKey);
+ tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey);
+ } catch (PGPException e) {
+ continue;
+ } catch (SignatureException e) {
+ continue;
+ }
+
+ if (tmp_subkeyBinding_isok)
+ subkeyBinding_isok = true;
+ if (tmp_subkeyBinding_isok) {
+ primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey);
+ if (primkeyBinding_isok)
+ break;
+ primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey);
+ if (primkeyBinding_isok)
+ break;
+ }
+ }
+ }
+ return (subkeyBinding_isok & primkeyBinding_isok);
+ }
+
+ private static boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
+ boolean primkeyBinding_isok = false;
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ PGPSignatureList eSigList;
+
+ if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
+ try {
+ eSigList = Pkts.getEmbeddedSignatures();
+ } catch (IOException e) {
+ return false;
+ } catch (PGPException e) {
+ return false;
+ }
+ for (int j = 0; j < eSigList.size(); ++j) {
+ PGPSignature emSig = eSigList.get(j);
+ if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
+ try {
+ emSig.init(contentVerifierBuilderProvider, signingPublicKey);
+ primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey);
+ if (primkeyBinding_isok)
+ break;
+ } catch (PGPException e) {
+ continue;
+ } catch (SignatureException e) {
+ continue;
+ }
+ }
+ }
+ }
+ return primkeyBinding_isok;
+ }
+
+ /**
+ * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
+ *
+ * @param sig
+ * @param line
+ * @throws SignatureException
+ * @throws IOException
+ */
+ private static void processLine(PGPSignature sig, byte[] line)
+ throws SignatureException, IOException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0) {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ } while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0) {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n') {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ private static int getLengthWithoutSeparator(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isLineEnding(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isLineEnding(byte b) {
+ return b == '\r' || b == '\n';
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+ private static byte[] getLineSeparator() {
+ String nl = System.getProperty("line.separator");
+ byte[] nlBytes = new byte[nl.length()];
+
+ for (int i = 0; i != nlBytes.length; i++) {
+ nlBytes[i] = (byte) nl.charAt(i);
+ }
+
+ return nlBytes;
+ }
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
index 78d42cbf9..c1c6f3088 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
@@ -42,6 +42,8 @@ import android.content.Context;
public class PgpKeyHelper {
+ private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
+
public static Date getCreationDate(PGPPublicKey key) {
return key.getCreationTime();
}
@@ -591,8 +593,7 @@ public class PgpKeyHelper {
* "Max Mustermann (this is a comment)"
* "Max Mustermann [this is nothing]"
*/
- Pattern withComment = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
- Matcher matcher = withComment.matcher(userId);
+ Matcher matcher = USER_ID_PATTERN.matcher(userId);
if (matcher.matches()) {
result[0] = matcher.group(1);
result[1] = matcher.group(3);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index 6055aebfc..80831d35f 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -504,7 +504,7 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_done, 100, 100);
}
- public PGPPublicKeyRing signKey(long masterKeyId, long pubKeyId, String passphrase)
+ public PGPPublicKeyRing certifyKey(long masterKeyId, long pubKeyId, String passphrase)
throws PgpGeneralException, PGPException, SignatureException {
if (passphrase == null) {
throw new PgpGeneralException("Unable to obtain passphrase");
@@ -512,14 +512,14 @@ public class PgpKeyOperation {
PGPPublicKeyRing pubring = ProviderHelper
.getPGPPublicKeyRingByKeyId(mContext, pubKeyId);
- PGPSecretKey signingKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId);
- if (signingKey == null) {
+ PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId);
+ if (certificationKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_could_not_extract_private_key));
@@ -527,7 +527,7 @@ public class PgpKeyOperation {
// TODO: SHA256 fixed?
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- signingKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
+ certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java
deleted file mode 100644
index 1402be435..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java
+++ /dev/null
@@ -1,1154 +0,0 @@
-/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.sufficientlysecure.keychain.pgp;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.SignatureException;
-import java.util.Date;
-import java.util.Iterator;
-
-import org.spongycastle.bcpg.ArmoredInputStream;
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.BCPGInputStream;
-import org.spongycastle.bcpg.BCPGOutputStream;
-
-import org.spongycastle.bcpg.SignaturePacket;
-
-import org.spongycastle.bcpg.SignatureSubpacket;
-import org.spongycastle.bcpg.SignatureSubpacketTags;
-import org.spongycastle.openpgp.PGPCompressedData;
-import org.spongycastle.openpgp.PGPCompressedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedData;
-import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedDataList;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPLiteralDataGenerator;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPOnePassSignature;
-import org.spongycastle.openpgp.PGPOnePassSignatureList;
-import org.spongycastle.openpgp.PGPPBEEncryptedData;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPSignatureList;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
-import org.spongycastle.openpgp.PGPUtil;
-import org.spongycastle.openpgp.PGPV3SignatureGenerator;
-import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
-import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-import android.content.Context;
-import android.os.Bundle;
-
-public class PgpOperation {
- private Context mContext;
- private ProgressDialogUpdater mProgress;
- private InputData mData;
- private OutputStream mOutStream;
-
- public PgpOperation(Context context, ProgressDialogUpdater progress, InputData data,
- OutputStream outStream) {
- super();
- this.mContext = context;
- this.mProgress = progress;
- this.mData = data;
- this.mOutStream = outStream;
- }
-
- public void updateProgress(int message, int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(message, current, total);
- }
- }
-
- public void updateProgress(int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(current, total);
- }
- }
-
- public void signAndEncrypt(boolean useAsciiArmor, int compression, long[] encryptionKeyIds,
- String encryptionPassphrase, int symmetricEncryptionAlgorithm, long signatureKeyId,
- int signatureHashAlgorithm, boolean signatureForceV3, String signaturePassphrase)
- throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
- NoSuchAlgorithmException, SignatureException {
-
- if (encryptionKeyIds == null) {
- encryptionKeyIds = new long[0];
- }
-
- ArmoredOutputStream armorOut = null;
- OutputStream out = null;
- OutputStream encryptOut = null;
- if (useAsciiArmor) {
- armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (encryptionKeyIds.length == 0 && encryptionPassphrase == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_no_encryption_keys_or_passphrase));
- }
-
- if (signatureKeyId != Id.key.none) {
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (signaturePassphrase == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_no_signature_passphrase));
- }
-
- updateProgress(R.string.progress_extracting_signature_key, 0, 100);
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- }
- updateProgress(R.string.progress_preparing_streams, 5, 100);
-
- // encrypt and compress input file content
- JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(
- symmetricEncryptionAlgorithm).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
- .setWithIntegrityPacket(true);
-
- PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
-
- if (encryptionKeyIds.length == 0) {
- // Symmetric encryption
- Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
-
- JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = new JcePBEKeyEncryptionMethodGenerator(
- encryptionPassphrase.toCharArray());
- cPk.addMethod(symmetricEncryptionGenerator);
- } else {
- // Asymmetric encryption
- for (long id : encryptionKeyIds) {
- PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
- if (key != null) {
-
- JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = new JcePublicKeyKeyEncryptionMethodGenerator(
- key);
- cPk.addMethod(pubKeyEncryptionGenerator);
- }
- }
- }
- encryptOut = cPk.open(out, new byte[1 << 16]);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- if (signatureKeyId != Id.key.none) {
- updateProgress(R.string.progress_preparing_signature, 10, 100);
-
- // content signer based on signing key algorithm and choosen hash algorithm
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- if (signatureForceV3) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
-
- String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper
- .getMasterKey(signingKeyRing));
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
- }
-
- PGPCompressedDataGenerator compressGen = null;
- BCPGOutputStream bcpgOut = null;
- if (compression == Id.choice.compression.none) {
- bcpgOut = new BCPGOutputStream(encryptOut);
- } else {
- compressGen = new PGPCompressedDataGenerator(compression);
- bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
- }
- if (signatureKeyId != Id.key.none) {
- if (signatureForceV3) {
- signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
- } else {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
- }
-
- PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
- // file name not needed, so empty string
- OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
- new byte[1 << 16]);
- updateProgress(R.string.progress_encrypting, 20, 100);
-
- long done = 0;
- int n = 0;
- byte[] buffer = new byte[1 << 16];
- InputStream in = mData.getInputStream();
- while ((n = in.read(buffer)) > 0) {
- pOut.write(buffer, 0, n);
- if (signatureKeyId != Id.key.none) {
- if (signatureForceV3) {
- signatureV3Generator.update(buffer, 0, n);
- } else {
- signatureGenerator.update(buffer, 0, n);
- }
- }
- done += n;
- if (mData.getSize() != 0) {
- updateProgress((int) (20 + (95 - 20) * done / mData.getSize()), 100);
- }
- }
-
- literalGen.close();
-
- if (signatureKeyId != Id.key.none) {
- updateProgress(R.string.progress_generating_signature, 95, 100);
- if (signatureForceV3) {
- signatureV3Generator.generate().encode(pOut);
- } else {
- signatureGenerator.generate().encode(pOut);
- }
- }
- if (compressGen != null) {
- compressGen.close();
- }
- encryptOut.close();
- if (useAsciiArmor) {
- armorOut.close();
- }
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
- public void signText(long signatureKeyId, String signaturePassphrase,
- int signatureHashAlgorithm, boolean forceV3Signature) throws PgpGeneralException,
- PGPException, IOException, NoSuchAlgorithmException, SignatureException {
-
- ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
-
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (signatureKeyId == 0) {
- armorOut.close();
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
- }
-
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
- if (signingKey == null) {
- armorOut.close();
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (signaturePassphrase == null) {
- armorOut.close();
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
- }
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- armorOut.close();
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- updateProgress(R.string.progress_preparing_streams, 0, 100);
-
- updateProgress(R.string.progress_preparing_signature, 30, 100);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- // content signer based on signing key algorithm and choosen hash algorithm
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
- .getPublicKey().getAlgorithm(), signatureHashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- if (forceV3Signature) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
-
- updateProgress(R.string.progress_signing, 40, 100);
-
- armorOut.beginClearText(signatureHashAlgorithm);
-
- InputStream inStream = mData.getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
-
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- if (forceV3Signature) {
- processLine(reader.readLine(), armorOut, signatureV3Generator);
- } else {
- processLine(reader.readLine(), armorOut, signatureGenerator);
- }
-
- while (true) {
- final String line = reader.readLine();
-
- if (line == null) {
- armorOut.write(newline);
- break;
- }
-
- armorOut.write(newline);
- if (forceV3Signature) {
- signatureV3Generator.update(newline);
- processLine(line, armorOut, signatureV3Generator);
- } else {
- signatureGenerator.update(newline);
- processLine(line, armorOut, signatureGenerator);
- }
- }
-
- armorOut.endClearText();
-
- BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- armorOut.close();
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
- public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
- String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
- throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
- SignatureException {
-
- OutputStream out = null;
-
- // Ascii Armor (Base64)
- ArmoredOutputStream armorOut = null;
- if (armored) {
- armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
-
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (signatureKeyId == 0) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
- }
-
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (signaturePassPhrase == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
- }
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- updateProgress(R.string.progress_preparing_streams, 0, 100);
-
- updateProgress(R.string.progress_preparing_signature, 30, 100);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
- if (binary) {
- type = PGPSignature.BINARY_DOCUMENT;
- }
-
- // content signer based on signing key algorithm and choosen hash algorithm
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
- .getPublicKey().getAlgorithm(), hashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- if (forceV3Signature) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(type, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(type, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
-
- updateProgress(R.string.progress_signing, 40, 100);
-
- InputStream inStream = mData.getInputStream();
- if (binary) {
- byte[] buffer = new byte[1 << 16];
- int n = 0;
- while ((n = inStream.read(buffer)) > 0) {
- if (forceV3Signature) {
- signatureV3Generator.update(buffer, 0, n);
- } else {
- signatureGenerator.update(buffer, 0, n);
- }
- }
- } else {
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- while (true) {
- final String line = reader.readLine();
-
- if (line == null) {
- break;
- }
-
- if (forceV3Signature) {
- processLine(line, null, signatureV3Generator);
- signatureV3Generator.update(newline);
- } else {
- processLine(line, null, signatureGenerator);
- signatureGenerator.update(newline);
- }
- }
- }
-
- BCPGOutputStream bOut = new BCPGOutputStream(out);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- out.close();
- mOutStream.close();
-
- if (mProgress != null)
- mProgress.setProgress(R.string.progress_done, 100, 100);
- }
-
- public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
- throws PgpGeneralException, IOException {
- InputStream in = PGPUtil.getDecoderStream(inputStream);
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
-
- // the first object might be a PGP marker packet.
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
- }
-
- Iterator<?> it = enc.getEncryptedDataObjects();
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPBEEncryptedData) {
- return true;
- }
- }
-
- return false;
- }
-
- public Bundle decryptAndVerify(String passphrase, boolean assumeSymmetric) throws IOException,
- PgpGeneralException, PGPException, SignatureException {
- if (passphrase == null) {
- passphrase = "";
- }
-
- Bundle returnData = new Bundle();
- InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
- long signatureKeyId = 0;
-
- int currentProgress = 0;
- updateProgress(R.string.progress_reading_data, currentProgress, 100);
-
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
- }
-
- InputStream clear = null;
- PGPEncryptedData encryptedData = null;
-
- currentProgress += 5;
-
- // TODO: currently we always only look at the first known key or symmetric encryption,
- // there might be more...
- if (assumeSymmetric) {
- PGPPBEEncryptedData pbe = null;
- Iterator<?> it = enc.getEncryptedDataObjects();
- // find secret key
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPBEEncryptedData) {
- pbe = (PGPPBEEncryptedData) obj;
- break;
- }
- }
-
- if (pbe == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_no_symmetric_encryption_packet));
- }
-
- updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
-
- PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
- PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
- digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.toCharArray());
-
- clear = pbe.getDataStream(decryptorFactory);
-
- encryptedData = pbe;
- currentProgress += 5;
- } else {
- updateProgress(R.string.progress_finding_key, currentProgress, 100);
-
- PGPPublicKeyEncryptedData pbe = null;
- PGPSecretKey secretKey = null;
- Iterator<?> it = enc.getEncryptedDataObjects();
- // find secret key
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPublicKeyEncryptedData) {
- PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- secretKey = ProviderHelper.getPGPSecretKeyByKeyId(mContext, encData.getKeyID());
- if (secretKey != null) {
- pbe = encData;
- break;
- }
- }
- }
-
- if (secretKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
- }
-
- currentProgress += 5;
- updateProgress(R.string.progress_extracting_key, currentProgress, 100);
- PGPPrivateKey privateKey = null;
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.toCharArray());
- privateKey = secretKey.extractPrivateKey(keyDecryptor);
- } catch (PGPException e) {
- throw new PGPException(mContext.getString(R.string.error_wrong_passphrase));
- }
- if (privateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- currentProgress += 5;
- updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
-
- PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
-
- clear = pbe.getDataStream(decryptorFactory);
-
- encryptedData = pbe;
- currentProgress += 5;
- }
-
- PGPObjectFactory plainFact = new PGPObjectFactory(clear);
- Object dataChunk = plainFact.nextObject();
- PGPOnePassSignature signature = null;
- PGPPublicKey signatureKey = null;
- int signatureIndex = -1;
-
- if (dataChunk instanceof PGPCompressedData) {
- updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
-
- PGPObjectFactory fact = new PGPObjectFactory(
- ((PGPCompressedData) dataChunk).getDataStream());
- dataChunk = fact.nextObject();
- plainFact = fact;
- currentProgress += 10;
- }
-
- if (dataChunk instanceof PGPOnePassSignatureList) {
- updateProgress(R.string.progress_processing_signature, currentProgress, 100);
-
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
- for (int i = 0; i < sigList.size(); ++i) {
- signature = sigList.get(i);
- signatureKey = ProviderHelper
- .getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
- if (signatureKeyId == 0) {
- signatureKeyId = signature.getKeyID();
- }
- if (signatureKey == null) {
- signature = null;
- } else {
- signatureIndex = i;
- signatureKeyId = signature.getKeyID();
- String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(
- mContext, signatureKeyId);
- if (signKeyRing != null) {
- userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
- }
- returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
- break;
- }
- }
-
- returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
-
- if (signature != null) {
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- signature.init(contentVerifierBuilderProvider, signatureKey);
- } else {
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
- }
-
- dataChunk = plainFact.nextObject();
- currentProgress += 10;
- }
-
- if (dataChunk instanceof PGPSignatureList) {
- dataChunk = plainFact.nextObject();
- }
-
- if (dataChunk instanceof PGPLiteralData) {
- updateProgress(R.string.progress_decrypting, currentProgress, 100);
-
- PGPLiteralData literalData = (PGPLiteralData) dataChunk;
- OutputStream out = mOutStream;
-
- byte[] buffer = new byte[1 << 16];
- InputStream dataIn = literalData.getInputStream();
-
- int startProgress = currentProgress;
- int endProgress = 100;
- if (signature != null) {
- endProgress = 90;
- } else if (encryptedData.isIntegrityProtected()) {
- endProgress = 95;
- }
- int n = 0;
- int done = 0;
- long startPos = mData.getStreamPosition();
- while ((n = dataIn.read(buffer)) > 0) {
- out.write(buffer, 0, n);
- done += n;
- if (signature != null) {
- try {
- signature.update(buffer, 0, n);
- } catch (SignatureException e) {
- returnData
- .putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
- signature = null;
- }
- }
- // unknown size, but try to at least have a moving, slowing down progress bar
- currentProgress = startProgress + (endProgress - startProgress) * done
- / (done + 100000);
- if (mData.getSize() - startPos == 0) {
- currentProgress = endProgress;
- } else {
- currentProgress = (int) (startProgress + (endProgress - startProgress)
- * (mData.getStreamPosition() - startPos) / (mData.getSize() - startPos));
- }
- updateProgress(currentProgress, 100);
- }
-
- if (signature != null) {
- updateProgress(R.string.progress_verifying_signature, 90, 100);
-
- PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
- PGPSignature messageSignature = signatureList.get(signatureIndex);
-
- //Now check binding signatures
- boolean keyBinding_isok = verifyKeyBinding(mContext, messageSignature, signatureKey);
- boolean sig_isok = signature.verify(messageSignature);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok);
- }
- }
-
- // TODO: add integrity somewhere
- if (encryptedData.isIntegrityProtected()) {
- updateProgress(R.string.progress_verifying_integrity, 95, 100);
-
- if (encryptedData.verify()) {
- // passed
- } else {
- // failed
- }
- } else {
- // no integrity check
- }
-
- updateProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- public Bundle verifyText(boolean lookupUnknownKey) throws IOException, PgpGeneralException,
- PGPException, SignatureException {
- Bundle returnData = new Bundle();
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ArmoredInputStream aIn = new ArmoredInputStream(mData.getInputStream());
-
- updateProgress(R.string.progress_done, 0, 100);
-
- // mostly taken from ClearSignedFileProcessor
- ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
- int lookAhead = readInputLine(lineOut, aIn);
- byte[] lineSep = getLineSeparator();
-
- byte[] line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
-
- while (lookAhead != -1 && aIn.isClearText()) {
- lookAhead = readInputLine(lineOut, lookAhead, aIn);
- line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
- }
-
- out.close();
-
- byte[] clearText = out.toByteArray();
- mOutStream.write(clearText);
-
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
-
- updateProgress(R.string.progress_processing_signature, 60, 100);
- PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
-
- PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
- if (sigList == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_corrupt_data));
- }
- PGPSignature signature = null;
- long signatureKeyId = 0;
- PGPPublicKey signatureKey = null;
- for (int i = 0; i < sigList.size(); ++i) {
- signature = sigList.get(i);
- signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
- if (signatureKeyId == 0) {
- signatureKeyId = signature.getKeyID();
- }
- // if key is not known and we want to lookup unknown ones...
- if (signatureKey == null && lookupUnknownKey) {
-
- returnData = new Bundle();
- returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_LOOKUP_KEY, true);
-
- // return directly now, decrypt will be done again after importing unknown key
- return returnData;
- }
-
- if (signatureKey == null) {
- signature = null;
- } else {
- signatureKeyId = signature.getKeyID();
- String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext,
- signatureKeyId);
- if (signKeyRing != null) {
- userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
- }
- returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
- break;
- }
- }
-
- returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
-
- if (signature == null) {
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
- if (mProgress != null)
- mProgress.setProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- signature.init(contentVerifierBuilderProvider, signatureKey);
-
- InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
-
- lookAhead = readInputLine(lineOut, sigIn);
-
- processLine(signature, lineOut.toByteArray());
-
- if (lookAhead != -1) {
- do {
- lookAhead = readInputLine(lineOut, lookAhead, sigIn);
-
- signature.update((byte) '\r');
- signature.update((byte) '\n');
-
- processLine(signature, lineOut.toByteArray());
- } while (lookAhead != -1);
- }
-
- boolean sig_isok = signature.verify();
-
- //Now check binding signatures
- boolean keyBinding_isok = verifyKeyBinding(mContext, signature, signatureKey);
-
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok);
-
- updateProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- public boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey)
- {
- long signatureKeyId = signature.getKeyID();
- boolean keyBinding_isok = false;
- String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext,
- signatureKeyId);
- PGPPublicKey mKey = null;
- if (signKeyRing != null) {
- mKey = PgpKeyHelper.getMasterKey(signKeyRing);
- }
- if (signature.getKeyID() != mKey.getKeyID()) {
- keyBinding_isok = verifyKeyBinding(mKey, signatureKey);
- } else { //if the key used to make the signature was the master key, no need to check binding sigs
- keyBinding_isok = true;
- }
- return keyBinding_isok;
- }
-
- public boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey)
- {
- boolean subkeyBinding_isok = false;
- boolean tmp_subkeyBinding_isok = false;
- boolean primkeyBinding_isok = false;
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
-
- subkeyBinding_isok = false;
- tmp_subkeyBinding_isok = false;
- primkeyBinding_isok = false;
- while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
- //gpg has an invalid subkey binding error on key import I think, but doesn't shout
- //about keys without subkey signing. Can't get it to import a slightly broken one
- //either, so we will err on bad subkey binding here.
- PGPSignature sig = itr.next();
- if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
- //check and if ok, check primary key binding.
- try {
- sig.init(contentVerifierBuilderProvider, masterPublicKey);
- tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey);
- } catch (PGPException e) {
- continue;
- } catch (SignatureException e) {
- continue;
- }
-
- if (tmp_subkeyBinding_isok)
- subkeyBinding_isok = true;
- if (tmp_subkeyBinding_isok) {
- primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey);
- if (primkeyBinding_isok)
- break;
- primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey);
- if (primkeyBinding_isok)
- break;
- }
- }
- }
- return (subkeyBinding_isok & primkeyBinding_isok);
- }
-
- private boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey)
- {
- boolean primkeyBinding_isok = false;
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureList eSigList;
-
- if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
- try {
- eSigList = Pkts.getEmbeddedSignatures();
- } catch (IOException e) {
- return false;
- } catch (PGPException e) {
- return false;
- }
- for (int j = 0; j < eSigList.size(); ++j) {
- PGPSignature emSig = eSigList.get(j);
- if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
- try {
- emSig.init(contentVerifierBuilderProvider, signingPublicKey);
- primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey);
- if (primkeyBinding_isok)
- break;
- } catch (PGPException e) {
- continue;
- } catch (SignatureException e) {
- continue;
- }
- }
- }
- }
- return primkeyBinding_isok;
- }
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
- SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
- // taken from ClearSignedFileProcessor in BC
- private static void processLine(PGPSignature sig, byte[] line) throws SignatureException,
- IOException {
- int length = getLengthWithoutWhiteSpace(line);
- if (length > 0) {
- sig.update(line, 0, length);
- }
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int lookAhead = -1;
- int ch;
-
- while ((ch = fIn.read()) >= 0) {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- }
-
- return lookAhead;
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int ch = lookAhead;
-
- do {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- } while ((ch = fIn.read()) >= 0);
-
- if (ch < 0) {
- lookAhead = -1;
- }
-
- return lookAhead;
- }
-
- private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
- throws IOException {
- int lookAhead = fIn.read();
-
- if (lastCh == '\r' && lookAhead == '\n') {
- bOut.write(lookAhead);
- lookAhead = fIn.read();
- }
-
- return lookAhead;
- }
-
- private static int getLengthWithoutSeparator(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isLineEnding(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isLineEnding(byte b) {
- return b == '\r' || b == '\n';
- }
-
- private static int getLengthWithoutWhiteSpace(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isWhiteSpace(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isWhiteSpace(byte b) {
- return b == '\r' || b == '\n' || b == '\t' || b == ' ';
- }
-
- private static byte[] getLineSeparator() {
- String nl = System.getProperty("line.separator");
- byte[] nlBytes = new byte[nl.length()];
-
- for (int i = 0; i != nlBytes.length; i++) {
- nlBytes[i] = (byte) nl.charAt(i);
- }
-
- return nlBytes;
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
new file mode 100644
index 000000000..ba1182c1b
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.pgp;
+
+import android.content.Context;
+
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.spongycastle.bcpg.BCPGOutputStream;
+import org.spongycastle.openpgp.PGPCompressedDataGenerator;
+import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPLiteralData;
+import org.spongycastle.openpgp.PGPLiteralDataGenerator;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPV3SignatureGenerator;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.util.InputData;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SignatureException;
+import java.util.Date;
+
+/**
+ * This class uses a Builder pattern!
+ */
+public class PgpSignEncrypt {
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ private ProgressDialogUpdater progress;
+ private boolean enableAsciiArmorOutput;
+ private int compressionId;
+ private long[] encryptionKeyIds;
+ private String encryptionPassphrase;
+ private int symmetricEncryptionAlgorithm;
+ private long signatureKeyId;
+ private int signatureHashAlgorithm;
+ private boolean signatureForceV3;
+ private String signaturePassphrase;
+
+ private PgpSignEncrypt(Builder builder) {
+ // private Constructor can only be called from Builder
+ this.context = builder.context;
+ this.data = builder.data;
+ this.outStream = builder.outStream;
+
+ this.progress = builder.progress;
+ this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput;
+ this.compressionId = builder.compressionId;
+ this.encryptionKeyIds = builder.encryptionKeyIds;
+ this.encryptionPassphrase = builder.encryptionPassphrase;
+ this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm;
+ this.signatureKeyId = builder.signatureKeyId;
+ this.signatureHashAlgorithm = builder.signatureHashAlgorithm;
+ this.signatureForceV3 = builder.signatureForceV3;
+ this.signaturePassphrase = builder.signaturePassphrase;
+ }
+
+ public static class Builder {
+ // mandatory parameter
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ // optional
+ private ProgressDialogUpdater progress = null;
+ private boolean enableAsciiArmorOutput = false;
+ private int compressionId = Id.choice.compression.none;
+ private long[] encryptionKeyIds = new long[0];
+ private String encryptionPassphrase = null;
+ private int symmetricEncryptionAlgorithm = 0;
+ private long signatureKeyId = Id.key.none;
+ private int signatureHashAlgorithm = 0;
+ private boolean signatureForceV3 = false;
+ private String signaturePassphrase = null;
+
+ public Builder(Context context, InputData data, OutputStream outStream) {
+ this.context = context;
+ this.data = data;
+ this.outStream = outStream;
+ }
+
+ public Builder progress(ProgressDialogUpdater progress) {
+ this.progress = progress;
+ return this;
+ }
+
+ public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
+ this.enableAsciiArmorOutput = enableAsciiArmorOutput;
+ return this;
+ }
+
+ public Builder compressionId(int compressionId) {
+ this.compressionId = compressionId;
+ return this;
+ }
+
+ public Builder encryptionKeyIds(long[] encryptionKeyIds) {
+ this.encryptionKeyIds = encryptionKeyIds;
+ return this;
+ }
+
+ public Builder encryptionPassphrase(String encryptionPassphrase) {
+ this.encryptionPassphrase = encryptionPassphrase;
+ return this;
+ }
+
+ public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
+ this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
+ return this;
+ }
+
+ public Builder signatureKeyId(long signatureKeyId) {
+ this.signatureKeyId = signatureKeyId;
+ return this;
+ }
+
+ public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
+ this.signatureHashAlgorithm = signatureHashAlgorithm;
+ return this;
+ }
+
+ public Builder signatureForceV3(boolean signatureForceV3) {
+ this.signatureForceV3 = signatureForceV3;
+ return this;
+ }
+
+ public Builder signaturePassphrase(String signaturePassphrase) {
+ this.signaturePassphrase = signaturePassphrase;
+ return this;
+ }
+
+ public PgpSignEncrypt build() {
+ return new PgpSignEncrypt(this);
+ }
+ }
+
+ public void updateProgress(int message, int current, int total) {
+ if (progress != null) {
+ progress.setProgress(message, current, total);
+ }
+ }
+
+ public void updateProgress(int current, int total) {
+ if (progress != null) {
+ progress.setProgress(current, total);
+ }
+ }
+
+ /**
+ * Signs and/or encrypts data based on parameters of class
+ *
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws SignatureException
+ */
+ public void execute()
+ throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
+ NoSuchAlgorithmException, SignatureException {
+
+ boolean enableSignature = signatureKeyId != Id.key.none;
+ boolean enableEncryption = (encryptionKeyIds.length != 0 || encryptionPassphrase != null);
+ boolean enableCompression = (enableEncryption && compressionId != Id.choice.compression.none);
+
+ Log.d(Constants.TAG, "enableSignature:" + enableSignature
+ + "\nenableEncryption:" + enableEncryption
+ + "\nenableCompression:" + enableCompression
+ + "\nenableAsciiArmorOutput:" + enableAsciiArmorOutput);
+
+ int signatureType;
+ if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ // for sign-only ascii text
+ signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ } else {
+ signatureType = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ ArmoredOutputStream armorOut = null;
+ OutputStream out;
+ if (enableAsciiArmorOutput) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+ /* Get keys for signature generation for later usage */
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+ if (enableSignature) {
+ signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
+ signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ if (signingKey == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ }
+
+ if (signaturePassphrase == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_no_signature_passphrase));
+ }
+
+ updateProgress(R.string.progress_extracting_signature_key, 0, 100);
+
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
+ signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_could_not_extract_private_key));
+ }
+ }
+ updateProgress(R.string.progress_preparing_streams, 5, 100);
+
+ /* Initialize PGPEncryptedDataGenerator for later usage */
+ PGPEncryptedDataGenerator cPk = null;
+ if (enableEncryption) {
+ // has Integrity packet enabled!
+ JcePGPDataEncryptorBuilder encryptorBuilder =
+ new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
+ .setWithIntegrityPacket(true);
+
+ cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
+
+ if (encryptionKeyIds.length == 0) {
+ // Symmetric encryption
+ Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
+
+ JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
+ new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
+ cPk.addMethod(symmetricEncryptionGenerator);
+ } else {
+ // Asymmetric encryption
+ for (long id : encryptionKeyIds) {
+ PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id);
+ if (key != null) {
+ JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
+ new JcePublicKeyKeyEncryptionMethodGenerator(key);
+ cPk.addMethod(pubKeyEncryptionGenerator);
+ }
+ }
+ }
+ }
+
+ /* Initialize signature generator object for later usage */
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+ if (enableSignature) {
+ updateProgress(R.string.progress_preparing_signature, 10, 100);
+
+ // content signer based on signing key algorithm and chosen hash algorithm
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ if (signatureForceV3) {
+ signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
+ signatureV3Generator.init(signatureType, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(signatureType, signaturePrivateKey);
+
+ String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+ }
+
+ PGPCompressedDataGenerator compressGen = null;
+ OutputStream pOut;
+ OutputStream encryptionOut = null;
+ BCPGOutputStream bcpgOut;
+ if (enableEncryption) {
+ /* actual encryption */
+
+ encryptionOut = cPk.open(out, new byte[1 << 16]);
+
+ if (enableCompression) {
+ compressGen = new PGPCompressedDataGenerator(compressionId);
+ bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
+ } else {
+ bcpgOut = new BCPGOutputStream(encryptionOut);
+ }
+
+ if (enableSignature) {
+ if (signatureForceV3) {
+ signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
+ } else {
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
+ }
+ }
+
+ PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
+ // file name not needed, so empty string
+ pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
+ new byte[1 << 16]);
+ updateProgress(R.string.progress_encrypting, 20, 100);
+
+ long progress = 0;
+ int n;
+ byte[] buffer = new byte[1 << 16];
+ InputStream in = data.getInputStream();
+ while ((n = in.read(buffer)) > 0) {
+ pOut.write(buffer, 0, n);
+
+ // update signature buffer if signature is requested
+ if (enableSignature) {
+ if (signatureForceV3) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ }
+
+ progress += n;
+ if (data.getSize() != 0) {
+ updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100);
+ }
+ }
+
+ literalGen.close();
+ } else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ /* sign-only of ascii text */
+
+ updateProgress(R.string.progress_signing, 40, 100);
+
+ // write directly on armor output stream
+ armorOut.beginClearText(signatureHashAlgorithm);
+
+ InputStream in = data.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ if (signatureForceV3) {
+ processLine(reader.readLine(), armorOut, signatureV3Generator);
+ } else {
+ processLine(reader.readLine(), armorOut, signatureGenerator);
+ }
+
+ while (true) {
+ String line = reader.readLine();
+
+ if (line == null) {
+ armorOut.write(newline);
+ break;
+ }
+
+ armorOut.write(newline);
+
+ // update signature buffer with input line
+ if (signatureForceV3) {
+ signatureV3Generator.update(newline);
+ processLine(line, armorOut, signatureV3Generator);
+ } else {
+ signatureGenerator.update(newline);
+ processLine(line, armorOut, signatureGenerator);
+ }
+ }
+
+ armorOut.endClearText();
+
+ pOut = new BCPGOutputStream(armorOut);
+ } else {
+ // TODO: implement sign-only for files!
+ pOut = null;
+ Log.e(Constants.TAG, "not supported!");
+ }
+
+ if (enableSignature) {
+ updateProgress(R.string.progress_generating_signature, 95, 100);
+ if (signatureForceV3) {
+ signatureV3Generator.generate().encode(pOut);
+ } else {
+ signatureGenerator.generate().encode(pOut);
+ }
+ }
+
+ // closing outputs
+ // NOTE: closing needs to be done in the correct order!
+ // TODO: closing bcpgOut and pOut???
+ if (enableEncryption) {
+ if (enableCompression) {
+ compressGen.close();
+ }
+
+ encryptionOut.close();
+ }
+ if (enableAsciiArmorOutput) {
+ armorOut.close();
+ }
+
+ out.close();
+ outStream.close();
+
+ updateProgress(R.string.progress_done, 100, 100);
+ }
+
+ // TODO: merge this into execute method!
+ // TODO: allow binary input for this class
+ public void generateSignature()
+ throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
+ SignatureException {
+
+ OutputStream out;
+ if (enableAsciiArmorOutput) {
+ // Ascii Armor (Radix-64)
+ ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+ if (signatureKeyId == 0) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_signature_key));
+ }
+
+ PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
+ PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ if (signingKey == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ }
+
+ if (signaturePassphrase == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase));
+ }
+
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
+ PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_could_not_extract_private_key));
+ }
+ updateProgress(R.string.progress_preparing_streams, 0, 100);
+
+ updateProgress(R.string.progress_preparing_signature, 30, 100);
+
+ int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+// if (binary) {
+// type = PGPSignature.BINARY_DOCUMENT;
+// }
+
+ // content signer based on signing key algorithm and chosen hash algorithm
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
+ .getPublicKey().getAlgorithm(), signatureHashAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+ if (signatureForceV3) {
+ signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
+ signatureV3Generator.init(type, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(type, signaturePrivateKey);
+
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+
+ updateProgress(R.string.progress_signing, 40, 100);
+
+ InputStream inStream = data.getInputStream();
+// if (binary) {
+// byte[] buffer = new byte[1 << 16];
+// int n = 0;
+// while ((n = inStream.read(buffer)) > 0) {
+// if (signatureForceV3) {
+// signatureV3Generator.update(buffer, 0, n);
+// } else {
+// signatureGenerator.update(buffer, 0, n);
+// }
+// }
+// } else {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (signatureForceV3) {
+ processLine(line, null, signatureV3Generator);
+ signatureV3Generator.update(newline);
+ } else {
+ processLine(line, null, signatureGenerator);
+ signatureGenerator.update(newline);
+ }
+ }
+// }
+
+ BCPGOutputStream bOut = new BCPGOutputStream(out);
+ if (signatureForceV3) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
+ out.close();
+ outStream.close();
+
+ updateProgress(R.string.progress_done, 100, 100);
+ }
+
+
+ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
+ final PGPSignatureGenerator pSignatureGenerator)
+ throws IOException, SignatureException {
+
+ if (pLine == null) {
+ return;
+ }
+
+ final char[] chars = pLine.toCharArray();
+ int len = chars.length;
+
+ while (len > 0) {
+ if (!Character.isWhitespace(chars[len - 1])) {
+ break;
+ }
+ len--;
+ }
+
+ final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
+
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
+ pSignatureGenerator.update(data);
+ }
+
+ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
+ final PGPV3SignatureGenerator pSignatureGenerator)
+ throws IOException, SignatureException {
+
+ if (pLine == null) {
+ return;
+ }
+
+ final char[] chars = pLine.toCharArray();
+ int len = chars.length;
+
+ while (len > 0) {
+ if (!Character.isWhitespace(chars[len - 1])) {
+ break;
+ }
+ len--;
+ }
+
+ final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
+
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
+ pSignatureGenerator.update(data);
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 3a00f3101..5f18ed6f9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -110,7 +110,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(Constants.TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
- // Upgrade from oldVersion through all methods to newest one
+ // Upgrade from oldVersion through all cases to newest one
for (int version = oldVersion; version < newVersion; ++version) {
Log.w(Constants.TAG, "Upgrading database to version " + version);
@@ -123,14 +123,17 @@ public class KeychainDatabase extends SQLiteOpenHelper {
break;
case 4:
db.execSQL(CREATE_API_APPS);
+ break;
case 5:
// new column: package_signature
db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS);
db.execSQL(CREATE_API_APPS);
+ break;
case 6:
// new column: fingerprint
db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.FINGERPRINT
+ " BLOB;");
+ break;
default:
break;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index cd3007353..781f36758 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -359,7 +359,9 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID);
// TODO: deprecated master key id
//projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID);
+
projectionMap.put(KeysColumns.FINGERPRINT, Tables.KEYS + "." + KeysColumns.FINGERPRINT);
+ projectionMap.put(KeysColumns.IS_REVOKED, Tables.KEYS + "." + KeysColumns.IS_REVOKED);
projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 12bc33995..ba931c61a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -28,6 +28,7 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
@@ -210,6 +211,13 @@ public class ProviderHelper {
++userIdRank;
}
+ for (PGPSignature certification : new IterableIterator<PGPSignature>(masterKey.getSignaturesOfType(PGPSignature.POSITIVE_CERTIFICATION))) {
+ //TODO: how to do this?? we need to verify the signatures again and again when they are displayed...
+// if (certification.verify
+// operations.add(buildPublicKeyOperations(context, keyRingRowId, key, rank));
+ }
+
+
try {
context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
} catch (RemoteException e) {
@@ -562,6 +570,26 @@ public class ProviderHelper {
return fingerprint;
}
+ public static String getUserId(Context context, Uri queryUri) {
+ String[] projection = new String[]{UserIds.USER_ID};
+ Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
+
+ String userId = null;
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ int col = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
+
+ userId = cursor.getString(col);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return userId;
+ }
+
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, Uri uri,
long[] masterKeyIds) {
ArrayList<String> output = new ArrayList<String>();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 5e5735c88..9e517b93e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -43,10 +43,11 @@ import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -95,7 +96,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING";
public static final String ACTION_DOWNLOAD_AND_IMPORT_KEYS = Constants.INTENT_PREFIX + "QUERY_KEYRING";
- public static final String ACTION_SIGN_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
+ public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
/* keys for data bundle */
@@ -119,11 +120,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String ENCRYPT_PROVIDER_URI = "provider_uri";
// decrypt/verify
- public static final String DECRYPT_SIGNED_ONLY = "signed_only";
public static final String DECRYPT_RETURN_BYTES = "return_binary";
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
public static final String DECRYPT_ASSUME_SYMMETRIC = "assume_symmetric";
- public static final String DECRYPT_LOOKUP_UNKNOWN_KEY = "lookup_unknownKey";
// save keyring
public static final String SAVE_KEYRING_NEW_PASSPHRASE = "new_passphrase";
@@ -166,8 +165,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String DOWNLOAD_KEY_LIST = "query_key_id";
// sign key
- public static final String SIGN_KEY_MASTER_KEY_ID = "sign_key_master_key_id";
- public static final String SIGN_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
+ public static final String CERTIFY_KEY_MASTER_KEY_ID = "sign_key_master_key_id";
+ public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
/*
* possible data keys as result send over messenger
@@ -189,10 +188,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id";
public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id";
+ public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only";
public static final String RESULT_SIGNATURE_SUCCESS = "signature_success";
public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown";
- public static final String RESULT_SIGNATURE_LOOKUP_KEY = "lookup_key";
// import
public static final String RESULT_IMPORT_ADDED = "added";
@@ -241,7 +240,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
String action = intent.getAction();
- // execute action from extra bundle
+ // executeServiceMethod action from extra bundle
if (ACTION_ENCRYPT_SIGN.equals(action)) {
try {
/* Input */
@@ -322,27 +321,41 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/* Operation */
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
+ PgpSignEncrypt.Builder builder =
+ new PgpSignEncrypt.Builder(this, inputData, outStream);
+ builder.progress(this);
+
if (generateSignature) {
Log.d(Constants.TAG, "generating signature...");
- operation.generateSignature(useAsciiArmor, false, secretKeyId,
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
- Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures());
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().generateSignature();
} else if (signOnly) {
Log.d(Constants.TAG, "sign only...");
- operation.signText(secretKeyId, PassphraseCacheService.getCachedPassphrase(
- this, secretKeyId), Preferences.getPreferences(this)
- .getDefaultHashAlgorithm(), Preferences.getPreferences(this)
- .getForceV3Signatures());
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().execute();
} else {
Log.d(Constants.TAG, "encrypt...");
- operation.signAndEncrypt(useAsciiArmor, compressionId, encryptionKeyIds,
- encryptionPassphrase, Preferences.getPreferences(this)
- .getDefaultEncryptionAlgorithm(), secretKeyId, Preferences
- .getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures(),
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .compressionId(compressionId)
+ .symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .encryptionKeyIds(encryptionKeyIds)
+ .encryptionPassphrase(encryptionPassphrase)
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().execute();
}
outStream.close();
@@ -395,12 +408,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
long secretKeyId = data.getLong(ENCRYPT_SECRET_KEY_ID);
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
- boolean signedOnly = data.getBoolean(DECRYPT_SIGNED_ONLY);
boolean returnBytes = data.getBoolean(DECRYPT_RETURN_BYTES);
boolean assumeSymmetricEncryption = data.getBoolean(DECRYPT_ASSUME_SYMMETRIC);
- boolean lookupUnknownKey = data.getBoolean(DECRYPT_LOOKUP_UNKNOWN_KEY);
-
InputStream inStream = null;
long inLength = -1;
InputData inputData = null;
@@ -474,14 +484,13 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
- if (signedOnly) {
- resultData = operation.verifyText(lookupUnknownKey);
- } else {
- resultData = operation.decryptAndVerify(
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
- assumeSymmetricEncryption);
- }
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
+ builder.progress(this);
+
+ builder.assumeSymmetric(assumeSymmetricEncryption)
+ .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ resultData = builder.build().execute();
outStream.close();
@@ -785,19 +794,19 @@ public class KeychainIntentService extends IntentService implements ProgressDial
} catch (Exception e) {
sendErrorToHandler(e);
}
- } else if (ACTION_SIGN_KEYRING.equals(action)) {
+ } else if (ACTION_CERTIFY_KEYRING.equals(action)) {
try {
/* Input */
- long masterKeyId = data.getLong(SIGN_KEY_MASTER_KEY_ID);
- long pubKeyId = data.getLong(SIGN_KEY_PUB_KEY_ID);
+ long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID);
+ long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID);
/* Operation */
String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this,
masterKeyId);
PgpKeyOperation keyOperation = new PgpKeyOperation(this, this);
- PGPPublicKeyRing signedPubKeyRing = keyOperation.signKey(masterKeyId, pubKeyId,
+ PGPPublicKeyRing signedPubKeyRing = keyOperation.certifyKey(masterKeyId, pubKeyId,
signaturePassPhrase);
// store the signed key in our local cache
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index 5a338c757..dfea7eb04 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -25,6 +25,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
import android.widget.Toast;
public class KeychainIntentServiceHandler extends Handler {
@@ -60,7 +61,14 @@ public class KeychainIntentServiceHandler extends Handler {
}
public void showProgressDialog(FragmentActivity activity) {
- mProgressDialogFragment.show(activity.getSupportFragmentManager(), "progressDialog");
+ // TODO: This is a hack!, see http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
+ final FragmentManager manager = activity.getSupportFragmentManager();
+ Handler handler = new Handler();
+ handler.post(new Runnable() {
+ public void run() {
+ mProgressDialogFragment.show(manager, "progressDialog");
+ }
+ });
}
@Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java
deleted file mode 100644
index 555303238..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class NoUserIdsException extends Exception {
-
- private static final long serialVersionUID = 7009311527126696207L;
-
- public NoUserIdsException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java
deleted file mode 100644
index 1152d6796..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class UserInteractionRequiredException extends Exception {
-
- private static final long serialVersionUID = -60128148603511936L;
-
- public UserInteractionRequiredException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java
deleted file mode 100644
index 14b774eb5..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class WrongPassphraseException extends Exception {
-
- private static final long serialVersionUID = -5309689232853485740L;
-
- public WrongPassphraseException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java
index 025929cfa..64c4c5e96 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java
@@ -109,6 +109,15 @@ public class AppSettingsFragment extends Fragment implements
return view;
}
+ /**
+ * Set error String on key selection
+ *
+ * @param error
+ */
+ public void setErrorOnSelectKeyFragment(String error) {
+ mSelectKeyFragment.setError(error);
+ }
+
private void initView(View view) {
mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getFragmentManager().findFragmentById(
R.id.api_app_settings_select_key_fragment);
@@ -182,7 +191,7 @@ public class AppSettingsFragment extends Fragment implements
// TODO: Better: collapse/expand animation
// final Animation animation2 = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
// Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,
- // Animation.RELATIVE_TO_SELF, 0.0f);
+ // Animation.RELATIVE_TO_SELF, 0.0f);u
// animation2.setDuration(150);
mAdvancedSettingsButton.setOnClickListener(new OnClickListener() {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java
deleted file mode 100644
index 427e6bb8f..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.service.remote;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-import java.security.cert.X509Certificate;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openssl.PEMWriter;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.PgpToX509;
-import org.sufficientlysecure.keychain.util.Log;
-
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-public class ExtendedApiService extends RemoteService {
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- private void selfSignedX509CertSafe(String subjAltNameURI, IExtendedApiCallback callback,
- AppSettings appSettings) {
-
- // TODO: for pgp keyrings with password
- CallbackHandler pgpPwdCallbackHandler = new PgpToX509.PredefinedPasswordCallbackHandler("");
-
- try {
- long keyId = appSettings.getKeyId();
- PGPSecretKey pgpSecretKey = PgpKeyHelper.getSigningKey(this, keyId);
-
- PasswordCallback pgpSecKeyPasswordCallBack = new PasswordCallback("pgp passphrase?",
- false);
- pgpPwdCallbackHandler.handle(new Callback[] { pgpSecKeyPasswordCallBack });
- PGPPrivateKey pgpPrivKey = pgpSecretKey.extractPrivateKey(
- pgpSecKeyPasswordCallBack.getPassword(), Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- pgpSecKeyPasswordCallBack.clearPassword();
-
- X509Certificate selfSignedCert = PgpToX509.createSelfSignedCert(pgpSecretKey,
- pgpPrivKey, subjAltNameURI);
-
- // Write x509cert and privKey into files
- // FileOutputStream fosCert = context.openFileOutput(CERT_FILENAME,
- // Context.MODE_PRIVATE);
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- PEMWriter pemWriterCert = new PEMWriter(new PrintWriter(outStream));
- pemWriterCert.writeObject(selfSignedCert);
- pemWriterCert.close();
-
- byte[] outputBytes = outStream.toByteArray();
-
- callback.onSuccess(outputBytes);
- } catch (Exception e) {
- Log.e(Constants.TAG, "ExtendedApiService", e);
- try {
- callback.onError(e.getMessage());
- } catch (RemoteException e1) {
- Log.e(Constants.TAG, "ExtendedApiService", e);
- }
- }
-
- // TODO: no private key at the moment! Don't give it to others
- // PrivateKey privKey = pgpPrivKey.getKey();
- // FileOutputStream fosKey = context.openFileOutput(PRIV_KEY_FILENAME,
- // Context.MODE_PRIVATE);
- // PEMWriter pemWriterKey = new PEMWriter(new PrintWriter(fosKey));
- // pemWriterKey.writeObject(privKey);
- // pemWriterKey.close();
- }
-
- private final IExtendedApiService.Stub mBinder = new IExtendedApiService.Stub() {
-
- @Override
- public void encrypt(byte[] inputBytes, String passphrase, IExtendedApiCallback callback)
- throws RemoteException {
- // TODO : implement
-
- }
-
- @Override
- public void selfSignedX509Cert(final String subjAltNameURI,
- final IExtendedApiCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- selfSignedX509CertSafe(subjAltNameURI, callback, settings);
- }
- };
-
- checkAndEnqueue(r);
- }
-
- };
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
index 575f76a22..34213bd3b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,108 +17,46 @@
package org.sufficientlysecure.keychain.service.remote;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.regex.Matcher;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
-import org.openintents.openpgp.IOpenPgpCallback;
-import org.openintents.openpgp.IOpenPgpKeyIdsCallback;
import org.openintents.openpgp.IOpenPgpService;
-import org.openintents.openpgp.OpenPgpData;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
+import org.openintents.openpgp.util.OpenPgpConstants;
import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.PgpHelper;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
-import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.service.exception.NoUserIdsException;
-import org.sufficientlysecure.keychain.service.exception.UserInteractionRequiredException;
-import org.sufficientlysecure.keychain.service.exception.WrongPassphraseException;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
public class OpenPgpService extends RemoteService {
- private String getCachedPassphrase(long keyId, boolean allowUserInteraction)
- throws UserInteractionRequiredException {
- String passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId);
-
- if (passphrase == null) {
- if (!allowUserInteraction) {
- throw new UserInteractionRequiredException(
- "Passphrase not found in cache, please enter your passphrase!");
- }
+ private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
+ private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
- Log.d(Constants.TAG, "No passphrase! Activity required!");
-
- // start passphrase dialog
- PassphraseActivityCallback callback = new PassphraseActivityCallback();
- Bundle extras = new Bundle();
- extras.putLong(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE, callback,
- extras);
-
- if (callback.isSuccess()) {
- Log.d(Constants.TAG, "New passphrase entered!");
-
- // get again after it was entered
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId);
- } else {
- Log.d(Constants.TAG, "Passphrase dialog canceled!");
-
- return null;
- }
-
- }
-
- return passphrase;
- }
-
- public class PassphraseActivityCallback extends UserInputCallback {
-
- private boolean success = false;
-
- public boolean isSuccess() {
- return success;
- }
-
- @Override
- public void handleUserInput(Message msg) {
- if (msg.arg1 == OKAY) {
- success = true;
- } else {
- success = false;
- }
- }
- };
/**
* Search database for key ids based on emails.
- *
+ *
* @param encryptionUserIds
* @return
*/
- private long[] getKeyIdsFromEmails(String[] encryptionUserIds, boolean allowUserInteraction)
- throws UserInteractionRequiredException {
+ private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) {
// find key ids to given emails in database
ArrayList<Long> keyIds = new ArrayList<Long>();
@@ -152,96 +90,129 @@ public class OpenPgpService extends RemoteService {
}
// allow the user to verify pub key selection
- if (allowUserInteraction && (missingUserIdsCheck || dublicateUserIdsCheck)) {
- SelectPubKeysActivityCallback callback = new SelectPubKeysActivityCallback();
-
- Bundle extras = new Bundle();
- extras.putLongArray(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
- extras.putStringArrayList(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
- extras.putStringArrayList(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS,
- dublicateUserIds);
-
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS, callback,
- extras);
-
- if (callback.isSuccess()) {
- Log.d(Constants.TAG, "New selection of pub keys!");
- keyIdsArray = callback.getPubKeyIds();
- } else {
- Log.d(Constants.TAG, "Pub key selection canceled!");
- return null;
- }
- }
-
- // if no user interaction is allow throw exceptions on duplicate or missing pub keys
- if (!allowUserInteraction) {
- if (missingUserIdsCheck)
- throw new UserInteractionRequiredException(
- "Pub keys for these user ids are missing:" + missingUserIds.toString());
- if (dublicateUserIdsCheck)
- throw new UserInteractionRequiredException(
- "More than one pub key with these user ids exist:"
- + dublicateUserIds.toString());
+ if (missingUserIdsCheck || dublicateUserIdsCheck) {
+ // build PendingIntent for passphrase input
+ Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
+ intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
+ intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
+ intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
+ intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
+ intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
}
if (keyIdsArray.length == 0) {
return null;
}
- return keyIdsArray;
- }
-
- public class SelectPubKeysActivityCallback extends UserInputCallback {
- public static final String PUB_KEY_IDS = "pub_key_ids";
- private boolean success = false;
- private long[] pubKeyIds;
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray);
+ return result;
+ }
- public boolean isSuccess() {
- return success;
- }
+ private Bundle getPassphraseBundleIntent(Bundle params, long keyId) {
+ // build PendingIntent for passphrase input
+ Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
+ intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE);
+ intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
+ // pass params through to activity that it can be returned again later to repeat pgp operation
+ intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
+ }
- public long[] getPubKeyIds() {
- return pubKeyIds;
- }
+ private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output,
+ AppSettings appSettings) {
+ try {
+ boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
- @Override
- public void handleUserInput(Message msg) {
- if (msg.arg1 == OKAY) {
- success = true;
- pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS);
+ // get passphrase from cache, if key has "no" passphrase, this returns an empty String
+ String passphrase;
+ if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
} else {
- success = false;
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
+ }
+ if (passphrase == null) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
}
- }
- };
- private synchronized void getKeyIdsSafe(String[] userIds, boolean allowUserInteraction,
- IOpenPgpKeyIdsCallback callback, AppSettings appSettings) {
- try {
- long[] keyIds = getKeyIdsFromEmails(userIds, allowUserInteraction);
- if (keyIds == null) {
- throw new NoUserIdsException("No user ids!");
+ // Get Input- and OutputStream from ParcelFileDescriptor
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ try {
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
+
+ // sign-only
+ PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os);
+ builder.enableAsciiArmorOutput(asciiArmor)
+ .signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureForceV3(false)
+ .signatureKeyId(appSettings.getKeyId())
+ .signaturePassphrase(passphrase);
+ builder.build().execute();
+ } finally {
+ is.close();
+ os.close();
}
- callback.onSuccess(keyIds);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (NoUserIdsException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
- private synchronized void encryptAndSignSafe(OpenPgpData inputData,
- final OpenPgpData outputData, long[] keyIds, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings, boolean sign) {
+ private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input,
+ ParcelFileDescriptor output, AppSettings appSettings,
+ boolean sign) {
try {
- // TODO: other options of OpenPgpData!
- byte[] inputBytes = getInput(inputData);
- boolean asciiArmor = false;
- if (outputData.getType() == OpenPgpData.TYPE_STRING) {
- asciiArmor = true;
+ boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
+
+ long[] keyIds;
+ if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) {
+ keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
+ } else if (params.containsKey(OpenPgpConstants.PARAMS_USER_IDS)) {
+ // get key ids based on given user ids
+ String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
+ // give params through to activity...
+ Bundle result = getKeyIdsFromEmails(params, userIds);
+
+ if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) {
+ keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
+ } else {
+ // if not success -> result contains a PendingIntent for user interaction
+ return result;
+ }
+ } else {
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
+ return result;
}
// add own key for encryption
@@ -249,350 +220,338 @@ public class OpenPgpService extends RemoteService {
keyIds[keyIds.length - 1] = appSettings.getKeyId();
// build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputDt = new InputData(inputStream, inputLength);
-
- OutputStream outputStream = new ByteArrayOutputStream();
+ // Get Input- and OutputStream from ParcelFileDescriptor
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ try {
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
+
+ PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os);
+ builder.enableAsciiArmorOutput(asciiArmor)
+ .compressionId(appSettings.getCompression())
+ .symmetricEncryptionAlgorithm(appSettings.getEncryptionAlgorithm())
+ .encryptionKeyIds(keyIds);
+
+ if (sign) {
+ String passphrase;
+ if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
+ } else {
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
+ appSettings.getKeyId());
+ }
+ if (passphrase == null) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
+ }
- PgpOperation operation = new PgpOperation(getContext(), null, inputDt, outputStream);
- if (sign) {
- String passphrase = getCachedPassphrase(appSettings.getKeyId(),
- allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
+ // sign and encrypt
+ builder.signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureForceV3(false)
+ .signatureKeyId(appSettings.getKeyId())
+ .signaturePassphrase(passphrase);
+ } else {
+ // encrypt only
+ builder.signatureKeyId(Id.key.none);
}
-
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
- appSettings.getHashAlgorithm(), true, passphrase);
- } else {
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), Id.key.none,
- appSettings.getHashAlgorithm(), true, null);
+ // execute PGP operation!
+ builder.build().execute();
+ } finally {
+ is.close();
+ os.close();
}
- outputStream.close();
-
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
-
- OpenPgpData output = null;
- if (asciiArmor) {
- output = new OpenPgpData(new String(outputBytes));
- } else {
- output = new OpenPgpData(outputBytes);
- }
-
- // return over handler on client side
- callback.onSuccess(output, null);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
- } catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
- }
- }
-
- // TODO: asciiArmor?!
- private void signSafe(byte[] inputBytes, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings) {
- try {
- // build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputData = new InputData(inputStream, inputLength);
-
- OutputStream outputStream = new ByteArrayOutputStream();
-
- String passphrase = getCachedPassphrase(appSettings.getKeyId(), allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
- }
-
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream);
- operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(),
- Preferences.getPreferences(this).getForceV3Signatures());
-
- outputStream.close();
-
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
- OpenPgpData output = new OpenPgpData(new String(outputBytes));
-
- // return over handler on client side
- callback.onSuccess(output, null);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
- private synchronized void decryptAndVerifySafe(byte[] inputBytes, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings) {
+ private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input,
+ ParcelFileDescriptor output, AppSettings appSettings) {
try {
- // TODO: this is not really needed
- // checked if it is text with BEGIN and END tags
- String message = new String(inputBytes);
- Log.d(Constants.TAG, "in: " + message);
- boolean signedOnly = false;
- Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
- if (matcher.matches()) {
- Log.d(Constants.TAG, "PGP_MESSAGE matched");
- message = matcher.group(1);
- // replace non breakable spaces
- message = message.replaceAll("\\xa0", " ");
-
- // overwrite inputBytes
- inputBytes = message.getBytes();
- } else {
- matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message);
- if (matcher.matches()) {
- signedOnly = true;
- Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
- message = matcher.group(1);
- // replace non breakable spaces
- message = message.replaceAll("\\xa0", " ");
-
- // overwrite inputBytes
- inputBytes = message.getBytes();
+ // Get Input- and OutputStream from ParcelFileDescriptor
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ OpenPgpSignatureResult sigResult = null;
+ try {
+
+// PGPUtil.getDecoderStream(is)
+ // TODOs API 2.0:
+ // implement verify-only!
+ // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
+ // should we allow to decrypt everything under every key id or only the one set?
+ // TODO: instead of trying to get the passphrase before
+ // pause stream when passphrase is missing and then resume
+
+
+ // TODO: this is not really needed
+ // checked if it is text with BEGIN and END tags
+// String message = new String(inputBytes);
+// Log.d(Constants.TAG, "in: " + message);
+// boolean signedOnly = false;
+// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
+// if (matcher.matches()) {
+// Log.d(Constants.TAG, "PGP_MESSAGE matched");
+// message = matcher.group(1);
+// // replace non breakable spaces
+// message = message.replaceAll("\\xa0", " ");
+//
+// // overwrite inputBytes
+// inputBytes = message.getBytes();
+// } else {
+// matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message);
+// if (matcher.matches()) {
+// signedOnly = true;
+// Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
+// message = matcher.group(1);
+// // replace non breakable spaces
+// message = message.replaceAll("\\xa0", " ");
+//
+// // overwrite inputBytes
+// inputBytes = message.getBytes();
+// } else {
+// Log.d(Constants.TAG, "Nothing matched! Binary?");
+// }
+// }
+ // END TODO
+
+// Log.d(Constants.TAG, "in: " + new String(inputBytes));
+
+ // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
+ // app, Fix this?
+
+// String passphrase = null;
+// if (!signedOnly) {
+// // BEGIN Get key
+// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
+// // better!
+// InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
+//
+// // TODO: duplicates functions from DecryptActivity!
+// long secretKeyId;
+// try {
+// if (inputStream2.markSupported()) {
+// // should probably set this to the max size of two
+// // pgpF objects, if it even needs to be anything other
+// // than 0.
+// inputStream2.mark(200);
+// }
+// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
+// if (secretKeyId == Id.key.none) {
+// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
+// }
+// } catch (NoAsymmetricEncryptionException e) {
+// if (inputStream2.markSupported()) {
+// inputStream2.reset();
+// }
+// secretKeyId = Id.key.symmetric;
+// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) {
+// throw new PgpGeneralException(
+// getString(R.string.error_no_known_encryption_found));
+// }
+// // we do not support symmetric decryption from the API!
+// throw new Exception("Symmetric decryption is not supported!");
+// }
+//
+// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
+
+ // NOTE: currently this only gets the passphrase for the key set for this client
+ String passphrase;
+ if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
} else {
- Log.d(Constants.TAG, "Nothing matched! Binary?");
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
}
- }
- // END TODO
-
- Log.d(Constants.TAG, "in: " + new String(inputBytes));
-
- // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
- // app, Fix this?
-
- String passphrase = null;
- if (!signedOnly) {
- // BEGIN Get key
- // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
- // better!
- InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
-
- // TODO: duplicates functions from DecryptActivity!
- long secretKeyId;
- try {
- if (inputStream2.markSupported()) {
- // should probably set this to the max size of two
- // pgpF objects, if it even needs to be anything other
- // than 0.
- inputStream2.mark(200);
- }
- secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
- if (secretKeyId == Id.key.none) {
- throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
- }
- } catch (NoAsymmetricEncryptionException e) {
- if (inputStream2.markSupported()) {
- inputStream2.reset();
- }
- secretKeyId = Id.key.symmetric;
- if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) {
- throw new PgpGeneralException(
- getString(R.string.error_no_known_encryption_found));
- }
- // we do not support symmetric decryption from the API!
- throw new Exception("Symmetric decryption is not supported!");
+ if (passphrase == null) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
}
+// }
- Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
+ // build InputData and write into OutputStream
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
- passphrase = getCachedPassphrase(secretKeyId, allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
- }
- }
- // build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputData = new InputData(inputStream, inputLength);
+ Bundle outputBundle;
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
- OutputStream outputStream = new ByteArrayOutputStream();
+// if (signedOnly) {
+// outputBundle = builder.build().verifyText();
+// } else {
+ builder.assumeSymmetric(false)
+ .passphrase(passphrase);
- Bundle outputBundle;
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream);
- if (signedOnly) {
- // TODO: download missing keys from keyserver?
- outputBundle = operation.verifyText(false);
- } else {
- outputBundle = operation.decryptAndVerify(passphrase, false);
- }
+ // Do we want to do this: instead of trying to get the passphrase before
+ // pause stream when passphrase is missing and then resume???
- outputStream.close();
+ // TODO: this also decrypts with other secret keys without passphrase!!!
+ outputBundle = builder.build().execute();
+// }
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
+// outputStream.close();
- // get signature informations from bundle
- boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE);
+// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
- OpenPgpSignatureResult sigResult = null;
- if (signature) {
- long signatureKeyId = outputBundle
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
- String signatureUserId = outputBundle
- .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
- boolean signatureSuccess = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS);
- boolean signatureUnknown = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
-
- int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
- if (signatureSuccess) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_TRUSTED;
- } else if (signatureUnknown) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
- }
+ // get signature informations from bundle
+ boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false);
- sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
- signedOnly, signatureKeyId);
+ if (signature) {
+ long signatureKeyId = outputBundle
+ .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0);
+ String signatureUserId = outputBundle
+ .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
+ boolean signatureSuccess = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
+ boolean signatureUnknown = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
+ boolean signatureOnly = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
+
+ int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
+ if (signatureSuccess) {
+ signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED;
+ } else if (signatureUnknown) {
+ signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
+ }
+
+ sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
+ signatureOnly, signatureKeyId);
+ }
+ } finally {
+ is.close();
+ os.close();
}
- OpenPgpData output = new OpenPgpData(new String(outputBytes));
-
- // return over handler on client side
- callback.onSuccess(output, sigResult);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
+
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
+ private Bundle getKeyIdsImpl(Bundle params) {
+ // get key ids based on given user ids
+ String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
+ Bundle result = getKeyIdsFromEmails(params, userIds);
+ return result;
+ }
+
/**
- * Returns error to IOpenPgpCallback
- *
- * @param callback
- * @param errorId
- * @param message
+ * Check requirements:
+ * - params != null
+ * - has supported API version
+ * - is allowed to call the service (access has been granted)
+ *
+ * @param params
+ * @return null if everything is okay, or a Bundle with an error/PendingIntent
*/
- private void callbackOpenPgpError(IOpenPgpCallback callback, int errorId, String message) {
- try {
- callback.onError(new OpenPgpError(0, message));
- } catch (Exception t) {
- Log.e(Constants.TAG,
- "Exception while returning OpenPgpError to client via callback.onError()", t);
+ private Bundle checkRequirements(Bundle params) {
+ // params Bundle is required!
+ if (params == null) {
+ Bundle result = new Bundle();
+ OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!");
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ return result;
}
- }
- private void callbackOpenPgpError(IOpenPgpKeyIdsCallback callback, int errorId, String message) {
- try {
- callback.onError(new OpenPgpError(0, message));
- } catch (Exception t) {
- Log.e(Constants.TAG,
- "Exception while returning OpenPgpError to client via callback.onError()", t);
+ // version code is required and needs to correspond to version code of service!
+ if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) {
+ Bundle result = new Bundle();
+ OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ return result;
}
+
+ // check if caller is allowed to access openpgp keychain
+ Bundle result = isAllowed(params);
+ if (result != null) {
+ return result;
+ }
+
+ return null;
}
+ // TODO: multi-threading
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
@Override
- public void encrypt(final OpenPgpData input, final OpenPgpData output, final long[] keyIds,
- final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- encryptAndSignSafe(input, output, keyIds, true, callback, settings, false);
- }
- };
-
- checkAndEnqueue(r);
- }
+ public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- @Override
- public void signAndEncrypt(final OpenPgpData input, final OpenPgpData output,
- final long[] keyIds, final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- encryptAndSignSafe(input, output, keyIds, true, callback, settings, true);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return signImpl(params, input, output, appSettings);
}
@Override
- public void sign(final OpenPgpData input, final OpenPgpData output,
- final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- signSafe(getInput(input), true, callback, settings);
- }
- };
+ public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
+
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return encryptAndSignImpl(params, input, output, appSettings, false);
}
@Override
- public void decryptAndVerify(final OpenPgpData input, final OpenPgpData output,
- final IOpenPgpCallback callback) throws RemoteException {
+ public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- decryptAndVerifySafe(getInput(input), true, callback, settings);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return encryptAndSignImpl(params, input, output, appSettings, true);
}
@Override
- public void getKeyIds(final String[] userIds, final boolean allowUserInteraction,
- final IOpenPgpKeyIdsCallback callback) throws RemoteException {
-
- final AppSettings settings = getAppSettings();
+ public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- getKeyIdsSafe(userIds, allowUserInteraction, callback, settings);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return decryptAndVerifyImpl(params, input, output, appSettings);
}
- };
-
- private static byte[] getInput(OpenPgpData data) {
- // TODO: support Uri and ParcelFileDescriptor
-
- byte[] inBytes = null;
- switch (data.getType()) {
- case OpenPgpData.TYPE_STRING:
- inBytes = data.getString().getBytes();
- break;
-
- case OpenPgpData.TYPE_BYTE_ARRAY:
- inBytes = data.getBytes();
- break;
+ @Override
+ public Bundle getKeyIds(Bundle params) {
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- default:
- Log.e(Constants.TAG, "Uri and ParcelFileDescriptor not supported right now!");
- break;
+ return getKeyIdsImpl(params);
}
- return inBytes;
- }
+ };
@Override
public IBinder onBind(Intent intent) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java
index bc513d532..cfd2b9ec3 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,17 +19,16 @@ package org.sufficientlysecure.keychain.service.remote;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.TimeUnit;
+import org.openintents.openpgp.OpenPgpError;
+import org.openintents.openpgp.util.OpenPgpConstants;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.exception.WrongPackageSignatureException;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -50,66 +49,19 @@ import android.os.Messenger;
public abstract class RemoteService extends Service {
Context mContext;
- private final ArrayBlockingQueue<Runnable> mPoolQueue = new ArrayBlockingQueue<Runnable>(100);
- // TODO: Are these parameters okay?
- private PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10,
- TimeUnit.SECONDS, mPoolQueue);
+ private static final int PRIVATE_REQUEST_CODE_REGISTER = 651;
+ private static final int PRIVATE_REQUEST_CODE_ERROR = 652;
- private final Object userInputLock = new Object();
-
- /**
- * Override handleUserInput() to handle OKAY (1) and CANCEL (0). After handling the waiting
- * threads will be notified and the queue resumed
- */
- protected class UserInputCallback extends BaseCallback {
-
- public void handleUserInput(Message msg) {
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- handleUserInput(msg);
-
- // resume
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- return true;
- }
-
- }
-
- /**
- * Extends Handler.Callback with OKAY (1), CANCEL (0) variables
- */
- private class BaseCallback implements Handler.Callback {
- public static final int OKAY = 1;
- public static final int CANCEL = 0;
-
- @Override
- public boolean handleMessage(Message msg) {
- return false;
- }
-
- }
public Context getContext() {
return mContext;
}
- /**
- * Should be used from Stub implementations of AIDL interfaces to enqueue a runnable for
- * execution
- *
- * @param r
- */
- protected void checkAndEnqueue(Runnable r) {
+ protected Bundle isAllowed(Bundle params) {
try {
if (isCallerAllowed(false)) {
- mThreadPool.execute(r);
- Log.d(Constants.TAG, "Enqueued runnable…");
+ return null;
} else {
String[] callingPackages = getPackageManager().getPackagesForUid(
Binder.getCallingUid());
@@ -121,32 +73,46 @@ public abstract class RemoteService extends Service {
packageSignature = getPackageSignature(packageName);
} catch (NameNotFoundException e) {
Log.e(Constants.TAG, "Should not happen, returning!", e);
- return;
- }
- Log.e(Constants.TAG,
- "Not allowed to use service! Starting activity for registration!");
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
- extras.putByteArray(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
- RegisterActivityCallback callback = new RegisterActivityCallback();
-
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback,
- extras);
-
- if (callback.isAllowed()) {
- mThreadPool.execute(r);
- Log.d(Constants.TAG, "Enqueued runnable…");
- } else {
- Log.d(Constants.TAG, "User disallowed app!");
+ // return error
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
+ Log.e(Constants.TAG, "Not allowed to use service! return PendingIntent for registration!");
+
+ Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
+ intent.setAction(RemoteServiceActivity.ACTION_REGISTER);
+ intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
+ intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
}
} catch (WrongPackageSignatureException e) {
- Log.e(Constants.TAG, e.getMessage());
+ Log.e(Constants.TAG, "wrong signature!", e);
+
+ Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
+ intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
+ intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
+ intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
- getString(R.string.api_error_wrong_signature));
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, extras);
+ return result;
}
}
@@ -161,40 +127,8 @@ public abstract class RemoteService extends Service {
}
/**
- * Locks current thread and pauses execution of runnables and starts activity for user input
- *
- * @param action
- * @param messenger
- * @param extras
- */
- protected void pauseAndStartUserInteraction(String action, BaseCallback callback, Bundle extras) {
- synchronized (userInputLock) {
- mThreadPool.pause();
-
- Log.d(Constants.TAG, "starting activity...");
- Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction(action);
-
- Messenger messenger = new Messenger(new Handler(getMainLooper(), callback));
-
- extras.putParcelable(RemoteServiceActivity.EXTRA_MESSENGER, messenger);
- intent.putExtras(extras);
-
- startActivity(intent);
-
- // lock current thread for user input
- try {
- userInputLock.wait();
- } catch (InterruptedException e) {
- Log.e(Constants.TAG, "CryptoService", e);
- }
- }
- }
-
- /**
* Retrieves AppSettings from database for the application calling this remote service
- *
+ *
* @return
*/
protected AppSettings getAppSettings() {
@@ -215,66 +149,11 @@ public abstract class RemoteService extends Service {
return null;
}
- class RegisterActivityCallback extends BaseCallback {
- public static final String PACKAGE_NAME = "package_name";
-
- private boolean allowed = false;
- private String packageName;
-
- public boolean isAllowed() {
- return allowed;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- if (msg.arg1 == OKAY) {
- allowed = true;
- packageName = msg.getData().getString(PACKAGE_NAME);
-
- // resume threads
- try {
- if (isPackageAllowed(packageName)) {
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- } else {
- // Should not happen!
- Log.e(Constants.TAG, "Should not happen! Emergency shutdown!");
- mThreadPool.shutdownNow();
- }
- } catch (WrongPackageSignatureException e) {
- Log.e(Constants.TAG, e.getMessage());
-
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
- getString(R.string.api_error_wrong_signature));
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null,
- extras);
- }
- } else {
- allowed = false;
-
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- }
- return true;
- }
-
- }
-
/**
* Checks if process that binds to this service (i.e. the package name corresponding to the
* process) is in the list of allowed package names.
- *
- * @param allowOnlySelf
- * allow only Keychain app itself
+ *
+ * @param allowOnlySelf allow only Keychain app itself
* @return true if process is allowed to use this service
* @throws WrongPackageSignatureException
*/
@@ -308,7 +187,7 @@ public abstract class RemoteService extends Service {
/**
* Checks if packageName is a registered app for the API. Does not return true for own package!
- *
+ *
* @param packageName
* @return
* @throws WrongPackageSignatureException
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java
index f1e203733..af8e3ade8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,8 +17,15 @@
package org.sufficientlysecure.keychain.service.remote;
-import java.util.ArrayList;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v7.app.ActionBarActivity;
+import android.view.View;
+import org.openintents.openpgp.util.OpenPgpConstants;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -30,15 +37,7 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v7.app.ActionBarActivity;
-import android.view.View;
-import android.widget.Toast;
+import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
@@ -64,17 +63,11 @@ public class RemoteServiceActivity extends ActionBarActivity {
// error message
public static final String EXTRA_ERROR_MESSAGE = "error_message";
- private Messenger mMessenger;
-
// register view
private AppSettingsFragment mSettingsFragment;
// select pub keys view
private SelectPublicKeyFragment mSelectFragment;
- // has the user clicked one of the buttons
- // or do we need to handle the callback in onStop()
- private boolean finishHandled;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -82,36 +75,12 @@ public class RemoteServiceActivity extends ActionBarActivity {
handleActions(getIntent(), savedInstanceState);
}
- @Override
- protected void onStop() {
- super.onStop();
-
- if (!finishHandled) {
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
- }
- }
-
protected void handleActions(Intent intent, Bundle savedInstanceState) {
- finishHandled = false;
String action = intent.getAction();
- Bundle extras = intent.getExtras();
+ final Bundle extras = intent.getExtras();
- if (extras == null) {
- extras = new Bundle();
- }
- mMessenger = extras.getParcelable(EXTRA_MESSENGER);
-
- /**
- * com.android.crypto actions
- */
if (ACTION_REGISTER.equals(action)) {
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
@@ -125,44 +94,27 @@ public class RemoteServiceActivity extends ActionBarActivity {
// user needs to select a key!
if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) {
- Toast.makeText(RemoteServiceActivity.this,
- R.string.api_register_error_select_key, Toast.LENGTH_LONG)
- .show();
+ mSettingsFragment.setErrorOnSelectKeyFragment(
+ getString(R.string.api_register_error_select_key));
} else {
ProviderHelper.insertApiApp(RemoteServiceActivity.this,
mSettingsFragment.getAppSettings());
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.OKAY;
- Bundle data = new Bundle();
- data.putString(RemoteService.RegisterActivityCallback.PACKAGE_NAME,
- packageName);
- msg.setData(data);
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ // give params through for new service call
+ Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
+
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
+ RemoteServiceActivity.this.finish();
}
}
}, R.string.api_register_disallow, new View.OnClickListener() {
@Override
public void onClick(View v) {
// Disallow
-
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
+ RemoteServiceActivity.this.finish();
}
}
);
@@ -176,8 +128,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
mSettingsFragment.setAppSettings(settings);
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
+ Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
- showPassphraseDialog(secretKeyId);
+ showPassphraseDialog(oldParams, secretKeyId);
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
ArrayList<String> missingUserIds = intent
@@ -185,8 +138,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
ArrayList<String> dublicateUserIds = intent
.getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);
- String text = new String();
- text += "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>";
+ // TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids
+ String text = "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>";
text += "<br/><br/>";
if (missingUserIds != null && missingUserIds.size() > 0) {
text += getString(R.string.api_select_pub_keys_missing_text);
@@ -213,40 +166,22 @@ public class RemoteServiceActivity extends ActionBarActivity {
new View.OnClickListener() {
@Override
public void onClick(View v) {
- // ok
-
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.OKAY;
- Bundle data = new Bundle();
- data.putLongArray(
- OpenPgpService.SelectPubKeysActivityCallback.PUB_KEY_IDS,
+ // add key ids to params Bundle for new request
+ Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
+ params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS,
mSelectFragment.getSelectedMasterKeyIds());
- msg.setData(data);
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
- finishHandled = true;
- finish();
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
+ RemoteServiceActivity.this.finish();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
-
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.CANCEL;
- ;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
+ RemoteServiceActivity.this.finish();
}
}
);
@@ -279,8 +214,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
} else if (ACTION_ERROR_MESSAGE.equals(action)) {
String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE);
- String text = new String();
- text += "<font color=\"red\">" + errorMessage + "</font>";
+ String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view
ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay,
@@ -288,7 +222,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
@Override
public void onClick(View v) {
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_OK);
+ RemoteServiceActivity.this.finish();
}
});
@@ -298,7 +233,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text);
textView.setHtmlFromString(text);
} else {
- Log.e(Constants.TAG, "Wrong action!");
+ Log.e(Constants.TAG, "Action does not exist!");
+ setResult(RESULT_CANCELED);
finish();
}
}
@@ -308,31 +244,21 @@ public class RemoteServiceActivity extends ActionBarActivity {
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
* for a symmetric passphrase
*/
- private void showPassphraseDialog(long secretKeyId) {
+ private void showPassphraseDialog(final Bundle params, long secretKeyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.PassphraseActivityCallback.OKAY;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
+ // return given params again, for calling the service method again
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
} else {
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.PassphraseActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
}
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.finish();
}
};
@@ -345,9 +271,12 @@ public class RemoteServiceActivity extends ActionBarActivity {
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
- Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
- // send message to handler to start encryption directly
- returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
+ Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!");
+ // return given params again, for calling the service method again
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ setResult(RESULT_OK, finishIntent);
+ finish();
}
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
index cef002265..cc08548e8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
@@ -1,4 +1,4 @@
-package org.sufficientlysecure.keychain.service.exception;
+package org.sufficientlysecure.keychain.service.remote;
public class WrongPackageSignatureException extends Exception {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SignKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index d9fb294d5..aab6b81d9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SignKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -56,7 +56,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
/**
* Signs the specified public key with the specified secret master key
*/
-public class SignKeyActivity extends ActionBarActivity implements
+public class CertifyKeyActivity extends ActionBarActivity implements
SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
private BootstrapButton mSignButton;
private CheckBox mUploadKeyCheckbox;
@@ -72,7 +72,7 @@ public class SignKeyActivity extends ActionBarActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.sign_key_activity);
+ setContentView(R.layout.certify_key_activity);
final ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(true);
@@ -164,8 +164,8 @@ public class SignKeyActivity extends ActionBarActivity implements
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
- Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
- // send message to handler to start encryption directly
+ Log.d(Constants.TAG, "No passphrase for this secret key!");
+ // send message to handler to start certification directly
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
}
}
@@ -196,8 +196,8 @@ public class SignKeyActivity extends ActionBarActivity implements
String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId);
if (passphrase == null) {
showPassphraseDialog(mMasterKeyId);
- return; // bail out; need to wait until the user has entered the passphrase
- // before trying again
+ // bail out; need to wait until the user has entered the passphrase before trying again
+ return;
} else {
startSigning();
}
@@ -218,13 +218,13 @@ public class SignKeyActivity extends ActionBarActivity implements
// Send all information needed to service to sign key in other thread
Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_SIGN_KEYRING);
+ intent.setAction(KeychainIntentService.ACTION_CERTIFY_KEYRING);
// fill values for this action
Bundle data = new Bundle();
- data.putLong(KeychainIntentService.SIGN_KEY_MASTER_KEY_ID, mMasterKeyId);
- data.putLong(KeychainIntentService.SIGN_KEY_PUB_KEY_ID, mPubKeyId);
+ data.putLong(KeychainIntentService.CERTIFY_KEY_MASTER_KEY_ID, mMasterKeyId);
+ data.putLong(KeychainIntentService.CERTIFY_KEY_PUB_KEY_ID, mPubKeyId);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@@ -237,14 +237,12 @@ public class SignKeyActivity extends ActionBarActivity implements
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Toast.makeText(SignKeyActivity.this, R.string.key_sign_success,
+ Toast.makeText(CertifyKeyActivity.this, R.string.key_sign_success,
Toast.LENGTH_SHORT).show();
// check if we need to send the key to the server or not
if (mUploadKeyCheckbox.isChecked()) {
- /*
- * upload the newly signed key to the key server
- */
+ // upload the newly signed key to the keyserver
uploadKey();
} else {
setResult(RESULT_OK);
@@ -291,7 +289,7 @@ public class SignKeyActivity extends ActionBarActivity implements
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Toast.makeText(SignKeyActivity.this, R.string.key_send_success,
+ Toast.makeText(CertifyKeyActivity.this, R.string.key_send_success,
Toast.LENGTH_SHORT).show();
setResult(RESULT_OK);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 26657479f..652310cd2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.LookupUnknownKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
@@ -61,7 +60,7 @@ import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
@@ -78,14 +77,20 @@ public class DecryptActivity extends DrawerActivity {
/* EXTRA keys for input */
public static final String EXTRA_TEXT = "text";
+ private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
+ private static final int RESULT_CODE_FILE = 0x00007003;
+
private long mSignatureKeyId = 0;
private boolean mReturnResult = false;
+
+ // TODO: replace signed only checks with something more intelligent
+ // PgpDecryptVerify should handle all automatically!!!
private boolean mSignedOnly = false;
private boolean mAssumeSymmetricEncryption = false;
private EditText mMessage = null;
- private LinearLayout mSignatureLayout = null;
+ private RelativeLayout mSignatureLayout = null;
private ImageView mSignatureStatusImage = null;
private TextView mUserId = null;
private TextView mUserIdRest = null;
@@ -100,6 +105,7 @@ public class DecryptActivity extends DrawerActivity {
private EditText mFilename = null;
private CheckBox mDeleteAfter = null;
private BootstrapButton mBrowse = null;
+ private BootstrapButton mLookupKey = null;
private String mInputFilename = null;
private String mOutputFilename = null;
@@ -107,14 +113,10 @@ public class DecryptActivity extends DrawerActivity {
private Uri mContentUri = null;
private boolean mReturnBinary = false;
- private long mUnknownSignatureKeyId = 0;
-
private long mSecretKeyId = Id.key.none;
private FileDialogFragment mFileDialog;
- private boolean mLookupUnknownKey = true;
-
private boolean mDecryptImmediately = false;
private BootstrapButton mDecryptButton;
@@ -154,7 +156,7 @@ public class DecryptActivity extends DrawerActivity {
mSourceLabel.setOnClickListener(nextSourceClickListener);
mMessage = (EditText) findViewById(R.id.message);
- mSignatureLayout = (LinearLayout) findViewById(R.id.signature);
+ mSignatureLayout = (RelativeLayout) findViewById(R.id.signature);
mSignatureStatusImage = (ImageView) findViewById(R.id.ic_signature_status);
mUserId = (TextView) findViewById(R.id.mainUserId);
mUserIdRest = (TextView) findViewById(R.id.mainUserIdRest);
@@ -171,7 +173,15 @@ public class DecryptActivity extends DrawerActivity {
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FileHelper.openFile(DecryptActivity.this, mFilename.getText().toString(), "*/*",
- Id.request.filename);
+ RESULT_CODE_FILE);
+ }
+ });
+
+ mLookupKey = (BootstrapButton) findViewById(R.id.lookup_key);
+ mLookupKey.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ lookupUnknownKey(mSignatureKeyId);
}
});
@@ -239,7 +249,7 @@ public class DecryptActivity extends DrawerActivity {
DecryptActivity.this, mSignatureKeyId);
if (key != null) {
Intent intent = new Intent(DecryptActivity.this, ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, mSignatureKeyId);
startActivity(intent);
}
@@ -263,14 +273,14 @@ public class DecryptActivity extends DrawerActivity {
if (mDecryptImmediately
|| (mSource.getCurrentView().getId() == R.id.sourceMessage && (mMessage.getText()
- .length() > 0 || mContentUri != null))) {
+ .length() > 0 || mContentUri != null))) {
decryptClicked();
}
}
/**
* Handles all actions with this intent
- *
+ *
* @param intent
*/
private void handleActions(Intent intent) {
@@ -287,13 +297,13 @@ public class DecryptActivity extends DrawerActivity {
* Android's Action
*/
if (Intent.ACTION_SEND.equals(action) && type != null) {
- // When sending to Keychain Encrypt via share menu
+ // When sending to Keychain Decrypt via share menu
if ("text/plain".equals(type)) {
// Plain text
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null) {
// handle like normal text decryption, override action and extras to later
- // execute ACTION_DECRYPT in main actions
+ // executeServiceMethod ACTION_DECRYPT in main actions
extras.putString(EXTRA_TEXT, sharedText);
action = ACTION_DECRYPT;
}
@@ -375,21 +385,21 @@ public class DecryptActivity extends DrawerActivity {
private void updateSource() {
switch (mSource.getCurrentView().getId()) {
- case R.id.sourceFile: {
- mSourceLabel.setText(R.string.label_file);
- mDecryptButton.setText(getString(R.string.btn_decrypt));
- break;
- }
+ case R.id.sourceFile: {
+ mSourceLabel.setText(R.string.label_file);
+ mDecryptButton.setText(getString(R.string.btn_decrypt));
+ break;
+ }
- case R.id.sourceMessage: {
- mSourceLabel.setText(R.string.label_message);
- mDecryptButton.setText(getString(R.string.btn_decrypt));
- break;
- }
+ case R.id.sourceMessage: {
+ mSourceLabel.setText(R.string.label_message);
+ mDecryptButton.setText(getString(R.string.btn_decrypt));
+ break;
+ }
- default: {
- break;
- }
+ default: {
+ break;
+ }
}
}
@@ -449,7 +459,7 @@ public class DecryptActivity extends DrawerActivity {
} else {
if (mDecryptTarget == Id.target.file) {
askForOutputFilename();
- } else {
+ } else { // mDecryptTarget == Id.target.message
decryptStart();
}
}
@@ -527,7 +537,7 @@ public class DecryptActivity extends DrawerActivity {
try {
if (inStream.markSupported()) {
inStream.mark(200); // should probably set this to the max size of two pgpF
- // objects, if it even needs to be anything other than 0.
+ // objects, if it even needs to be anything other than 0.
}
mSecretKeyId = PgpHelper.getDecryptionKeyId(this, inStream);
if (mSecretKeyId == Id.key.none) {
@@ -539,7 +549,7 @@ public class DecryptActivity extends DrawerActivity {
inStream.reset();
}
mSecretKeyId = Id.key.symmetric;
- if (!PgpOperation.hasSymmetricEncryption(this, inStream)) {
+ if (!PgpDecryptVerify.hasSymmetricEncryption(this, inStream)) {
throw new PgpGeneralException(
getString(R.string.error_no_known_encryption_found));
}
@@ -559,7 +569,7 @@ public class DecryptActivity extends DrawerActivity {
data = "\n\n" + data;
intent.putExtra(EncryptActivity.EXTRA_TEXT, data);
intent.putExtra(EncryptActivity.EXTRA_SIGNATURE_KEY_ID, mSecretKeyId);
- intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, new long[] { mSignatureKeyId });
+ intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, new long[]{mSignatureKeyId});
startActivity(intent);
}
@@ -587,28 +597,10 @@ public class DecryptActivity extends DrawerActivity {
}
private void lookupUnknownKey(long unknownKeyId) {
- // Message is received after passphrase is cached
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == LookupUnknownKeyDialogFragment.MESSAGE_OKAY) {
- // the result is handled by onActivityResult() as LookupUnknownKeyDialogFragment
- // starts a new Intent which then returns data
- } else if (message.what == LookupUnknownKeyDialogFragment.MESSAGE_CANCEL) {
- // decrypt again, but don't lookup unknown keys!
- mLookupUnknownKey = false;
- decryptStart();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- LookupUnknownKeyDialogFragment lookupKeyDialog = LookupUnknownKeyDialogFragment
- .newInstance(messenger, unknownKeyId);
-
- lookupKeyDialog.show(getSupportFragmentManager(), "unknownKeyDialog");
+ Intent intent = new Intent(this, ImportKeysActivity.class);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
+ intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId);
+ startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY);
}
private void decryptStart() {
@@ -644,8 +636,6 @@ public class DecryptActivity extends DrawerActivity {
data.putLong(KeychainIntentService.ENCRYPT_SECRET_KEY_ID, mSecretKeyId);
- data.putBoolean(KeychainIntentService.DECRYPT_SIGNED_ONLY, mSignedOnly);
- data.putBoolean(KeychainIntentService.DECRYPT_LOOKUP_UNKNOWN_KEY, mLookupUnknownKey);
data.putBoolean(KeychainIntentService.DECRYPT_RETURN_BYTES, mReturnBinary);
data.putBoolean(KeychainIntentService.DECRYPT_ASSUME_SYMMETRIC, mAssumeSymmetricEncryption);
@@ -662,15 +652,6 @@ public class DecryptActivity extends DrawerActivity {
// get returned data bundle
Bundle returnData = message.getData();
- // if key is unknown show lookup dialog
- if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_LOOKUP_KEY)
- && mLookupUnknownKey) {
- mUnknownSignatureKeyId = returnData
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
- lookupUnknownKey(mUnknownSignatureKeyId);
- return;
- }
-
mSignatureKeyId = 0;
mSignatureLayout.setVisibility(View.GONE);
@@ -685,26 +666,26 @@ public class DecryptActivity extends DrawerActivity {
}
switch (mDecryptTarget) {
- case Id.target.message:
- String decryptedMessage = returnData
- .getString(KeychainIntentService.RESULT_DECRYPTED_STRING);
- mMessage.setText(decryptedMessage);
- mMessage.setHorizontallyScrolling(false);
-
- break;
-
- case Id.target.file:
- if (mDeleteAfter.isChecked()) {
- // Create and show dialog to delete original file
- DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
- .newInstance(mInputFilename);
- deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
- }
- break;
-
- default:
- // shouldn't happen
- break;
+ case Id.target.message:
+ String decryptedMessage = returnData
+ .getString(KeychainIntentService.RESULT_DECRYPTED_STRING);
+ mMessage.setText(decryptedMessage);
+ mMessage.setHorizontallyScrolling(false);
+
+ break;
+
+ case Id.target.file:
+ if (mDeleteAfter.isChecked()) {
+ // Create and show dialog to delete original file
+ DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
+ .newInstance(mInputFilename);
+ deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
+ }
+ break;
+
+ default:
+ // shouldn't happen
+ break;
}
@@ -727,19 +708,24 @@ public class DecryptActivity extends DrawerActivity {
if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) {
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
+ mLookupKey.setVisibility(View.GONE);
} else if (returnData
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ mLookupKey.setVisibility(View.VISIBLE);
Toast.makeText(DecryptActivity.this,
- R.string.unknown_signature_key_touch_to_look_up,
+ R.string.unknown_signature,
Toast.LENGTH_LONG).show();
} else {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ mLookupKey.setVisibility(View.GONE);
}
mSignatureLayout.setVisibility(View.VISIBLE);
}
}
- };
+ }
+
+ ;
};
// Create a new Messenger for the communication back
@@ -756,36 +742,37 @@ public class DecryptActivity extends DrawerActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case Id.request.filename: {
- if (resultCode == RESULT_OK && data != null) {
- try {
- String path = FileHelper.getPath(this, data.getData());
- Log.d(Constants.TAG, "path=" + path);
-
- mFilename.setText(path);
- } catch (NullPointerException e) {
- Log.e(Constants.TAG, "Nullpointer while retrieving path!");
+ case RESULT_CODE_FILE: {
+ if (resultCode == RESULT_OK && data != null) {
+ try {
+ String path = FileHelper.getPath(this, data.getData());
+ Log.d(Constants.TAG, "path=" + path);
+
+ mFilename.setText(path);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Nullpointer while retrieving path!");
+ }
}
+ return;
}
- return;
- }
- // this request is returned after LookupUnknownKeyDialogFragment started
- // ImportKeysActivity and user looked uo key
- case Id.request.look_up_key_id: {
- Log.d(Constants.TAG, "Returning from Lookup Key...");
- // decrypt again without lookup
- mLookupUnknownKey = false;
- decryptStart();
- return;
- }
+ // this request is returned after LookupUnknownKeyDialogFragment started
+ // ImportKeysActivity and user looked uo key
+ case RESULT_CODE_LOOKUP_KEY: {
+ Log.d(Constants.TAG, "Returning from Lookup Key...");
+ if (resultCode == RESULT_OK) {
+ // decrypt again
+ decryptStart();
+ }
+ return;
+ }
- default: {
- break;
- }
- }
+ default: {
+ super.onActivityResult(requestCode, resultCode, data);
- super.onActivityResult(requestCode, resultCode, data);
+ break;
+ }
+ }
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index 81446db99..85bfba224 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -173,7 +173,7 @@ public class EncryptActivity extends DrawerActivity {
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null) {
// handle like normal text encryption, override action and extras to later
- // execute ACTION_ENCRYPT in main actions
+ // executeServiceMethod ACTION_ENCRYPT in main actions
extras.putString(EXTRA_TEXT, sharedText);
extras.putBoolean(EXTRA_ASCII_ARMOR, true);
action = ACTION_ENCRYPT;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
index be7c50dbb..12d689274 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
@@ -33,18 +33,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
-public class HelpFragmentAbout extends Fragment {
-
- /**
- * Workaround for Android Bug. See
- * http://stackoverflow.com/questions/8748064/starting-activity-from
- * -fragment-causes-nullpointerexception
- */
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- setUserVisibleHint(true);
- }
+public class HelpAboutFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
index 2fe7c56e6..9ccd7e088 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
@@ -20,12 +20,13 @@ package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
@@ -37,8 +38,6 @@ public class HelpActivity extends ActionBarActivity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
- TextView tabCenter;
- TextView tabText;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -63,93 +62,21 @@ public class HelpActivity extends ActionBarActivity {
}
Bundle startBundle = new Bundle();
- startBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_start);
+ startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)),
- HelpFragmentHtml.class, startBundle, (selectedTab == 0 ? true : false));
+ HelpHtmlFragment.class, startBundle, (selectedTab == 0 ? true : false));
Bundle nfcBundle = new Bundle();
- nfcBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_nfc_beam);
+ nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)),
- HelpFragmentHtml.class, nfcBundle, (selectedTab == 1 ? true : false));
+ HelpHtmlFragment.class, nfcBundle, (selectedTab == 1 ? true : false));
Bundle changelogBundle = new Bundle();
- changelogBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_changelog);
+ changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)),
- HelpFragmentHtml.class, changelogBundle, (selectedTab == 2 ? true : false));
+ HelpHtmlFragment.class, changelogBundle, (selectedTab == 2 ? true : false));
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)),
- HelpFragmentAbout.class, null, (selectedTab == 3 ? true : false));
- }
-
- public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener,
- ViewPager.OnPageChangeListener {
- private final Context mContext;
- private final ActionBar mActionBar;
- private final ViewPager mViewPager;
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
-
- static final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
-
- TabInfo(Class<?> _class, Bundle _args) {
- clss = _class;
- args = _args;
- }
- }
-
- public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- mContext = activity;
- mActionBar = activity.getSupportActionBar();
- mViewPager = pager;
- mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
- }
-
- public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, boolean selected) {
- TabInfo info = new TabInfo(clss, args);
- tab.setTag(info);
- tab.setTabListener(this);
- mTabs.add(info);
- mActionBar.addTab(tab, selected);
- notifyDataSetChanged();
- }
-
- @Override
- public int getCount() {
- return mTabs.size();
- }
-
- @Override
- public Fragment getItem(int position) {
- TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(), info.args);
- }
-
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- }
-
- public void onPageSelected(int position) {
- mActionBar.setSelectedNavigationItem(position);
- }
-
- public void onPageScrollStateChanged(int state) {
- }
-
- public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
- Object tag = tab.getTag();
- for (int i = 0; i < mTabs.size(); i++) {
- if (mTabs.get(i) == tag) {
- mViewPager.setCurrentItem(i);
- }
- }
- }
-
- public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
- }
-
- public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
- }
+ HelpAboutFragment.class, null, (selectedTab == 3 ? true : false));
}
} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java
index fb6747db0..3afb5bbe0 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java
@@ -28,7 +28,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
-public class HelpFragmentHtml extends Fragment {
+public class HelpHtmlFragment extends Fragment {
private Activity mActivity;
private int htmlFile;
@@ -36,10 +36,10 @@ public class HelpFragmentHtml extends Fragment {
public static final String ARG_HTML_FILE = "htmlFile";
/**
- * Create a new instance of HelpFragmentHtml, providing "htmlFile" as an argument.
+ * Create a new instance of HelpHtmlFragment, providing "htmlFile" as an argument.
*/
- static HelpFragmentHtml newInstance(int htmlFile) {
- HelpFragmentHtml f = new HelpFragmentHtml();
+ static HelpHtmlFragment newInstance(int htmlFile) {
+ HelpHtmlFragment f = new HelpHtmlFragment();
// Supply html raw file input as an argument.
Bundle args = new Bundle();
@@ -49,17 +49,6 @@ public class HelpFragmentHtml extends Fragment {
return f;
}
- /**
- * Workaround for Android Bug. See
- * http://stackoverflow.com/questions/8748064/starting-activity-from
- * -fragment-causes-nullpointerexception
- */
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- setUserVisibleHint(true);
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mActivity = getActivity();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index dc3a07def..a5027ac1c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2011 Senecaso
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,16 +47,19 @@ import android.support.v7.app.ActionBar;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
-import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
+import com.devspark.appmsg.AppMsg;
public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener {
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_QR_CODE";
- public static final String ACTION_IMPORT_KEY_FROM_KEY_SERVER = Constants.INTENT_PREFIX
- + "IMPORT_KEY_FROM_KEY_SERVER";
+ public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX
+ + "IMPORT_KEY_FROM_KEYSERVER";
+ // TODO: implement:
+ public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX
+ + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN";
// Actions for internal use only:
public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX
@@ -67,7 +70,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// only used by ACTION_IMPORT_KEY
public static final String EXTRA_KEY_BYTES = "key_bytes";
- // only used by ACTION_IMPORT_KEY_FROM_KEY_SERVER
+ // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER
public static final String EXTRA_QUERY = "query";
public static final String EXTRA_KEY_ID = "key_id";
public static final String EXTRA_FINGERPRINT = "fingerprint";
@@ -78,6 +81,16 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
private Fragment mCurrentFragment;
private BootstrapButton mImportButton;
+ private static final Class[] NAVIGATION_CLASSES = new Class[]{
+ ImportKeysServerFragment.class,
+ ImportKeysFileFragment.class,
+ ImportKeysQrCodeFragment.class,
+ ImportKeysClipboardFragment.class,
+ ImportKeysNFCFragment.class
+ };
+
+ private int mCurrentNavPostition = -1;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -107,6 +120,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
handleActions(savedInstanceState, getIntent());
}
+
protected void handleActions(Bundle savedInstanceState, Intent intent) {
String action = intent.getAction();
Bundle extras = intent.getExtras();
@@ -125,24 +139,23 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) {
/* Scanning a fingerprint directly with Barcode Scanner */
- getSupportActionBar().setSelectedNavigationItem(0);
- loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[0]);
- loadFromFingerprintUri(dataUri);
+ loadFromFingerprintUri(savedInstanceState, dataUri);
} else if (ACTION_IMPORT_KEY.equals(action)) {
/* Keychain's own Actions */
- getSupportActionBar().setSelectedNavigationItem(1);
- loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[1]);
+
+ // display file fragment
+ loadNavFragment(1, null);
if (dataUri != null) {
- // directly load data
+ // action: directly load data
startListFragment(savedInstanceState, null, dataUri, null);
} else if (extras.containsKey(EXTRA_KEY_BYTES)) {
byte[] importData = intent.getByteArrayExtra(EXTRA_KEY_BYTES);
- // directly load data
+ // action: directly load data
startListFragment(savedInstanceState, importData, null, null);
}
- } else if (ACTION_IMPORT_KEY_FROM_KEY_SERVER.equals(action)) {
+ } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action)) {
String query = null;
if (extras.containsKey(EXTRA_QUERY)) {
query = extras.getString(EXTRA_QUERY);
@@ -161,82 +174,97 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
return;
}
- // search directly
- getSupportActionBar().setSelectedNavigationItem(0);
+ // display keyserver fragment with query
Bundle args = new Bundle();
args.putString(ImportKeysServerFragment.ARG_QUERY, query);
- loadFragment(ImportKeysServerFragment.class, args, mNavigationStrings[0]);
+ loadNavFragment(0, args);
+ // action: search immediately
startListFragment(savedInstanceState, null, null, query);
- } else {
- // Other actions
+ } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) {
+
+ // NOTE: this only displays the appropriate fragment, no actions are taken
+ loadNavFragment(1, null);
+
+ // no immediate actions!
startListFragment(savedInstanceState, null, null, null);
+ } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) {
+ // also exposed in AndroidManifest
- if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) {
- getSupportActionBar().setSelectedNavigationItem(1);
- loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[1]);
- } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) {
- // also exposed in AndroidManifest
- getSupportActionBar().setSelectedNavigationItem(2);
- loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[2]);
- } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) {
- getSupportActionBar().setSelectedNavigationItem(3);
- loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[3]);
- }
+ // NOTE: this only displays the appropriate fragment, no actions are taken
+ loadNavFragment(2, null);
+
+ // no immediate actions!
+ startListFragment(savedInstanceState, null, null, null);
+ } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) {
+
+ // NOTE: this only displays the appropriate fragment, no actions are taken
+ loadNavFragment(3, null);
+
+ // no immediate actions!
+ startListFragment(savedInstanceState, null, null, null);
+ } else {
+ startListFragment(savedInstanceState, null, null, null);
}
}
private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) {
- // Check that the activity is using the layout version with
- // the fragment_container FrameLayout
- if (findViewById(R.id.import_keys_list_container) != null) {
-
- // However, if we're being restored from a previous state,
- // then we don't need to do anything and should return or else
- // we could end up with overlapping fragments.
- if (savedInstanceState != null) {
- return;
- }
+ // However, if we're being restored from a previous state,
+ // then we don't need to do anything and should return or else
+ // we could end up with overlapping fragments.
+ if (savedInstanceState != null) {
+ return;
+ }
- // Create an instance of the fragment
- mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery);
+ // Create an instance of the fragment
+ mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery);
- // Add the fragment to the 'fragment_container' FrameLayout
- // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.import_keys_list_container, mListFragment)
- .commitAllowingStateLoss();
- // do it immediately!
- getSupportFragmentManager().executePendingTransactions();
- }
+ // Add the fragment to the 'fragment_container' FrameLayout
+ // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.import_keys_list_container, mListFragment)
+ .commitAllowingStateLoss();
+ // do it immediately!
+ getSupportFragmentManager().executePendingTransactions();
}
+ /**
+ * "Basically, when using a list navigation, onNavigationItemSelected() is automatically
+ * called when your activity is created/re-created, whether you like it or not. To prevent
+ * your Fragment's onCreateView() from being called twice, this initial automatic call to
+ * onNavigationItemSelected() should check whether the Fragment is already in existence
+ * inside your Activity."
+ * <p/>
+ * from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474
+ *
+ * In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint,
+ * the fragment would be loaded twice resulting in the query being empty after the second load.
+ *
+ * Our solution:
+ * To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment
+ * checks against mCurrentNavPostition.
+ *
+ * @param itemPosition
+ * @param itemId
+ * @return
+ */
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
- // Create new fragment from our own Fragment class
- switch (itemPosition) {
- case 0:
- loadFragment(ImportKeysServerFragment.class, null, mNavigationStrings[itemPosition]);
- break;
- case 1:
- loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[itemPosition]);
- break;
- case 2:
- loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[itemPosition]);
- break;
- case 3:
- loadFragment(ImportKeysClipboardFragment.class, null, mNavigationStrings[itemPosition]);
- break;
- case 4:
- loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[itemPosition]);
- break;
-
- default:
- break;
- }
+ Log.d(Constants.TAG, "onNavigationItemSelected");
+
+ loadNavFragment(itemPosition, null);
+
return true;
}
+ private void loadNavFragment(int itemPosition, Bundle args) {
+ if (mCurrentNavPostition != itemPosition) {
+ getSupportActionBar().setSelectedNavigationItem(itemPosition);
+ loadFragment(NAVIGATION_CLASSES[itemPosition], args, mNavigationStrings[itemPosition]);
+ mCurrentNavPostition = itemPosition;
+ }
+ }
+
private void loadFragment(Class<?> clss, Bundle args, String tag) {
mCurrentFragment = Fragment.instantiate(this, clss.getName(), args);
@@ -248,26 +276,26 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
ft.commit();
}
- public void loadFromFingerprintUri(Uri dataUri) {
+ public void loadFromFingerprintUri(Bundle savedInstanceState, Uri dataUri) {
String fingerprint = dataUri.toString().split(":")[1].toLowerCase(Locale.ENGLISH);
Log.d(Constants.TAG, "fingerprint: " + fingerprint);
if (fingerprint.length() < 16) {
- Toast.makeText(this, R.string.import_qr_code_too_short_fingerprint,
- Toast.LENGTH_LONG).show();
+ AppMsg.makeText(this, R.string.import_qr_code_too_short_fingerprint,
+ AppMsg.STYLE_ALERT).show();
return;
}
String query = "0x" + fingerprint;
- // search directly
- getSupportActionBar().setSelectedNavigationItem(0);
+ // display keyserver fragment with query
Bundle args = new Bundle();
args.putString(ImportKeysServerFragment.ARG_QUERY, query);
- loadFragment(ImportKeysServerFragment.class, args, mNavigationStrings[0]);
+ loadNavFragment(0, args);
- startListFragment(null, null, null, query);
+ // action: search directly
+ startListFragment(savedInstanceState, null, null, query);
}
public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer) {
@@ -364,7 +392,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
} else {
toastMessage = getString(R.string.no_keys_added_or_updated);
}
- Toast.makeText(ImportKeysActivity.this, toastMessage, Toast.LENGTH_SHORT)
+ AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
.show();
if (bad > 0) {
AlertDialog.Builder alert = new AlertDialog.Builder(
@@ -446,7 +474,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// start service with intent
startService(intent);
} else {
- Toast.makeText(this, R.string.error_nothing_import, Toast.LENGTH_LONG).show();
+ AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show();
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index 68d318491..b52de5bc9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -122,7 +122,7 @@ public class ImportKeysListFragment extends ListFragment implements
mKeyBytes = getArguments().getByteArray(ARG_BYTES);
mServerQuery = getArguments().getString(ARG_SERVER_QUERY);
- // TODO: this is used when scanning QR Code. Currently it simply uses key server nr 0
+ // TODO: this is used when scanning QR Code. Currently it simply uses keyserver nr 0
mKeyServer = Preferences.getPreferences(getActivity())
.getKeyServers()[0];
@@ -136,7 +136,7 @@ public class ImportKeysListFragment extends ListFragment implements
getLoaderManager().initLoader(LOADER_ID_BYTES, null, this);
}
- if (mServerQuery != null) {
+ if (mServerQuery != null && mKeyServer != null) {
// Start out with a progress indicator.
setListShown(false);
@@ -165,14 +165,19 @@ public class ImportKeysListFragment extends ListFragment implements
mServerQuery = serverQuery;
mKeyServer = keyServer;
- // Start out with a progress indicator.
- setListShown(false);
+ if (mKeyBytes != null || mDataUri != null) {
+ // Start out with a progress indicator.
+ setListShown(false);
- if (mKeyBytes != null || mDataUri != null)
getLoaderManager().restartLoader(LOADER_ID_BYTES, null, this);
+ }
+
+ if (mServerQuery != null && mKeyServer != null) {
+ // Start out with a progress indicator.
+ setListShown(false);
- if (mServerQuery != null && mKeyServer != null)
getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this);
+ }
}
@Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
index 63727ad26..ee91b2434 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
@@ -98,22 +98,29 @@ public class ImportKeysQrCodeFragment extends Fragment {
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
resultCode, data);
if (scanResult != null && scanResult.getFormatName() != null) {
+ String scannedContent = scanResult.getContents();
- Log.d(Constants.TAG, "scanResult content: " + scanResult.getContents());
+ Log.d(Constants.TAG, "scannedContent: " + scannedContent);
// look if it's fingerprint only
- if (scanResult.getContents().toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
+ if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
importFingerprint(Uri.parse(scanResult.getContents()));
return;
}
// look if it is the whole key
- String[] parts = scanResult.getContents().split(",");
+ String[] parts = scannedContent.split(",");
if (parts.length == 3) {
importParts(parts);
return;
}
+ // is this a full key encoded as qr code?
+ if (scannedContent.startsWith("-----BEGIN PGP")) {
+ mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
+ return;
+ }
+
// fail...
Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG)
.show();
@@ -130,7 +137,7 @@ public class ImportKeysQrCodeFragment extends Fragment {
}
public void importFingerprint(Uri dataUri) {
- mImportActivity.loadFromFingerprintUri(dataUri);
+ mImportActivity.loadFromFingerprintUri(null, dataUri);
}
private void importParts(String[] parts) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
index 2e0956d8b..d77015aa7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
@@ -127,21 +127,21 @@ public class ImportKeysServerFragment extends Fragment {
mImportActivity = (ImportKeysActivity) getActivity();
// set displayed values
- if (getArguments() != null && getArguments().containsKey(ARG_QUERY)) {
- String query = getArguments().getString(ARG_QUERY);
- mQueryEditText.setText(query, TextView.BufferType.EDITABLE);
+ if (getArguments() != null) {
+ if (getArguments().containsKey(ARG_QUERY)) {
+ String query = getArguments().getString(ARG_QUERY);
+ mQueryEditText.setText(query, TextView.BufferType.EDITABLE);
+
+ Log.d(Constants.TAG, "query: " + query);
+ }
- String keyServer = null;
if (getArguments().containsKey(ARG_KEY_SERVER)) {
- keyServer = getArguments().getString(ARG_KEY_SERVER);
+ String keyServer = getArguments().getString(ARG_KEY_SERVER);
int keyServerPos = mServerAdapter.getPosition(keyServer);
mServerSpinner.setSelection(keyServerPos);
- } else {
- keyServer = (String) mServerSpinner.getSelectedItem();
- }
- Log.d(Constants.TAG, "query: " + query);
- Log.d(Constants.TAG, "keyServer: " + keyServer);
+ Log.d(Constants.TAG, "keyServer: " + keyServer);
+ }
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
index 6ae2b9bf9..c28d57627 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+import java.util.ArrayList;
import java.util.Set;
import org.sufficientlysecure.keychain.Id;
@@ -30,12 +31,16 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
+
import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
@@ -50,6 +55,7 @@ import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
@@ -63,7 +69,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
private KeyListPublicAdapter mAdapter;
private StickyListHeadersListView mStickyList;
- // empty layout
+ // empty list layout
private BootstrapButton mButtonEmptyCreate;
private BootstrapButton mButtonEmptyImport;
@@ -92,9 +98,9 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
@Override
public void onClick(View v) {
- Intent intentImportFromFile = new Intent(getActivity(), ImportKeysActivity.class);
- intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
- startActivityForResult(intentImportFromFile, 0);
+ Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
+ startActivityForResult(intent, 0);
}
});
@@ -109,7 +115,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- // mKeyListPublicActivity = (KeyListPublicActivity) getActivity();
mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list);
mStickyList.setOnItemClickListener(this);
@@ -159,18 +164,16 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
}
switch (item.getItemId()) {
- case R.id.menu_key_list_public_multi_encrypt: {
- encrypt(ids);
-
- break;
- }
- case R.id.menu_key_list_public_multi_delete: {
- showDeleteKeyDialog(ids);
-
- break;
- }
+ case R.id.menu_key_list_public_multi_encrypt: {
+ encrypt(mode, ids);
+ break;
+ }
+ case R.id.menu_key_list_public_multi_delete: {
+ showDeleteKeyDialog(mode, ids);
+ break;
+ }
}
- return false;
+ return true;
}
@Override
@@ -181,7 +184,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
+ boolean checked) {
if (checked) {
count++;
mAdapter.setNewSelection(position, checked);
@@ -212,8 +215,12 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
}
// These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID,
- UserIds.USER_ID };
+ static final String[] PROJECTION = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.UserIds.USER_ID,
+ KeychainContract.Keys.IS_REVOKED
+ };
static final int USER_ID_INDEX = 2;
@@ -270,7 +277,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
startActivity(viewIntent);
}
- public void encrypt(long[] keyRingRowIds) {
+ public void encrypt(ActionMode mode, long[] keyRingRowIds) {
// get master key ids from row ids
long[] keyRingIds = new long[keyRingRowIds.length];
for (int i = 0; i < keyRingRowIds.length; i++) {
@@ -282,15 +289,44 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingIds);
// used instead of startActivity set actionbar based on callingPackage
startActivityForResult(intent, 0);
+
+ mode.finish();
}
/**
* Show dialog to delete key
- *
+ *
* @param keyRingRowIds
*/
- public void showDeleteKeyDialog(long[] keyRingRowIds) {
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null,
+ public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
+ // Message is received after key is deleted
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
+ Bundle returnData = message.getData();
+ if (returnData != null
+ && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) {
+ ArrayList<String> notDeleted =
+ returnData.getStringArrayList(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED);
+ String notDeletedMsg = "";
+ for (String userId : notDeleted) {
+ notDeletedMsg += userId + "\n";
+ }
+ Toast.makeText(getActivity(), getString(R.string.error_can_not_delete_contacts, notDeletedMsg)
+ + getResources().getQuantityString(R.plurals.error_can_not_delete_info, notDeleted.size()),
+ Toast.LENGTH_LONG).show();
+
+ mode.finish();
+ }
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
keyRingRowIds, Id.type.public_key);
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java
index f2e6131f6..f9d267f27 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+import java.util.ArrayList;
import java.util.Set;
import org.sufficientlysecure.keychain.Id;
@@ -33,6 +34,9 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
@@ -45,6 +49,7 @@ import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Toast;
public class KeyListSecretFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener {
@@ -103,13 +108,12 @@ public class KeyListSecretFragment extends ListFragment implements
}
switch (item.getItemId()) {
- case R.id.menu_key_list_public_multi_delete: {
- showDeleteKeyDialog(ids);
-
- break;
- }
+ case R.id.menu_key_list_public_multi_delete: {
+ showDeleteKeyDialog(mode, ids);
+ break;
+ }
}
- return false;
+ return true;
}
@Override
@@ -120,7 +124,7 @@ public class KeyListSecretFragment extends ListFragment implements
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
+ boolean checked) {
if (checked) {
count++;
mAdapter.setNewSelection(position, checked);
@@ -153,8 +157,8 @@ public class KeyListSecretFragment extends ListFragment implements
}
// These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID,
- UserIds.USER_ID };
+ static final String[] PROJECTION = new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID,
+ UserIds.USER_ID};
static final String SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC";
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -202,13 +206,27 @@ public class KeyListSecretFragment extends ListFragment implements
/**
* Show dialog to delete key
- *
+ *
* @param keyRingRowIds
*/
- public void showDeleteKeyDialog(long[] keyRingRowIds) {
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null,
+ public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
+ // Message is received after key is deleted
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
+ mode.finish();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
keyRingRowIds, Id.type.secret_key);
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
}
+
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
index e3881503b..550d3047d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
@@ -40,7 +40,7 @@ import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
/**
- * Sends the selected public key to a key server
+ * Sends the selected public key to a keyserver
*/
public class UploadKeyActivity extends ActionBarActivity {
private BootstrapButton mUploadButton;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 99d93fbbd..0a452bc8a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -18,8 +18,17 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.ArrayList;
-import java.util.Date;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -27,63 +36,27 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
-import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.support.v7.app.ActionBarActivity;
-import android.text.format.DateFormat;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
+import java.util.ArrayList;
-public class ViewKeyActivity extends ActionBarActivity implements
- LoaderManager.LoaderCallbacks<Cursor> {
+public class ViewKeyActivity extends ActionBarActivity {
ExportHelper mExportHelper;
protected Uri mDataUri;
- private TextView mName;
- private TextView mEmail;
- private TextView mComment;
- private TextView mAlgorithm;
- private TextView mKeyId;
- private TextView mExpiry;
- private TextView mCreation;
- private TextView mFingerprint;
- private BootstrapButton mActionEncrypt;
-
- private ListView mUserIds;
- private ListView mKeys;
-
- private static final int LOADER_ID_KEYRING = 0;
- private static final int LOADER_ID_USER_IDS = 1;
- private static final int LOADER_ID_KEYS = 2;
- private ViewKeyUserIdsAdapter mUserIdsAdapter;
- private ViewKeyKeysAdapter mKeysAdapter;
+ public static final String EXTRA_SELECTED_TAB = "selectedTab";
+
+ ViewPager mViewPager;
+ TabsAdapter mTabsAdapter;
+
+ private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -91,25 +64,36 @@ public class ViewKeyActivity extends ActionBarActivity implements
mExportHelper = new ExportHelper(this);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setIcon(android.R.color.transparent);
- getSupportActionBar().setHomeButtonEnabled(true);
+ // let the actionbar look like Android's contact app
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setIcon(android.R.color.transparent);
+ actionBar.setHomeButtonEnabled(true);
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
setContentView(R.layout.view_key_activity);
- mName = (TextView) findViewById(R.id.name);
- mEmail = (TextView) findViewById(R.id.email);
- mComment = (TextView) findViewById(R.id.comment);
- mKeyId = (TextView) findViewById(R.id.key_id);
- mAlgorithm = (TextView) findViewById(R.id.algorithm);
- mCreation = (TextView) findViewById(R.id.creation);
- mExpiry = (TextView) findViewById(R.id.expiry);
- mFingerprint = (TextView) findViewById(R.id.fingerprint);
- mActionEncrypt = (BootstrapButton) findViewById(R.id.action_encrypt);
- mUserIds = (ListView) findViewById(R.id.user_ids);
- mKeys = (ListView) findViewById(R.id.keys);
-
- loadData(getIntent());
+ mViewPager = (ViewPager) findViewById(R.id.pager);
+
+ mTabsAdapter = new TabsAdapter(this, mViewPager);
+
+ int selectedTab = 0;
+ Intent intent = getIntent();
+ if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) {
+ selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
+ }
+
+ mDataUri = getIntent().getData();
+
+ Bundle mainBundle = new Bundle();
+ mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri);
+ mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)),
+ ViewKeyMainFragment.class, mainBundle, (selectedTab == 0 ? true : false));
+
+ Bundle certBundle = new Bundle();
+ certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, mDataUri);
+ mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)),
+ ViewKeyCertsFragment.class, certBundle, (selectedTab == 1 ? true : false));
}
@Override
@@ -130,9 +114,6 @@ public class ViewKeyActivity extends ActionBarActivity implements
case R.id.menu_key_view_update:
updateFromKeyserver(mDataUri);
return true;
- case R.id.menu_key_view_sign:
- signKey(mDataUri);
- return true;
case R.id.menu_key_view_export_keyserver:
uploadToKeyserver(mDataUri);
return true;
@@ -159,230 +140,13 @@ public class ViewKeyActivity extends ActionBarActivity implements
copyToClipboard(mDataUri);
return true;
case R.id.menu_key_view_delete: {
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- setResult(RESULT_CANCELED);
- finish();
- }
- }
- };
-
- mExportHelper.deleteKey(mDataUri, Id.type.public_key, returnHandler);
+ deleteKey(mDataUri);
return true;
}
}
return super.onOptionsItemSelected(item);
}
- private void loadData(Intent intent) {
- if (intent.getData().equals(mDataUri)) {
- Log.d(Constants.TAG, "Same URI, no need to load the data again!");
- return;
- }
-
- mDataUri = intent.getData();
- if (mDataUri == null) {
- Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!");
- finish();
- return;
- }
-
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
-
- mActionEncrypt.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- long keyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, mDataUri);
-
- long[] encryptionKeyIds = new long[]{keyId};
- Intent intent = new Intent(ViewKeyActivity.this, EncryptActivity.class);
- intent.setAction(EncryptActivity.ACTION_ENCRYPT);
- intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds);
- // used instead of startActivity set actionbar based on callingPackage
- startActivityForResult(intent, 0);
- }
- });
-
- mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0);
-
- mUserIds.setAdapter(mUserIdsAdapter);
- // mUserIds.setEmptyView(findViewById(android.R.id.empty));
- // mUserIds.setClickable(true);
- // mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- // @Override
- // public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) {
- // }
- // });
-
- mKeysAdapter = new ViewKeyKeysAdapter(this, null, 0);
-
- mKeys.setAdapter(mKeysAdapter);
-
- // Prepare the loader. Either re-connect with an existing one,
- // or start a new one.
- getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this);
- getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
- getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
- }
-
- static final String[] KEYRING_PROJECTION = new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID,
- UserIds.USER_ID};
- static final int KEYRING_INDEX_ID = 0;
- static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
- static final int KEYRING_INDEX_USER_ID = 2;
-
- static final String[] USER_IDS_PROJECTION = new String[]{UserIds._ID, UserIds.USER_ID,
- UserIds.RANK,};
- // not the main user id
- static final String USER_IDS_SELECTION = UserIds.RANK + " > 0 ";
- static final String USER_IDS_SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC";
-
- static final String[] KEYS_PROJECTION = new String[]{Keys._ID, Keys.KEY_ID,
- Keys.IS_MASTER_KEY, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN,
- Keys.CAN_ENCRYPT, Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT};
- static final String KEYS_SORT_ORDER = Keys.RANK + " ASC";
- static final int KEYS_INDEX_ID = 0;
- static final int KEYS_INDEX_KEY_ID = 1;
- static final int KEYS_INDEX_IS_MASTER_KEY = 2;
- static final int KEYS_INDEX_ALGORITHM = 3;
- static final int KEYS_INDEX_KEY_SIZE = 4;
- static final int KEYS_INDEX_CAN_CERTIFY = 5;
- static final int KEYS_INDEX_CAN_SIGN = 6;
- static final int KEYS_INDEX_CAN_ENCRYPT = 7;
- static final int KEYS_INDEX_CREATION = 8;
- static final int KEYS_INDEX_EXPIRY = 9;
- static final int KEYS_INDEX_FINGERPRINT = 10;
-
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- switch (id) {
- case LOADER_ID_KEYRING: {
- Uri baseUri = mDataUri;
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(this, baseUri, KEYRING_PROJECTION, null, null, null);
- }
- case LOADER_ID_USER_IDS: {
- Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(this, baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null,
- USER_IDS_SORT_ORDER);
- }
- case LOADER_ID_KEYS: {
- Uri baseUri = Keys.buildKeysUri(mDataUri);
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(this, baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER);
- }
-
- default:
- return null;
- }
- }
-
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- // Swap the new cursor in. (The framework will take care of closing the
- // old cursor once we return.)
- switch (loader.getId()) {
- case LOADER_ID_KEYRING:
- if (data.moveToFirst()) {
- // get name, email, and comment from USER_ID
- String[] mainUserId = PgpKeyHelper.splitUserId(data
- .getString(KEYRING_INDEX_USER_ID));
- if (mainUserId[0] != null) {
- setTitle(mainUserId[0]);
- mName.setText(mainUserId[0]);
- } else {
- setTitle(R.string.user_id_no_name);
- mName.setText(R.string.user_id_no_name);
- }
- mEmail.setText(mainUserId[1]);
- mComment.setText(mainUserId[2]);
- }
-
- break;
- case LOADER_ID_USER_IDS:
- mUserIdsAdapter.swapCursor(data);
- break;
- case LOADER_ID_KEYS:
- // the first key here is our master key
- if (data.moveToFirst()) {
- // get key id from MASTER_KEY_ID
- long keyId = data.getLong(KEYS_INDEX_KEY_ID);
-
- String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId);
- mKeyId.setText(keyIdStr);
-
- // get creation date from CREATION
- if (data.isNull(KEYS_INDEX_CREATION)) {
- mCreation.setText(R.string.none);
- } else {
- Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
-
- mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(
- creationDate));
- }
-
- // get expiry date from EXPIRY
- if (data.isNull(KEYS_INDEX_EXPIRY)) {
- mExpiry.setText(R.string.none);
- } else {
- Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
-
- mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(
- expiryDate));
- }
-
- String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
- data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE));
- mAlgorithm.setText(algorithmStr);
-
- byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT);
- if (fingerprintBlob == null) {
- // FALLBACK for old database entries
- fingerprintBlob = ProviderHelper.getFingerprint(this, mDataUri);
- }
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true);
- fingerprint = fingerprint.replace(" ", "\n");
-
- mFingerprint.setText(fingerprint);
- }
-
- mKeysAdapter.swapCursor(data);
- break;
-
- default:
- break;
- }
- }
-
- /**
- * This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
- * We need to make sure we are no longer using it.
- */
- public void onLoaderReset(Loader<Cursor> loader) {
- switch (loader.getId()) {
- case LOADER_ID_KEYRING:
- // No resources need to be freed for this ID
- break;
- case LOADER_ID_USER_IDS:
- mUserIdsAdapter.swapCursor(null);
- break;
- case LOADER_ID_KEYS:
- mKeysAdapter.swapCursor(null);
- break;
- default:
- break;
- }
- }
-
private void uploadToKeyserver(Uri dataUri) {
Intent uploadIntent = new Intent(this, UploadKeyActivity.class);
uploadIntent.setData(dataUri);
@@ -398,21 +162,15 @@ public class ViewKeyActivity extends ActionBarActivity implements
}
Intent queryIntent = new Intent(this, ImportKeysActivity.class);
- queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER);
+ queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
queryIntent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, updateKeyId);
- // TODO: lookup??
- startActivityForResult(queryIntent, Id.request.look_up_key_id);
- }
-
- private void signKey(Uri dataUri) {
- Intent signIntent = new Intent(this, SignKeyActivity.class);
- signIntent.setData(dataUri);
- startActivity(signIntent);
+ // TODO: lookup with onactivityresult!
+ startActivityForResult(queryIntent, RESULT_CODE_LOOKUP_KEY);
}
private void shareKey(Uri dataUri, boolean fingerprintOnly) {
- String content = null;
+ String content;
if (fingerprintOnly) {
byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, false);
@@ -465,4 +223,29 @@ public class ViewKeyActivity extends ActionBarActivity implements
dialog.show(getSupportFragmentManager(), "shareNfcDialog");
}
+ private void deleteKey(Uri dataUri) {
+ // Message is received after key is deleted
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
+ Bundle returnData = message.getData();
+ if (returnData != null
+ && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) {
+ // we delete only this key, so MESSAGE_NOT_DELETED will solely contain this key
+ Toast.makeText(ViewKeyActivity.this,
+ getString(R.string.error_can_not_delete_contact)
+ + getResources().getQuantityString(R.plurals.error_can_not_delete_info, 1),
+ Toast.LENGTH_LONG).show();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+ }
+ };
+
+ mExportHelper.deleteKey(dataUri, Id.type.public_key, returnHandler);
+ }
+
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
index a2e3e4339..59037d9ff 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
@@ -23,7 +23,6 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import android.annotation.TargetApi;
-import android.database.Cursor;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
@@ -35,12 +34,11 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.support.v4.app.LoaderManager;
import android.widget.Toast;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback,
- OnNdefPushCompleteCallback, LoaderManager.LoaderCallbacks<Cursor> {
+ OnNdefPushCompleteCallback {
// NFC
private NfcAdapter mNfcAdapter;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
new file mode 100644
index 000000000..36d3e6ace
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.beardedhen.androidbootstrap.BootstrapButton;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+public class ViewKeyCertsFragment extends Fragment {
+
+ public static final String ARG_DATA_URI = "uri";
+
+ private BootstrapButton mActionCertify;
+
+ private Uri mDataUri;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false);
+
+ mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify);
+
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
+ if (dataUri == null) {
+ Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
+ getActivity().finish();
+ return;
+ }
+
+ loadData(dataUri);
+ }
+
+ private void loadData(Uri dataUri) {
+ if (dataUri.equals(mDataUri)) {
+ Log.d(Constants.TAG, "Same URI, no need to load the data again!");
+ return;
+ }
+
+ mDataUri = dataUri;
+
+ Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
+
+ mActionCertify.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ certifyKey(mDataUri);
+ }
+ });
+
+ }
+
+ private void certifyKey(Uri dataUri) {
+ Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class);
+ signIntent.setData(dataUri);
+ startActivity(signIntent);
+ }
+
+} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
new file mode 100644
index 000000000..495764eaf
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.beardedhen.androidbootstrap.BootstrapButton;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.Date;
+
+
+public class ViewKeyMainFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor>{
+
+ public static final String ARG_DATA_URI = "uri";
+
+ private TextView mName;
+ private TextView mEmail;
+ private TextView mComment;
+ private TextView mAlgorithm;
+ private TextView mKeyId;
+ private TextView mExpiry;
+ private TextView mCreation;
+ private TextView mFingerprint;
+ private BootstrapButton mActionEncrypt;
+
+ private ListView mUserIds;
+ private ListView mKeys;
+
+ private static final int LOADER_ID_KEYRING = 0;
+ private static final int LOADER_ID_USER_IDS = 1;
+ private static final int LOADER_ID_KEYS = 2;
+
+ private ViewKeyUserIdsAdapter mUserIdsAdapter;
+ private ViewKeyKeysAdapter mKeysAdapter;
+
+ private Uri mDataUri;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
+
+ mName = (TextView) view.findViewById(R.id.name);
+ mEmail = (TextView) view.findViewById(R.id.email);
+ mComment = (TextView) view.findViewById(R.id.comment);
+ mKeyId = (TextView) view.findViewById(R.id.key_id);
+ mAlgorithm = (TextView) view.findViewById(R.id.algorithm);
+ mCreation = (TextView) view.findViewById(R.id.creation);
+ mExpiry = (TextView) view.findViewById(R.id.expiry);
+ mFingerprint = (TextView) view.findViewById(R.id.fingerprint);
+ mUserIds = (ListView) view.findViewById(R.id.user_ids);
+ mKeys = (ListView) view.findViewById(R.id.keys);
+ mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt);
+
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
+ if (dataUri == null) {
+ Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
+ getActivity().finish();
+ return;
+ }
+
+ loadData(dataUri);
+ }
+
+ private void loadData(Uri dataUri) {
+ if (dataUri.equals(mDataUri)) {
+ Log.d(Constants.TAG, "Same URI, no need to load the data again!");
+ return;
+ }
+
+ mDataUri = dataUri;
+
+ Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
+
+ mActionEncrypt.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ encryptToContact(mDataUri);
+ }
+ });
+
+ mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0);
+ mUserIds.setAdapter(mUserIdsAdapter);
+
+ mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0);
+ mKeys.setAdapter(mKeysAdapter);
+
+ // Prepare the loaders. Either re-connect with an existing ones,
+ // or start new ones.
+ getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this);
+ getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
+ getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
+ }
+
+ static final String[] KEYRING_PROJECTION = new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.UserIds.USER_ID};
+ static final int KEYRING_INDEX_ID = 0;
+ static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
+ static final int KEYRING_INDEX_USER_ID = 2;
+
+ static final String[] USER_IDS_PROJECTION = new String[]{KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
+ KeychainContract.UserIds.RANK,};
+ // not the main user id
+ static final String USER_IDS_SELECTION = KeychainContract.UserIds.RANK + " > 0 ";
+ static final String USER_IDS_SORT_ORDER = KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC";
+
+ static final String[] KEYS_PROJECTION = new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
+ KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, KeychainContract.Keys.CAN_SIGN,
+ KeychainContract.Keys.CAN_ENCRYPT, KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT};
+ static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
+ static final int KEYS_INDEX_ID = 0;
+ static final int KEYS_INDEX_KEY_ID = 1;
+ static final int KEYS_INDEX_IS_MASTER_KEY = 2;
+ static final int KEYS_INDEX_ALGORITHM = 3;
+ static final int KEYS_INDEX_KEY_SIZE = 4;
+ static final int KEYS_INDEX_CAN_CERTIFY = 5;
+ static final int KEYS_INDEX_CAN_SIGN = 6;
+ static final int KEYS_INDEX_CAN_ENCRYPT = 7;
+ static final int KEYS_INDEX_CREATION = 8;
+ static final int KEYS_INDEX_EXPIRY = 9;
+ static final int KEYS_INDEX_FINGERPRINT = 10;
+
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ switch (id) {
+ case LOADER_ID_KEYRING: {
+ Uri baseUri = mDataUri;
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getActivity(), baseUri, KEYRING_PROJECTION, null, null, null);
+ }
+ case LOADER_ID_USER_IDS: {
+ Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri);
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null,
+ USER_IDS_SORT_ORDER);
+ }
+ case LOADER_ID_KEYS: {
+ Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri);
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER);
+ }
+
+ default:
+ return null;
+ }
+ }
+
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ // Swap the new cursor in. (The framework will take care of closing the
+ // old cursor once we return.)
+ switch (loader.getId()) {
+ case LOADER_ID_KEYRING:
+ if (data.moveToFirst()) {
+ // get name, email, and comment from USER_ID
+ String[] mainUserId = PgpKeyHelper.splitUserId(data
+ .getString(KEYRING_INDEX_USER_ID));
+ if (mainUserId[0] != null) {
+ getActivity().setTitle(mainUserId[0]);
+ mName.setText(mainUserId[0]);
+ } else {
+ getActivity().setTitle(R.string.user_id_no_name);
+ mName.setText(R.string.user_id_no_name);
+ }
+ mEmail.setText(mainUserId[1]);
+ mComment.setText(mainUserId[2]);
+ }
+
+ break;
+ case LOADER_ID_USER_IDS:
+ mUserIdsAdapter.swapCursor(data);
+ break;
+ case LOADER_ID_KEYS:
+ // the first key here is our master key
+ if (data.moveToFirst()) {
+ // get key id from MASTER_KEY_ID
+ long keyId = data.getLong(KEYS_INDEX_KEY_ID);
+
+ String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId);
+ mKeyId.setText(keyIdStr);
+
+ // get creation date from CREATION
+ if (data.isNull(KEYS_INDEX_CREATION)) {
+ mCreation.setText(R.string.none);
+ } else {
+ Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
+
+ mCreation.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
+ creationDate));
+ }
+
+ // get expiry date from EXPIRY
+ if (data.isNull(KEYS_INDEX_EXPIRY)) {
+ mExpiry.setText(R.string.none);
+ } else {
+ Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
+
+ mExpiry.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
+ expiryDate));
+ }
+
+ String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
+ data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE));
+ mAlgorithm.setText(algorithmStr);
+
+ byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT);
+ if (fingerprintBlob == null) {
+ // FALLBACK for old database entries
+ fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri);
+ }
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true);
+ fingerprint = fingerprint.replace(" ", "\n");
+
+ mFingerprint.setText(fingerprint);
+ }
+
+ mKeysAdapter.swapCursor(data);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /**
+ * This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
+ * We need to make sure we are no longer using it.
+ */
+ public void onLoaderReset(Loader<Cursor> loader) {
+ switch (loader.getId()) {
+ case LOADER_ID_KEYRING:
+ // No resources need to be freed for this ID
+ break;
+ case LOADER_ID_USER_IDS:
+ mUserIdsAdapter.swapCursor(null);
+ break;
+ case LOADER_ID_KEYS:
+ mKeysAdapter.swapCursor(null);
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ private void encryptToContact(Uri dataUri) {
+ long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
+
+ long[] encryptionKeyIds = new long[]{keyId};
+ Intent intent = new Intent(getActivity(), EncryptActivity.class);
+ intent.setAction(EncryptActivity.ACTION_ENCRYPT);
+ intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds);
+ // used instead of startActivity set actionbar based on callingPackage
+ startActivityForResult(intent, 0);
+ }
+
+ private void certifyKey(Uri dataUri) {
+ Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class);
+ signIntent.setData(dataUri);
+ startActivity(signIntent);
+ }
+
+
+} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
index a850fc020..52186b662 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
@@ -90,16 +90,11 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
View view = mInflater.inflate(R.layout.import_keys_list_entry, null);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- mainUserId.setText(R.string.user_id_no_name);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
- keyId.setText(R.string.no_key);
TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint);
TextView algorithm = (TextView) view.findViewById(R.id.algorithm);
- algorithm.setText("");
TextView status = (TextView) view.findViewById(R.id.status);
- status.setText("");
// main user id
String userId = entry.userIds.get(0);
@@ -113,6 +108,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
mainUserId.setTextColor(Color.RED);
}
mainUserId.setText(userIdSplit[0]);
+ } else {
+ mainUserId.setText(R.string.user_id_no_name);
}
// email
@@ -124,12 +121,18 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
}
keyId.setText(entry.hexKeyId);
- fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint);
+
+ if (entry.fingerPrint != null) {
+ fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint);
+ fingerprint.setVisibility(View.VISIBLE);
+ } else {
+ fingerprint.setVisibility(View.GONE);
+ }
algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
if (entry.revoked) {
- status.setText("revoked");
+ status.setText(R.string.revoked);
} else {
status.setVisibility(View.GONE);
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
index 5094e8abd..4a7a9c93a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
@@ -48,7 +48,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
private boolean selected;
- private byte[] bytes = new byte[] {};
+ private byte[] bytes = new byte[]{};
public ImportKeysListEntry(ImportKeysListEntry b) {
this.userIds = b.userIds;
@@ -167,7 +167,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.revoked = pgpKeyRing.getPublicKey().isRevoked();
this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey()
.getFingerprint(), true);
- this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId);
+ this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId);
this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength();
int algorithm = pgpKeyRing.getPublicKey().getAlgorithm();
if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
index 753994450..b3bc39127 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
@@ -79,7 +79,7 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
}
/**
- * Query key server
+ * Query keyserver
*/
private void queryServer(String query, String keyServer) {
HkpKeyServer server = new HkpKeyServer(keyServer);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
index f0e926655..257136cbd 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
@@ -23,10 +23,11 @@ import java.util.Set;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.util.Log;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
+
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
@@ -35,6 +36,7 @@ import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.RelativeLayout;
import android.widget.TextView;
/**
@@ -44,6 +46,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea
private LayoutInflater mInflater;
private int mSectionColumnIndex;
private int mIndexUserId;
+ private int mIndexIsRevoked;
@SuppressLint("UseSparseArrays")
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
@@ -66,48 +69,59 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea
/**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582
- *
+ *
* @param cursor
*/
private void initIndex(Cursor cursor) {
if (cursor != null) {
- mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
+ mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.UserIds.USER_ID);
+ mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeychainContract.Keys.IS_REVOKED);
}
}
/**
* Bind cursor data to the item list view
- *
+ * <p/>
* NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus
* no ViewHolder is required here.
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- mainUserId.setText(R.string.user_id_no_name);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- mainUserIdRest.setText("");
+ TextView revoked = (TextView) view.findViewById(R.id.revoked);
String userId = cursor.getString(mIndexUserId);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
-
if (userIdSplit[0] != null) {
mainUserId.setText(userIdSplit[0]);
+ } else {
+ mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mainUserIdRest.setText(userIdSplit[1]);
+ mainUserIdRest.setVisibility(View.VISIBLE);
+ } else {
+ mainUserIdRest.setVisibility(View.GONE);
+ }
+
+ boolean isRevoked = cursor.getInt(mIndexIsRevoked) > 0;
+ if (isRevoked) {
+ revoked.setVisibility(View.VISIBLE);
+ } else {
+ revoked.setVisibility(View.GONE);
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.key_list_item, null);
+ return mInflater.inflate(R.layout.key_list_public_item, null);
}
/**
* Creates a new header view and binds the section headers to it. It uses the ViewHolder
* pattern. Most functionality is similar to getView() from Android's CursorAdapter.
- *
+ * <p/>
* NOTE: The variables mDataValid and mCursor are available due to the super class
* CursorAdapter.
*/
@@ -159,8 +173,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea
}
// return the first character of the name as ID because this is what
- // headers private HashMap<Integer, Boolean> mSelection = new HashMap<Integer,
- // Boolean>();are based upon
+ // headers are based upon
String userId = mCursor.getString(mSectionColumnIndex);
if (userId != null && userId.length() > 0) {
return userId.subSequence(0, 1).charAt(0);
@@ -173,7 +186,9 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea
TextView text;
}
- /** -------------------------- MULTI-SELECTION METHODS -------------- */
+ /**
+ * -------------------------- MULTI-SELECTION METHODS --------------
+ */
public void setNewSelection(int position, boolean value) {
mSelection.put(position, value);
notifyDataSetChanged();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java
index ce9b48bff..11d1e8c17 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java
@@ -71,24 +71,26 @@ public class KeyListSecretAdapter extends CursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- mainUserId.setText(R.string.user_id_no_name);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- mainUserIdRest.setText("");
String userId = cursor.getString(mIndexUserId);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
mainUserId.setText(userIdSplit[0]);
+ } else {
+ mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mainUserIdRest.setText(userIdSplit[1]);
+ } else {
+ mainUserIdRest.setText("");
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.key_list_item, null);
+ return mInflater.inflate(R.layout.key_list_secret_item, null);
}
/** -------------------------- MULTI-SELECTION METHODS -------------- */
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
index 7e01faf9b..d44dd5890 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
@@ -96,27 +96,31 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
boolean valid = cursor.getInt(mIndexProjectionValid) > 0;
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- mainUserId.setText(R.string.user_id_no_name);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
- keyId.setText(R.string.no_key);
TextView status = (TextView) view.findViewById(R.id.status);
- status.setText(R.string.unknown_status);
String userId = cursor.getString(mIndexUserId);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
mainUserId.setText(userIdSplit[0]);
+ } else {
+ mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mainUserIdRest.setText(userIdSplit[1]);
+ } else {
+ mainUserIdRest.setText("");
}
+ // TODO: needed to key id to no?
+ keyId.setText(R.string.no_key);
long masterKeyId = cursor.getLong(mIndexMasterKeyId);
keyId.setText(PgpKeyHelper.convertKeyIdToHex(masterKeyId));
+ // TODO: needed to set unknown_status?
+ status.setText(R.string.unknown_status);
if (valid) {
if (mKeyType == Id.type.public_key) {
status.setText(R.string.can_encrypt);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
new file mode 100644
index 000000000..924a70897
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
@@ -0,0 +1,84 @@
+package org.sufficientlysecure.keychain.ui.adapter;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+
+import java.util.ArrayList;
+
+public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener,
+ ViewPager.OnPageChangeListener {
+ private final Context mContext;
+ private final ActionBar mActionBar;
+ private final ViewPager mViewPager;
+ private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+
+ static final class TabInfo {
+ private final Class<?> clss;
+ private final Bundle args;
+
+ TabInfo(Class<?> _class, Bundle _args) {
+ clss = _class;
+ args = _args;
+ }
+ }
+
+ public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
+ super(activity.getSupportFragmentManager());
+ mContext = activity;
+ mActionBar = activity.getSupportActionBar();
+ mViewPager = pager;
+ mViewPager.setAdapter(this);
+ mViewPager.setOnPageChangeListener(this);
+ }
+
+ public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, boolean selected) {
+ TabInfo info = new TabInfo(clss, args);
+ tab.setTag(info);
+ tab.setTabListener(this);
+ mTabs.add(info);
+ mActionBar.addTab(tab, selected);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ TabInfo info = mTabs.get(position);
+ return Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ }
+
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ public void onPageSelected(int position) {
+ mActionBar.setSelectedNavigationItem(position);
+ }
+
+ public void onPageScrollStateChanged(int state) {
+ }
+
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+ Object tag = tab.getTag();
+ for (int i = 0; i < mTabs.size(); i++) {
+ if (mTabs.get(i) == tag) {
+ mViewPager.setCurrentItem(i);
+ }
+ }
+ }
+
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ }
+
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ }
+} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
index d5162c403..54c7eb60e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
@@ -76,38 +76,39 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
+ TextView keyId = (TextView) view.findViewById(R.id.keyId);
+ TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
+ ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey);
+ ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey);
+ ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
+ ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
+
String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId));
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm),
cursor.getInt(mIndexKeySize));
- TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(keyIdStr);
- TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
keyDetails.setText("(" + algorithmStr + ")");
- ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey);
if (cursor.getInt(mIndexIsMasterKey) != 1) {
masterKeyIcon.setVisibility(View.INVISIBLE);
} else {
masterKeyIcon.setVisibility(View.VISIBLE);
}
- ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey);
if (cursor.getInt(mIndexCanCertify) != 1) {
certifyIcon.setVisibility(View.GONE);
} else {
certifyIcon.setVisibility(View.VISIBLE);
}
- ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
if (cursor.getInt(mIndexCanEncrypt) != 1) {
encryptIcon.setVisibility(View.GONE);
} else {
encryptIcon.setVisibility(View.VISIBLE);
}
- ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
if (cursor.getInt(mIndexCanSign) != 1) {
signIcon.setVisibility(View.GONE);
} else {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index 109bfe929..3c44bff81 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -23,12 +23,16 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
@@ -36,6 +40,8 @@ import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import java.util.ArrayList;
+
public class DeleteKeyDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_file";
@@ -43,13 +49,15 @@ public class DeleteKeyDialogFragment extends DialogFragment {
public static final int MESSAGE_OKAY = 1;
+ public static final String MESSAGE_NOT_DELETED = "not_deleted";
+
private Messenger mMessenger;
/**
* Creates new instance of this delete file dialog fragment
*/
public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds,
- int keyType) {
+ int keyType) {
DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
Bundle args = new Bundle();
@@ -77,20 +85,13 @@ public class DeleteKeyDialogFragment extends DialogFragment {
builder.setTitle(R.string.warning);
if (keyRingRowIds.length == 1) {
- // TODO: better way to do this?
- String userId = activity.getString(R.string.user_id_no_name);
-
+ Uri dataUri;
if (keyType == Id.type.public_key) {
- PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByRowId(activity,
- keyRingRowIds[0]);
- userId = PgpKeyHelper.getMainUserIdSafe(activity,
- PgpKeyHelper.getMasterKey(keyRing));
+ dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowIds[0]));
} else {
- PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByRowId(activity,
- keyRingRowIds[0]);
- userId = PgpKeyHelper.getMainUserIdSafe(activity,
- PgpKeyHelper.getMasterKey(keyRing));
+ dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowIds[0]));
}
+ String userId = ProviderHelper.getUserId(activity, dataUri);
builder.setMessage(getString(
keyType == Id.type.public_key ? R.string.key_deletion_confirmation
@@ -104,9 +105,61 @@ public class DeleteKeyDialogFragment extends DialogFragment {
@Override
public void onClick(DialogInterface dialog, int id) {
+ ArrayList<String> notDeleted = new ArrayList<String>();
+
if (keyType == Id.type.public_key) {
- for (long keyRowId : keyRingRowIds) {
- ProviderHelper.deletePublicKeyRing(activity, keyRowId);
+ Uri queryUri = KeychainContract.KeyRings.buildPublicKeyRingsUri();
+ String[] projection = new String[]{
+ KeychainContract.KeyRings._ID, // 0
+ KeychainContract.KeyRings.MASTER_KEY_ID, // 1
+ KeychainContract.UserIds.USER_ID // 2
+ };
+
+ // make selection with all entries where _ID is one of the given row ids
+ String selection = KeychainDatabase.Tables.KEY_RINGS + "." +
+ KeychainContract.KeyRings._ID + " IN(";
+ String selectionIDs = "";
+ for (int i = 0; i < keyRingRowIds.length; i++) {
+ selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
+ if (i+1 < keyRingRowIds.length)
+ selectionIDs += ",";
+ }
+ selection += selectionIDs + ")";
+
+ Cursor cursor = activity.getContentResolver().query(queryUri, projection,
+ selection, null, null);
+
+ long rowId;
+ long masterKeyId;
+ String userId;
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ rowId = cursor.getLong(0);
+ masterKeyId = cursor.getLong(1);
+ userId = cursor.getString(2);
+
+ Log.d(Constants.TAG, "rowId: " + rowId + ", masterKeyId: " + masterKeyId
+ + ", userId: " + userId);
+
+ // check if a corresponding secret key exists...
+ Cursor secretCursor = activity.getContentResolver().query(
+ KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId)),
+ null, null, null, null
+ );
+ if (secretCursor != null && secretCursor.getCount() > 0) {
+ notDeleted.add(userId);
+ } else {
+ // it is okay to delete this key, no secret key found!
+ ProviderHelper.deletePublicKeyRing(activity, rowId);
+ }
+ if (secretCursor != null) {
+ secretCursor.close();
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
for (long keyRowId : keyRingRowIds) {
@@ -116,7 +169,13 @@ public class DeleteKeyDialogFragment extends DialogFragment {
dismiss();
- sendMessageToHandler(MESSAGE_OKAY);
+ if (notDeleted.size() > 0) {
+ Bundle data = new Bundle();
+ data.putStringArrayList(MESSAGE_NOT_DELETED, notDeleted);
+ sendMessageToHandler(MESSAGE_OKAY, data);
+ } else {
+ sendMessageToHandler(MESSAGE_OKAY, null);
+ }
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -131,13 +190,15 @@ public class DeleteKeyDialogFragment extends DialogFragment {
/**
* Send message back to handler which is initialized in a activity
- *
- * @param what
- * Message integer you want to send
+ *
+ * @param what Message integer you want to send
*/
- private void sendMessageToHandler(Integer what) {
+ private void sendMessageToHandler(Integer what, Bundle data) {
Message msg = Message.obtain();
msg.what = what;
+ if (data != null) {
+ msg.setData(data);
+ }
try {
mMessenger.send(msg);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java
deleted file mode 100644
index a0592285f..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui.dialog;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.ui.ImportKeysActivity;
-import org.sufficientlysecure.keychain.util.Log;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v4.app.DialogFragment;
-
-public class LookupUnknownKeyDialogFragment extends DialogFragment {
- private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_UNKNOWN_KEY_ID = "unknown_key_id";
-
- public static final int MESSAGE_OKAY = 1;
- public static final int MESSAGE_CANCEL = 2;
-
- private Messenger mMessenger;
-
- /**
- * Creates new instance of this dialog fragment
- *
- * @param messenger
- * @param unknownKeyId
- * @return
- */
- public static LookupUnknownKeyDialogFragment newInstance(Messenger messenger, long unknownKeyId) {
- LookupUnknownKeyDialogFragment frag = new LookupUnknownKeyDialogFragment();
- Bundle args = new Bundle();
- args.putLong(ARG_UNKNOWN_KEY_ID, unknownKeyId);
- args.putParcelable(ARG_MESSENGER, messenger);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates dialog
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
-
- final long unknownKeyId = getArguments().getLong(ARG_UNKNOWN_KEY_ID);
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
-
- AlertDialog.Builder alert = new AlertDialog.Builder(activity);
-
- alert.setIcon(android.R.drawable.ic_dialog_alert);
- alert.setTitle(R.string.title_unknown_signature_key);
- alert.setMessage(getString(R.string.lookup_unknown_key,
- PgpKeyHelper.convertKeyIdToHex(unknownKeyId)));
-
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
-
- sendMessageToHandler(MESSAGE_OKAY);
-
- Intent intent = new Intent(activity, ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER);
- intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId);
- startActivityForResult(intent, Id.request.look_up_key_id);
- }
- });
- alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
-
- sendMessageToHandler(MESSAGE_CANCEL);
- }
- });
- alert.setCancelable(true);
- alert.setOnCancelListener(new OnCancelListener() {
-
- @Override
- public void onCancel(DialogInterface dialog) {
- sendMessageToHandler(MESSAGE_CANCEL);
- }
- });
-
- return alert.create();
- }
-
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what
- * Message integer you want to send
- */
- private void sendMessageToHandler(Integer what) {
- Message msg = Message.obtain();
- msg.what = what;
-
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
- } catch (NullPointerException e) {
- Log.w(Constants.TAG, "Messenger is null!", e);
- }
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
index 05e52fb47..61fe13ffb 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
@@ -50,6 +50,13 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import android.text.Html;
+/**
+ * TODO:
+ * rewrite to use machine readable output.
+ * <p/>
+ * see http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5
+ * https://github.com/openpgp-keychain/openpgp-keychain/issues/259
+ */
public class HkpKeyServer extends KeyServer {
private static class HttpError extends Exception {
private static final long serialVersionUID = 1718783705229428893L;
@@ -181,8 +188,8 @@ public class HkpKeyServer extends KeyServer {
ImportKeysListEntry info = new ImportKeysListEntry();
info.bitStrength = Integer.parseInt(matcher.group(1));
info.algorithm = matcher.group(2);
+ info.hexKeyId = "0x" + matcher.group(3);
info.keyId = PgpKeyHelper.convertHexToKeyId(matcher.group(3));
- info.fingerPrint = PgpKeyHelper.convertKeyIdToHex(info.keyId);
String chunks[] = matcher.group(4).split("-");
GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml
index 79daef590..c60416494 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml
@@ -1,25 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical" >
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <TextView
- android:id="@+id/api_register_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingBottom="3dip"
- android:text="@string/api_register_text"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <fragment
- android:id="@+id/api_app_settings_fragment"
- android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- tools:layout="@layout/api_app_settings_fragment" />
+ android:layout_height="match_parent"
+ android:padding="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/api_register_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="3dip"
+ android:text="@string/api_register_text"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <fragment
+ android:id="@+id/api_app_settings_fragment"
+ android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:layout="@layout/api_app_settings_fragment" />
-</LinearLayout> \ No newline at end of file
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
index e60ad50e3..d4fb5103a 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
@@ -1,17 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical" >
+ android:layout_height="match_parent">
- <fragment
- android:id="@+id/api_app_settings_fragment"
- android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- tools:layout="@layout/api_app_settings_fragment" />
+ android:layout_height="match_parent"
+ android:padding="16dp"
+ android:orientation="vertical">
-</LinearLayout> \ No newline at end of file
+ <fragment
+ android:id="@+id/api_app_settings_fragment"
+ android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:layout="@layout/api_app_settings_fragment" />
+
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
index 0695e5922..a8b68859b 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
@@ -1,129 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/api_app_settings_app_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginRight="6dp"
+ android:src="@drawable/icon" />
+
+ <TextView
+ android:id="@+id/api_app_settings_app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/api_app_settings_app_icon"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:text="Name (set in-code)"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </RelativeLayout>
+
+ <fragment
+ android:id="@+id/api_app_settings_select_key_fragment"
+ android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:layout="@layout/select_secret_key_layout_fragment" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/api_app_settings_advanced_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:text="@string/api_settings_show_advanced"
+ bootstrapbutton:bb_icon_left="fa-caret-up"
+ bootstrapbutton:bb_size="default"
+ bootstrapbutton:bb_type="default" />
<LinearLayout
+ android:id="@+id/api_app_settings_advanced"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/label_encryption_algorithm"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Spinner
+ android:id="@+id/api_app_settings_encryption_algorithm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
- <RelativeLayout
+ <TextView
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:gravity="center_horizontal"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/api_app_settings_app_icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentTop="true"
- android:layout_marginRight="6dp"
- android:src="@drawable/icon" />
-
- <TextView
- android:id="@+id/api_app_settings_app_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/api_app_settings_app_icon"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:text="Name (set in-code)"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- </RelativeLayout>
-
- <fragment
- android:id="@+id/api_app_settings_select_key_fragment"
- android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ android:layout_height="wrap_content"
+ android:text="@string/label_hash_algorithm"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Spinner
+ android:id="@+id/api_app_settings_hash_algorithm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:layout="@layout/select_secret_key_layout_fragment" />
+ android:text="@string/label_message_compression"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/api_app_settings_advanced_button"
+ <Spinner
+ android:id="@+id/api_app_settings_compression"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:text="@string/api_settings_show_advanced"
- bootstrapbutton:bb_icon_left="fa-caret-up"
- bootstrapbutton:bb_size="default"
- bootstrapbutton:bb_type="default" />
-
- <LinearLayout
- android:id="@+id/api_app_settings_advanced"
+ android:text="@string/api_settings_package_name"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/api_app_settings_package_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_encryption_algorithm"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_encryption_algorithm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_hash_algorithm"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_hash_algorithm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_message_compression"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_compression"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/api_settings_package_name"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/api_app_settings_package_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="com.example"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/api_settings_package_signature"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/api_app_settings_package_signature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Base64 encoded signature"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
- </LinearLayout>
+ android:text="com.example"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/api_settings_package_signature"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
-</ScrollView> \ No newline at end of file
+ <TextView
+ android:id="@+id/api_app_settings_package_signature"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Base64 encoded signature"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_apps_adapter_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/api_apps_adapter_list_item.xml
index cb20a20af..e70a79589 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_apps_adapter_list_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_apps_adapter_list_item.xml
@@ -1,28 +1,26 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:gravity="left"
- android:orientation="horizontal" >
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
<ImageView
android:id="@+id/api_apps_adapter_item_icon"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
+ android:layout_centerVertical="true"
android:src="@drawable/icon" />
<TextView
android:id="@+id/api_apps_adapter_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:text="Application Name"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/api_apps_adapter_item_icon"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:text="Set in-code!"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:layout_toRightOf="@+id/api_apps_adapter_item_icon" />
</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/sign_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml
index 07f63b91b..ddb424ee8 100644
--- a/OpenPGP-Keychain/src/main/res/layout/sign_key_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml
@@ -18,7 +18,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
- android:text="@string/section_signing_key" />
+ android:text="@string/section_certification_key" />
<fragment
android:id="@+id/sign_key_select_key_fragment"
@@ -60,7 +60,7 @@
android:layout_height="60dp"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
- android:text="@string/btn_sign"
+ android:text="@string/btn_certify"
bootstrapbutton:bb_icon_left="fa-pencil"
bootstrapbutton:bb_type="info" />
</LinearLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
index c6834d745..e6c81c3fc 100644
--- a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
@@ -20,10 +20,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:paddingTop="4dp"
android:paddingLeft="10dp"
android:paddingRight="10dp">
- <LinearLayout
+ <RelativeLayout
android:id="@+id/signature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -35,7 +36,8 @@
<RelativeLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:id="@+id/relativeLayout">
<ImageView
android:id="@+id/ic_signature"
@@ -50,29 +52,40 @@
android:src="@drawable/overlay_error" />
</RelativeLayout>
- <LinearLayout
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/lookup_key"
+ android:visibility="gone"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="5dip">
+ android:layout_height="50dp"
+ android:padding="4dp"
+ android:text="@string/btn_lookup_key"
+ bootstrapbutton:bb_icon_left="fa-download"
+ bootstrapbutton:bb_type="info"
+ bootstrapbutton:bb_size="small"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true" />
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:text="Main User Id"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:text="Main User Id"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_alignTop="@+id/linearLayout"
+ android:layout_toRightOf="@+id/relativeLayout" />
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:text="Main User Id Rest"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
- </LinearLayout>
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:text="Main User Id Rest"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_below="@+id/mainUserId"
+ android:layout_toRightOf="@+id/relativeLayout" />
+ </RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
diff --git a/OpenPGP-Keychain/src/main/res/layout/drawer_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/drawer_list_item.xml
index 14760e79d..72f4fec50 100644
--- a/OpenPGP-Keychain/src/main/res/layout/drawer_list_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/drawer_list_item.xml
@@ -1,28 +1,33 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
+ android:layout_height="wrap_content">
<com.beardedhen.androidbootstrap.FontAwesomeText
android:id="@+id/drawer_item_icon"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="10dp"
+ android:layout_width="30dp"
+ android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textSize="24sp"
- fontawesometext:fa_icon="fa-github" />
+ android:layout_marginLeft="8dp"
+ fontawesometext:fa_icon="fa-github"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
<TextView
android:id="@+id/drawer_item_text"
+ android:text="Test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
+ android:layout_marginLeft="8dp"
android:paddingBottom="16dp"
- android:paddingLeft="4dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:textAppearance="@android:style/TextAppearance.Medium"
- android:textColor="#111" />
+ android:textColor="#111"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@+id/drawer_item_icon" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml
deleted file mode 100644
index 2571bb6e7..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginRight="?android:attr/scrollbarSize"
- android:orientation="vertical"
- android:paddingLeft="8dp"
- android:singleLine="true" >
-
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Main User ID"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&lt;user@example.com>"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml
new file mode 100644
index 000000000..9307ab2e5
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:layout_marginRight="?android:attr/scrollbarSize"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:singleLine="true">
+
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Main User ID"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="&lt;user@example.com>"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_below="@+id/mainUserId"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+ <TextView
+ android:id="@+id/revoked"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/revoked"
+ android:textColor="#e00"
+ android:visibility="gone"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml
index 13370f2e5..cd208a545 100644
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml
@@ -2,17 +2,21 @@
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent">
<fragment
android:id="@+id/key_list_secret_fragment"
android:name="org.sufficientlysecure.keychain.ui.KeyListSecretFragment"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:paddingBottom="16dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:scrollbarStyle="outsideOverlay" />
</FrameLayout>
<include layout="@layout/drawer_list" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml
new file mode 100644
index 000000000..1ed86f730
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:singleLine="true">
+
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Main User ID"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="&lt;user@example.com>"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_below="@+id/mainUserId"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml
index 73a86a725..58e4919dc 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml
@@ -1,220 +1,12 @@
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
- <LinearLayout
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp">
+ android:layout_height="match_parent" />
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_master_user_id" />
-
- <TableLayout
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:stretchColumns="1">
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingRight="10dip"
- android:text="@string/label_name" />
-
- <TextView
- android:id="@+id/name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text="" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingRight="10dip"
- android:text="@string/label_email" />
-
- <TextView
- android:id="@+id/email"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text="" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingRight="10dip"
- android:text="@string/label_comment" />
-
- <TextView
- android:id="@+id/comment"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text="" />
- </TableRow>
- </TableLayout>
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_master_key" />
-
- <TableLayout
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:stretchColumns="1">
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_key_id" />
-
- <TextView
- android:id="@+id/key_id"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text=""
- android:typeface="monospace" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:id="@+id/label_algorithm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_algorithm" />
-
- <TextView
- android:id="@+id/algorithm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text="" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_creation" />
-
- <TextView
- android:id="@+id/creation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_expiry" />
-
- <TextView
- android:id="@+id/expiry"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_fingerprint" />
-
- <TextView
- android:id="@+id/fingerprint"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:typeface="monospace" />
- </TableRow>
- </TableLayout>
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_user_ids" />
-
- <org.sufficientlysecure.keychain.ui.widget.FixedListView
- android:id="@+id/user_ids"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_keys" />
-
- <org.sufficientlysecure.keychain.ui.widget.FixedListView
- android:id="@+id/keys"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_actions" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/action_encrypt"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:text="@string/key_view_action_encrypt"
- bootstrapbutton:bb_icon_left="fa-lock"
- bootstrapbutton:bb_type="info" />
- </LinearLayout>
-
-</ScrollView> \ No newline at end of file
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml
new file mode 100644
index 000000000..299471c66
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml
@@ -0,0 +1,38 @@
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="Display of existing certifications is a planned feature for a later release of OpenPGP Keychain. Stay tuned for updates!" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_actions" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_certify"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:text="@string/key_view_action_certify"
+ bootstrapbutton:bb_icon_left="fa-pencil"
+ bootstrapbutton:bb_type="info" />
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
index b50253980..c44835bb0 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginRight="?android:attr/scrollbarSize"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="8dip"
android:paddingRight="3dip"
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
new file mode 100644
index 000000000..055687183
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
@@ -0,0 +1,226 @@
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- focusable and related properties to workaround http://stackoverflow.com/q/16182331-->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:descendantFocusability="beforeDescendants"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp">
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_master_user_id" />
+
+ <TableLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:stretchColumns="1">
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingRight="10dip"
+ android:text="@string/label_name" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text="" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingRight="10dip"
+ android:text="@string/label_email" />
+
+ <TextView
+ android:id="@+id/email"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text="" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingRight="10dip"
+ android:text="@string/label_comment" />
+
+ <TextView
+ android:id="@+id/comment"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text="" />
+ </TableRow>
+ </TableLayout>
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_master_key" />
+
+ <TableLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:stretchColumns="1">
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_key_id" />
+
+ <TextView
+ android:id="@+id/key_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text=""
+ android:typeface="monospace" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:id="@+id/label_algorithm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_algorithm" />
+
+ <TextView
+ android:id="@+id/algorithm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text="" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_creation" />
+
+ <TextView
+ android:id="@+id/creation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_expiry" />
+
+ <TextView
+ android:id="@+id/expiry"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_fingerprint" />
+
+ <TextView
+ android:id="@+id/fingerprint"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:typeface="monospace" />
+ </TableRow>
+ </TableLayout>
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_user_ids" />
+
+ <org.sufficientlysecure.keychain.ui.widget.FixedListView
+ android:id="@+id/user_ids"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_keys" />
+
+ <org.sufficientlysecure.keychain.ui.widget.FixedListView
+ android:id="@+id/keys"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_actions" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_encrypt"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:layout_marginBottom="10dp"
+ android:text="@string/key_view_action_encrypt"
+ bootstrapbutton:bb_icon_left="fa-lock"
+ bootstrapbutton:bb_type="info" />
+
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
index 2d022ba13..508d080a6 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
@@ -1,16 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginRight="?android:attr/scrollbarSize"
+ android:layout_height="wrap_content"
android:orientation="vertical"
- android:singleLine="true" >
+ android:paddingRight="3dip"
+ android:singleLine="true">
<TextView
android:id="@+id/userId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingRight="3dip"
android:text="User ID"
android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_view.xml b/OpenPGP-Keychain/src/main/res/menu/key_view.xml
index acf3eb099..59247221a 100644
--- a/OpenPGP-Keychain/src/main/res/menu/key_view.xml
+++ b/OpenPGP-Keychain/src/main/res/menu/key_view.xml
@@ -65,10 +65,6 @@
</menu>
</item>
<item
- android:id="@+id/menu_key_view_sign"
- app:showAsAction="ifRoom"
- android:title="@string/menu_sign_key" />
- <item
android:id="@+id/menu_key_view_export_file"
app:showAsAction="never"
android:title="@string/menu_export_key" />
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
index 0ebedb1a1..89f74e9b0 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
@@ -23,7 +23,9 @@
<h2>Bibliotheken</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache Lizenz v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
index f6f6844a2..56dcf0c8b 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>Einfacher Schlüsselserversupport</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>mehr Auswahlmöglichkeiten für den Passwortcache: 1, 2, 4, 8, Stunden</li>
<li>Übersetzungen: norwegisch (Danke, Sander Danielsen), chinesisch (danke, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-de/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_start.html b/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-de/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_about.html b/OpenPGP-Keychain/src/main/res/raw-es/help_about.html
new file mode 100644
index 000000000..a81789cec
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_about.html
@@ -0,0 +1,43 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
+<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> es una implementación de OpenPGP para Android. Su desarrollo comenzó como un fork de Android Privacy Guard (APG).</p>
+<p>Licencia: GPLv3+</p>
+
+<h2>Desarrolladores de OpenPGP Keychain</h2>
+<ul>
+<li>Dominik Schürmann (Desarrollador principal)</li>
+<li>Ash Hughes (Parches cryptográficos)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+
+</ul>
+<h2>Desarrolladores de APG 1.x</h2>
+<ul>
+<li>'Thialfihar' (Desarrollador principal)</li>
+<li>'Senecaso' (Código QR, clave de firma, carga de clave)</li>
+<li>Oliver Runge</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Librerías</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licencia Apache v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licencia Apache v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licencia Apache v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (Licencia MIT)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Licencia Apache v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
+<li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li>
+<li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html
new file mode 100644
index 000000000..dfb51dc81
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html
@@ -0,0 +1,108 @@
+<html>
+<head></head>
+<body>
+<h2>2.3</h2>
+<ul>
+<li>elimina la exportación innecesaria de claves públicas cuando se exporta la clave secreta (gracias a Ash Hughes)</li>
+<li>corrige la configuración de la fecha de caducidad en las claves (gracias a Ash Hughes)</li>
+<li>más correcciones internas cuando se editan claves (gracias a Ash Hughes)</li>
+<li>consultar los servidores de claves directamente desde la ventana de importación</li>
+<li>corrige el diseño y estilo de mensajes en Android 2.2-3.0</li>
+<li>corrige error en claves con IDs de usuario vacías</li>
+<li>corrige fallo y listados vacíos cuando se regresa desde la pantalla de firma</li>
+<li>Bouncy Castle (librería criptográfica) actualizada de 1.47 a 1.50 y compilada desde la fuente</li>
+<li>corrige la carga de la clave desde la pantalla de firma</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>nuevo diseño con Navigation Drawer</li>
+<li>nuevo diseño de la lista de clave pública</li>
+<li>nueva vista de la clave pública</li>
+<li>correcciones en la importación de claves</li>
+<li>clave de certificación cruzada (gracias a Ash Hughes)</li>
+<li>manejo correcto de las contraseñas UTF-8 (gracias a Ash Hughes)</li>
+<li>primera versión con nuevos idiomas (gracias a los colaboradores en Transifex)</li>
+<li>compartir claves a través de códigos QR corregido y mejorado</li>
+<li>verificación por API del paquete de firma</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>Actualizaciones de la API, preparación para la integración con K-9 Mail</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>corrección de muchos bugs</li>
+<li>nueva API para desarrolladores</li>
+<li>corrección del bug PRNG por Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>completo rediseño</li>
+<li>compartir claves públicas a través de códigos QR, NFC, Beam</li>
+<li>claves de firma</li>
+<li>cargar claves al servidor</li>
+<li>corrige problemas importantes</li>
+<li>nueva API AIDL</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>compatibilidad básica de los servidores de claves</li>
+<li>app-a-sd</li>
+<li>más opciones para la caché de la frase de contraseña: 1, 2, 4, 8 horas</li>
+<li>traducciones: noruego (gracias, Sander Danielsen), chino (gracias, Zhang Fredrick)</li>
+<li>correcciones de errores</li>
+<li>optimizaciones</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>corregido el problema con la verificación de firma de textos que arrastran a una nueva línea</li>
+<li>más opciones para el tiempo de la caché de la frase de contraseña hasta ahora (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>corregido el problema al añadir cuentas en Froyo</li>
+<li>borrado seguro de archivo</li>
+<li>opción para borrar el archivo de clave después de importarlo</li>
+<li>flujo de cifrado/descifrado (galería, etc.)</li>
+<li>nuevas opciones (idioma, forzar firmas v3)</li>
+<li>cambios en la interfaz</li>
+<li>correcciones de errores</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>traducciones a alemán e italiano</li>
+<li>paquete de mucho menos tamaño, debido a fuentes BC reducidas</li>
+<li>nuevas preferencias en la GUI</li>
+<li>ajuste del diseño para localización</li>
+<li>corrección de error en la firma</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>corregido otro error causado por algún bug en el SDK con el constructor de consultas</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>corregidos los errores durante el cifrado/firma y probablemente en la exportación de la clave</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>listas de claves con filtro</li>
+<li>preselección de claves de cifrado más inteligente</li>
+<li>nuevo intento en el manejo para VER y ENVIAR, permite que los archivos sean cifrados/descifrados fuera de los gestores de archivos</li>
+<li>corrige y añade características (preselección de clave) para K-9 Mail, nueva compilación disponible</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>La enumeración de cuentas de GMail no funcionaba en 1.0.0, corregida de nuevo</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>integración con K-9 Mail, APG compatible con la compilación beta de K-9 Mail</li>
+<li>compatibilidad para más gestores de archivos (incluyendo ASTRO)</li>
+<li>traducción al esloveno</li>
+<li>nueva base de datos, más rápida, con menos demanda de memoria</li>
+<li>definidos los intentos y el proveedor de contenido para otras aplicaciones</li>
+<li>correcciones de errores</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-es/help_nfc_beam.html
new file mode 100644
index 000000000..4a95680b5
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>Cómo recibir las claves</h2>
+<ol>
+<li>Vete a los contactos de tu compañero y abre el contacto con el que quieres compartir</li>
+<li>Mantén los dos dispositivos de con ambos reversos juntos (tienen que estar casi en contacto) y notarás una vibración.</li>
+<li>Después de que vibre, verás el contenido en el dispositivo de tu compañero convertirse en una especie de ficha con una animación de Star Trek de fondo.</li>
+<li>Toca la ficha y el contenido se cargará en tu dispositivo.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_start.html b/OpenPGP-Keychain/src/main/res/raw-es/help_start.html
new file mode 100644
index 000000000..d0eee8adb
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Primeros pasos</h2>
+<p>Primero necesitas un par de claves personales. Crea una a través del menú "Mis claves" o importa un par de claves ya existentes a través de "Importar claves". Después, puedes descargar las claves de tus amigos o intercambiarlas a través de códigos QR o NFC.</p>
+
+<p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p>
+
+<h2>¡He encontrado un bug en OpenPGP Keychain!</h2>
+<p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenPGP Keychain</a>.</p>
+
+<h2>Aportar</h2>
+<p>Si quieres ayudarnos con el desarrollo de OpenPGP Keychain aportando código <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">sigue nuestra pequeña guía en Github</a>.</p>
+
+<h2>Traducciones</h2>
+<p>¡Ayúdanos a traducir OpenPGP Keychain! Todo el mundo es bienvenido en <a href="https://www.transifex.com/projects/p/openpgp-keychain/">Transifex - OpenPGP Keychain</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-es/nfc_beam_share.html
new file mode 100644
index 000000000..b6c2a2278
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-es/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Asegúrate de que NFC está encendido en Ajustes &gt; Más &gt; NFC, y asegúrate de que Android Beam está también activado en ese mismo apartado.</li>
+<li>Mantén los dos dispositivos con ambos reversos juntos (deben estar casi en contacto) y notarás una vibración.</li>
+<li>Después de la vibración verás el contenido de tu dispositivo convertirse en una especie de ficha con una animación de Star Trek de fondo.</li>
+<li>Pulsa la ficha y el contenido será cargado en el dispositivo de la otra persona.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
index 6bede7bd6..0833c35d9 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
@@ -23,7 +23,9 @@
<h2>Bibliothèques</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Licence Apache v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Bibliothèque de soutien Android v4</a> (Licence Apache v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Bibliothèque de soutien Android v7 « appcompat »</a> (Licence Apache v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licence Apache v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
index d85882a9b..c86c4a465 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>supprimer l'exportation non nécessaire des clefs publiques lors de l'exportation d'une clef secrète</li>
+<li>correctif de définition de la date date de péremption des clefs (merci à Ash Hughes)</li>
+<li>autres correctifs internes affectant la modifications des clefs (merci à Ash hughes)</li>
+<li>interrogation des serveurs de clefs directement depuis l'écran d'importation</li>
+<li>correctif de mise en page et du style des fenêtres de dialogue sur Android 2.2-3.0</li>
<li>corrige un plantage pour les clefs avec des ID utilisateur vides</li>
<li>corrige un plantage et des listes vides en revenant de l'écran de signature</li>
<li>Bouncy Castle (bibliothèque cryptographique) mise à jour de 1.47 à 1.50 et compilée depuis la source</li>
-<li>supprimer l'exportation non nécessaire des clefs publiques lors de l'exportation d'une clef secrète</li>
<li>correction du téléversement d'une clef depuis l'écran de signature</li>
</ul>
<h2>2.2</h2>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_nfc_beam.html
index 6d6e7d693..673e5b224 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>Comment recevoir des clefs</h2>
<ol>
-<li>Aller à la « Gestion des clefs publiques » de votre partenaire et appuyer longuement sur la clef que vous voulez partager.</li>
+<li>Allez aux contacts de votre partenaire et ouvrez le contact que vous voulez partager.</li>
<li>Tenir les deux appareils dos à dos (se touchant presque) et une vibration sera ressentie.</li>
<li>Après la vibration, le contenu de l'appareil de votre partenaire deviendra un objet en forme de carte avec une animation à la Star Trek en arrière-plan.</li>
<li>Toquer la carte et le contenu se chargera alors sur votre appareil.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
index bec69318b..4be071ec9 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>Logiciel EXPÉRIMENTAL</h2>
-<p>Ce logiciel est EXPÉRIMENTAL. À utiliser à vos propres risques !</p>
-
<h2>Commencer</h2>
-<p>Il vous faut d'abord des clefs. Importez ou créez-les depuis le menu des options de « Mes clefs secrètes ».<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>Il est recommandé que vous installiez le Gestionnaire de fichiers OI afin de pouvoir utiliser le bouton Parcourir pour choisir des fichiers depuis le Porte-clefs OpenPGP.</p>
+<p>Vous avez d'abord besoin d'une paire de clefs personelles. Créez-en une avec l'option du menu « Mes clefs » ou importez des paires de clefs existantes avec « Importer des clefs ». Ensuite vous pouvez télécharger les clefs de vos amis, ou les échanger par codes QR ou NFC.</p>
-<h2>Les gros morceaux à faire</h2>
-<ul>
-<li>L'intégration à K-9 Mail n'est pas publiée</li>
-<li>L'importation de clefs existantes sera dépouillé de certificats pour l'instant</li>
-<li>PGP/MIME est manquant dans K-9 Mail</li>
-</ul>
-<p>Si vous voulez contribuer, bifurquer et faire une demande d'extraction sur Github : <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p>
<h2>J'ai trouvé un bogue dans le Porte-clefs OpenPGP !</h2>
-<p>Veuillez le rapporter avec le <a href="https://github.com/dschuermann/openpgp-keychain/issues">gestionnaire de bogues du Porte-clefs OpenPGP</a>.</p>
+<p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogues du Porte-clefs OpenPGP</a>.</p>
+
+<h2>Contribuer</h2>
+<p>Si vous voulez nous aider à développer le Porte-clefs OpenPGP en y contribuant par du code, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">veuillez suivre notre petit guide sur Github</a>.</p>
+
+<h2>Traductions</h2>
+<p>Aidez-nous à traduire le Porte-clefs OpenPGP ! Tout le monde peut y participer sur la <a href="https://www.transifex.com/projects/p/openpgp-keychain/">page Transifex du Porte-clefs OpenPGP Keychain</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-fr/nfc_beam_share.html
index b2592fd8e..b63c9ac84 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/nfc_beam_share.html
@@ -4,7 +4,7 @@
<ol>
<li>Assurez-vous que la NFC est activée dans Paramètres &gt; Paramètres supplémentaires &gt; NFC, ainsi que Android Beam. </li>
<li>Tenir les deux appareils dos à dos (se touchant presque) et une vibration sera ressentie.</li>
-<li>Après la vibration, le contenu de l'appareil de votre partenaire deviendra un objet en forme de carte avec une animation à la Star Trek en arrière-plan.</li>
+<li>Après la vibration, le contenu de votre appareil deviendra un objet en forme de carte avec une animation à la Star Trek en arrière-plan.</li>
<li>Toquer la carte et le contenu se chargera alors sur votre appareil.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html
new file mode 100644
index 000000000..51e0b8c25
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html
@@ -0,0 +1,43 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
+<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> は AndroidにおけるOpenPGP実装の一つです。開発はAndroid Privacy Guard (APG)から分岐して始まりました。</p>
+<p>ライセンス: GPLv3以降</p>
+
+<h2>OpenPGP Keychain開発者</h2>
+<ul>
+<li>Dominik Schürmann (主任開発者)</li>
+<li>Ash Hughes (暗号関係パッチ提供)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+
+</ul>
+<h2>APG 1.xの開発者達</h2>
+<ul>
+<li>'Thialfihar' (主任開発者)</li>
+<li>'Senecaso' (QRコード, 鍵署名, 鍵アップロード関係)</li>
+<li>Oliver Runge</li>
+<li>Markus Doits</li>
+</ul>
+<h2>ライブラリ</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
+<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (パブリックドメイン)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html
new file mode 100644
index 000000000..4878a3b55
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html
@@ -0,0 +1,108 @@
+<html>
+<head></head>
+<body>
+<h2>2.3</h2>
+<ul>
+<li>秘密鍵のエクスポート時における必要でない公開鍵のエクスポートの削除 (thanks to Ash Hughes)</li>
+<li>鍵の期限日時設定の修正 (thanks to Ash Hughes)</li>
+<li>鍵編集時のさらなる内部修正 (thanks to Ash Hughes)</li>
+<li>インポート画面から直接鍵サーバへ要求するようにした</li>
+<li>Android 2.2から3.0でのレイアウトとダイアログスタイルの修正</li>
+<li>空ユーザIDの鍵でのクラッシュ修正</li>
+<li>署名画面から戻ってきたときにリストが空だとクラッシュするのを修正</li>
+<li>Bouncy Castle (cryptography library) を1.47 から 1.50アップデートおよびソースからのビルド</li>
+<li>署名画面からの鍵のアップロード修正</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>ナビゲーションドロワーの新しいデザイン</li>
+<li>新しい公開鍵リストデザイン</li>
+<li>新しい公開鍵ビュー</li>
+<li>鍵のインポート時のバグ修正</li>
+<li>鍵のクロス証明 (thanks to Ash Hughes)</li>
+<li>適切な UTF-8 パスワード処理 (thanks to Ash Hughes)</li>
+<li>新しい言語での最初のバージョン (thanks to the contributors on Transifex)</li>
+<li>QRコードによる鍵共有の修正と改善</li>
+<li>APIでのパッケージ署名検証</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>APIアップデート、K-9 Mail統合準備</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>たくさんのバグ修正</li>
+<li>開発者向け新API</li>
+<li>Googleによる擬似乱数生成器バグの修正</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>再デザイン完了</li>
+<li>QRコード、NFCビームでの公開鍵共有</li>
+<li>鍵への署名</li>
+<li>鍵サーバへアップロード</li>
+<li>インポート問題修正</li>
+<li>新しいAIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>鍵サーバの基本サポート</li>
+<li>App2SD</li>
+<li>パスフレーズのキャッシュ時間について1,2,4,8時間の選択肢追加</li>
+<li>翻訳: ノルウェー語 (thanks, Sander Danielsen), 中国語 (thanks, Zhang Fredrick) 追加</li>
+<li>バグ修正</li>
+<li>最適化</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>改行を含まないテキストの署名検証問題の修正</li>
+<li>パスフレーズのキャッシュ時間 (20,40,60分) のオプション追加</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>Froyo でのアカウント追加時クラッシュの修正</li>
+<li>セキュアファイル削除</li>
+<li>鍵ファイルインポート後の削除オプション</li>
+<li>ストリーム暗号化/復号化 (ギャラリーなど)</li>
+<li>新しいオプション (言語、強制V3署名)</li>
+<li>インタフェース変更</li>
+<li>バグ修正</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>ドイツ語およびイタリア語翻訳追加</li>
+<li>BCソースが重複してしまっていたことによる、より小さいパッケージ化</li>
+<li>新しい設定GUI</li>
+<li>ローカライズでのレイアウトを適合化</li>
+<li>署名バグ修正</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>クエリービルダーによるSDKのいくつかのバグによるクラッシュの修正</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>鍵エクスポートできる時と暗号化/署名中のクラッシュ修正</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>鍵リストのフィルタ可能化</li>
+<li>暗号化鍵の事前選択のよりスマートな実装</li>
+<li>VIEWおよびSENDについて新しいインテントのハンドリング、ファイルマネージャ外のファイルを暗号化/復号化するのを受け付けるようになる。</li>
+<li>K-9 Mailにおける修正と追加機能 (鍵事前選択)、新しいベータビルド提供</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>1.0.0で壊れたGmailアカウントリストアップを再度修正</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail 統合、K-9 MailでのAPG サポートのベータビルド</li>
+<li>(ASTROを含む)ファイルマネージャのさらなるサポート</li>
+<li>スロベニア語翻訳追加</li>
+<li>より早くてメモリ使用量の少ない新しいデータベース</li>
+<li>他のアプリでのインテントおよびコンテンツプロバイダの定義</li>
+<li>バグ修正</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_nfc_beam.html
new file mode 100644
index 000000000..c19280fd1
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>鍵の受信方法</h2>
+<ol>
+<li>パートナーの連絡先に行き、共有したい連絡先を開きます。</li>
+<li>2つのデバイスを背中合せ(ほとんどすべてのタッチ方法)にしてバイブを感じるまで保持しておいてください。</li>
+<li>バイブの後、相手のデバイスでスタートレック風のバックグラウンドアニメーションしているカード風のコンテンツを見ると思います。</li>
+<li>カードをタップしコンテンツをあなたのデバイスにロードします。</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html
new file mode 100644
index 000000000..5c78a1273
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>入門</h2>
+<p>最初にあなたの個人用鍵ペアが必要になります。オプションメニューの"自分の鍵"で生成するか、"鍵のインポート"から既存の鍵ペアをインポートします。その後、あなたの友人の鍵をダウンロード、もしくはQRコードやNFCで交換します。</p>
+
+<p>ファイルの選択を拡張するには<a href="market://details?id=org.openintents.filemanager">OI File Manager</a>、<a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>を生成したQRコードのスキャンのため、それぞれのインストールを必要とします。 リンクをクリックして、Google Play Store上かF-Droidからインストールしてください。</p>
+
+<h2>OpenPGP Keychainにバグを発見した!</h2>
+<p><a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">OpenPGP KeychainのIssueトラッカー</a>を使ってバグレポートを送ってください。</p>
+
+<h2>寄贈</h2>
+<p>もし、あなたが OpenPGP Keychain の開発を助け、コードを寄贈するというなら、<a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">Githubの寄贈ガイドを確認</a>して下さい。</p>
+
+<h2>翻訳</h2>
+<p>OpenPGP Keychainの翻訳を補助してください! だれでも、<a href="https://www.transifex.com/projects/p/openpgp-keychain/">TransifexでのOpenPGP Keychainプロジェクト</a>に参加できます。</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-ja/nfc_beam_share.html
new file mode 100644
index 000000000..422423a5d
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>設定 &gt; その他 &gt; NFC からNFCを有効にしてください、そしてAndroid Beamもまた選択してください。</li>
+<li>2つのデバイスを背中合せ(ほとんどすべてのタッチ方法)にしてバイブを感じるまで保持しておいてください。</li>
+<li>バイブの後、相手のデバイスでスタートレック風のバックグラウンドアニメーションしているカード風のコンテンツを見ると思います。</li>
+<li>カードをタップしコンテンツを他のデバイスに読み込ませてください。</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
index 566029511..b11aaab35 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
@@ -23,7 +23,9 @@
<h2>Компоненты</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
index d923de570..2a324202f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>удален не требующийся экспорт публичного ключа при экспорте секретного ключа (спасибо, Ash Hughes)</li>
+<li>исправлена ошибка срока годности ключей (спасибо, Ash Hughes)</li>
+<li>исправления ошибок при изменении ключей (спасибо, Ash Hughes)</li>
+<li>запрос ключа с сервера прямо из окна импорта ключей</li>
+<li>исправление внешнего вида для Android 2.2-3.0</li>
<li>исправлено падение когда ключ не содержал имя пользователя</li>
<li>исправлено падение и пустой список при возвращении из окна подписания</li>
<li>криптографическая библиотека Bouncy Castle обновлена до версии 1.50</li>
-<li>удален не требующийся экспорт публичного ключа при экспорте секретного ключа (спасибо, Ash Hughes)</li>
<li>исправлена загрузка ключа из окна подписания</li>
</ul>
<h2>2.2</h2>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
index d55f3296b..99e6f263d 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>ЭКСПЕРИМЕНТАЛЬНАЯ программа</h2>
-<p>Это ЭКСПЕРИМЕНТАЛЬНАЯ версия. Используйте на свой страх и риск!</p>
-
<h2>Приступая</h2>
-<p>Для начала Вам потребуются ключи. Воспользуйтесь функцией Импорт в меню раздела "Мои ключи".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>Для удобства выбора файлов рекомендуется установить OI File Manager. Он будет вызываться при нажатии кнопки выбора файла.</p>
+<p>Для начала вам понадобится своя пара ключей. Воспользуйтесь меню в разделе "Мои ключи", что бы создать новую, или добавьте ранее созданную пару в разделе "Импорт ключей". После этого вы сможете скачать ключи ваших друзей или обменяться ключами посредством QR кодов или NFC.</p>
-<h2>Над чем еще ведётся работа</h2>
-<ul>
-<li>Интеграция с почтовой программой K9 Mail.</li>
-<li>При импорте сущестующих ключей теряются подписи</li>
-<li>Отсутсвует поддержка PGP/MIME в K9 Mail</li>
-</ul>
-<p>Если вы ходите принять участие в доработке и развитии проекта, посетите страницу проекта на Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>Рекомендуется установить <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для удобного выбора файлов и <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для распознавания QR кодов. Перейдите по ссылкам на соответствующие страницы Google Play или F-Droid для дальнейшей установки.</p>
<h2>Я нашел ошибку в OpenPGP Keychain!</h2>
-<p>Пожалуйста, сообщите о ней в разделе '<a href="https://github.com/dschuermann/openpgp-keychain/issues">Проблемы с OpenPGP Keychain</a>'.</p>
+<p>Пожалуйста, сообщайте о возникших проблемах и найденных ошибках в разделе <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Решение проблем OpenPGP Keychain</a>.</p>
+
+<h2>Вклад в развитие</h2>
+<p>Если Вы хотите помочь в разработке OpenPGP Keychain, обратитесь к <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">инструкции на Github</a>.</p>
+
+<h2>Перевод</h2>
+<p>Помогите переводить OpenPGP Keychain! Каждый может принять участие в переводе <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain на Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
index 3d4549cbd..3a95c8c16 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
@@ -23,7 +23,9 @@
<h2>Kütüphaneler</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-tr/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
index 7b6f22e94..c6c2e1eed 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
@@ -23,7 +23,9 @@
<h2>Бібліотеки</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (ліцензія Apache в.2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Бібліотека підтримки Android в.4</a> (Ліцензія Apache в. 2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Бібліотека підтримки Android в.7 'appcompat'</a> (Ліцензія Apache в.2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (ліцензія Apache в. 2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
index 174a2b0d4..0b67fa3a9 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>видалений непотрібний експорт публічного ключа при експорті секретного ключа (завдяки Ash Hughes)</li>
+<li>виправлено налаштування дат дії ключів (завдяки Ash Hughes)</li>
+<li>більше внутрішніх виправлень при редагуванні ключів (завдяки Ash Hughes)</li>
+<li>сервери запитаного ключа безпосередньо з екрану імпорту</li>
+<li>виправлено стиль розмітки і діалогу у Андроїд 2.2-3.0</li>
<li>виправлено збої, коли ключ мав порожній ідентифікатор користувача</li>
<li>виправлено збої та порожні списки при поверненні з екрану реєстрації</li>
<li>Bouncy Castle (криптографічна бібліотека) оновлена з версії 1.47 до 1.50 та зібрана з коду</li>
-<li>видалений непотрібний експорт публічного ключа при експорті секретного ключа (завдяки Ash Hughes)</li>
<li>виправлено завантаження ключа з вікна реєстрації</li>
</ul>
<h2>2.2</h2>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_nfc_beam.html
index 4a91477d4..dc34048d3 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>Як обмінятися ключами</h2>
<ol>
-<li>Натисніть і утримуйте ключ, який ви хочете передати.</li>
+<li>Перейдіть до контактних даних ваших партнерів і відкрийте контакт, який ви хочете надіслати.</li>
<li>Піднесіть обидва пристрої впритул зворотними сторонами (до повного торкання). Ви відчуєте невелику вібрацію.</li>
<li>Після вібрації пристроїв на екрані з'явиться картка з передаваним вмістом.</li>
<li>Натисніть на картку, що б передати дані з одного пристрою на інший.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
index c2b5a8019..520224815 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>ЕКСПЕРИМЕНТАЛЬНА програма</h2>
-<p>Це ЕКСПЕРИМЕНТАЛЬНА версія. Використовуйте на свій страх і ризик!</p>
-
<h2>Приступаючи до роботи</h2>
-<p>Для початку Вам будуть потрібні ключі. Скористайтеся функцією Імпорт в меню розділу "Мої ключі".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>Для зручності вибору файлів рекомендується встановити OI File Manager. Він буде викликатися при натисканні кнопки вибору файлу.</p>
+<p>Спершу вам потрібна персональна в'язка ключів. Створіть одну через меню параметрів у "Мої Ключі" або імпортуйте наявні в'язки ключів через "Імпорт ключів". Після цього ви зможете завантажувати ключі ваших друзів чи обміняти їх через штрих-коди або NFC.</p>
-<h2>Над чим ще ведеться робота</h2>
-<ul>
-<li>Інтеграція з поштовою програмою K9 Mail.</li>
-<li>При імпорті існуючих ключів губляться підписи</li>
-<li>Відсутня підтримка PGP/MIME K9 Mail</li>
-</ul>
-<p>Якщо ви ходите взяти участь у доопрацюванні та розвитку проекту, відвідайте сторінку проекту на Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-брелок</a></p>
+<p>Рекомендуємо вам встановити <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для поліпшеного виділення файлів та <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для сканування згенерованих штрих-кодів. Натискання посилань відкриє Google Play або F-Droid для встановлення.</p>
<h2>Я знайшов помилку в OpenPGP Keychain!</h2>
-<p>Будь ласка, повідомте про неї в розділі '<a href="https://github.com/dschuermann/openpgp-keychain/issues">Проблеми з В'язкою ключів OpenPGP</a>'.</p>
+<p>Будь ласка, повідомте про ваду за допомогою <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">відстежувача проблем OpenPGP Keychain</a>.</p>
+
+<h2>Внесок</h2>
+<p>Якщо ви хочете допомогти нам у розробці OpenPGP Keychain через редагування коду програми <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">підпишіться на наш невеличкий посібник у Github</a>.</p>
+
+<h2>Переклади</h2>
+<p>Допоможіть перекласти OpenPGP Keychain! Кожний може взяти участь у <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain на Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
index 7db2f83de..773d11fa7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
@@ -23,7 +23,9 @@
<h2>Libraries</h2>
<ul>
<li>
-<a href="http://actionbarsherlock.com">ActionBarSherlock</a> (Apache License v2)</li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
<li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
index 32ad1a13d..abf660ba8 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
@@ -3,10 +3,14 @@
<body>
<h2>2.3</h2>
<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
-<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix upload of key from signing screen</li>
</ul>
<h2>2.2</h2>
@@ -42,7 +46,7 @@
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
index 2e7e637e5..88492731c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
@@ -3,7 +3,7 @@
<body>
<h2>How to receive keys</h2>
<ol>
-<li>Go to your partners 'Manage Public Keys' and long press on the key you want to share.</li>
+<li>Go to your partners contacts and open the contact you want to share.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the your device.</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
index 1386e8cc1..198dfe64f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
@@ -1,22 +1,19 @@
<html>
<head></head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
+
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
index 453d435e3..083e055c7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
@@ -3,8 +3,8 @@
<body>
<ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
<li>Tap the card and the content will then load on the other person’s device.</li>
</ol>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_about.html b/OpenPGP-Keychain/src/main/res/raw/help_about.html
index 85130965c..51e3f1325 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_about.html
@@ -5,11 +5,11 @@ And don't add newlines before or after p tags because of transifex -->
<head>
</head>
<body>
-<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
-<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p>
-<h2>Developers OpenPGP Keychain</h2>
+<h2>Developers OpenKeychain</h2>
<ul>
<li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li>
@@ -34,8 +34,9 @@ And don't add newlines before or after p tags because of transifex -->
<li><a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
<li><a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li><a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li><a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
index 7bb558a24..17ad853de 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
@@ -10,7 +10,7 @@ And don't add newlines before or after p tags because of transifex -->
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
-<li>querying key servers directly from the import screen</li>
+<li>querying keyservers directly from the import screen</li>
<li>fix layout and dialog style on Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li>
<li>fix crash and empty lists when coming back from signing screen</li>
@@ -55,7 +55,7 @@ And don't add newlines before or after p tags because of transifex -->
<h2>1.0.8</h2>
<ul>
-<li>basic key server support</li>
+<li>basic keyserver support</li>
<li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_start.html b/OpenPGP-Keychain/src/main/res/raw/help_start.html
index 097e22ba8..6c8c49846 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_start.html
@@ -5,23 +5,19 @@ And don't add newlines before or after p tags because of transifex -->
<head>
</head>
<body>
-<h2>EXPERIMENTAL software</h2>
-<p>This is EXPERIMENTAL software. Use at your own risk!</p>
-
<h2>Getting started</h2>
-<p>First you need some keys. Import or create them via the option menus in "My Secret Keys".
-<!--<p>Install K-9 Mail for the best integration, it will supports OpenPGP Keychain for PGP/INLINE and lets you directly encrypt/decrypt emails.-->
-<br/>It is recommended that you install OI File Manager to be able to use the browse button for file selection in OpenPGP Keychain.</p>
+<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
-<h2>Big ToDos</h2>
-<ul>
-<li>K9 Mail integration not published</li>
-<li>Importing existing keys will be stripped of certificates right now</li>
-<li>PGP/MIME in K9 Mail is missing</li>
-</ul>
-<p>If you want to contribute, fork it and do a pull request on Github: <a href="https://github.com/dschuermann/openpgp-keychain">https://github.com/dschuermann/openpgp-keychain</a></p>
+<h2>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
-<h2>I found a bug in OpenPGP Keychain!</h2>
-<p>Please report it in the <a href="https://github.com/dschuermann/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/values-de/strings.xml b/OpenPGP-Keychain/src/main/res/values-de/strings.xml
index ebf303f8a..d421fd141 100644
--- a/OpenPGP-Keychain/src/main/res/values-de/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-de/strings.xml
@@ -12,7 +12,7 @@
<string name="title_edit_key">Schlüssel bearbeiten</string>
<string name="title_preferences">Einstellungen</string>
<string name="title_api_registered_apps">Registrierte Anwendungen</string>
- <string name="title_key_server_preference">Einstellung der Schlüsselserver</string>
+ <string name="title_key_server_preference">Schlüsselserver</string>
<string name="title_change_pass_phrase">Passwort ändern</string>
<string name="title_set_passphrase">Passwort setzen</string>
<string name="title_send_email">E-Mail senden...</string>
@@ -22,10 +22,10 @@
<string name="title_export_key">Schlüssel exportieren</string>
<string name="title_export_keys">Schlüssel exportieren</string>
<string name="title_key_not_found">Schlüssel nicht gefunden</string>
- <string name="title_key_server_query">Schlüssel-Server abfragen</string>
+ <string name="title_key_server_query">Schlüsselserver abfragen</string>
<string name="title_send_key">Auf Schlüsselserver hochladen</string>
<string name="title_unknown_signature_key">Unbekannter Signaturschlüssel</string>
- <string name="title_sign_key">Schlüssel signieren</string>
+ <string name="title_certify_key">Schlüssel beglaubigen</string>
<string name="title_key_details">Schlüsseldetails</string>
<string name="title_help">Hilfe</string>
<!--section-->
@@ -37,17 +37,16 @@
<string name="section_master_key">Hauptschlüssel</string>
<string name="section_master_user_id">Hauptbenutzer-ID</string>
<string name="section_actions">Aktionen</string>
- <string name="section_signing_key">Dein Signaturschlüssel</string>
+ <string name="section_certification_key">Mit diesem Schlüssel beglaubigen</string>
<string name="section_upload_key">Schlüssel hochladen</string>
<string name="section_key_server">Schlüsselserver</string>
+ <string name="section_encrypt_and_or_sign">Verschlüsseln und/oder Signieren</string>
+ <string name="section_decrypt_verify">Entschlüsseln und Verifizieren</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Signieren (Zwischenablage)</string>
- <string name="btn_encrypt_to_clipboard">In die Zwischenablage verschlüsseln</string>
- <string name="btn_encrypt_and_send">Verschlüsseln und senden...</string>
- <string name="btn_sign_and_send">Signieren und senden...</string>
<string name="btn_sign">Signieren</string>
+ <string name="btn_certify">Beglaubigen</string>
<string name="btn_decrypt">Entschlüsseln</string>
- <string name="btn_verify">Signatur prüfen</string>
+ <string name="btn_decrypt_verify">Entschlüsseln und Verifizieren</string>
<string name="btn_select_encrypt_keys">Empfänger auswählen</string>
<string name="btn_encrypt_file">Datei verschlüsseln</string>
<string name="btn_save">Speichern</string>
@@ -61,6 +60,9 @@
<string name="btn_export_to_server">Auf Schlüsselserver hochladen</string>
<string name="btn_next">Weiter</string>
<string name="btn_back">Zurück</string>
+ <string name="btn_clipboard">Zwischenablage</string>
+ <string name="btn_share">Teilen mit…</string>
+ <string name="btn_lookup_key">Schlüssel nachschlagen</string>
<!--menu-->
<string name="menu_preferences">Einstellungen</string>
<string name="menu_help">Hilfe</string>
@@ -99,6 +101,7 @@
<string name="label_passphrase_again">Wiederholen</string>
<string name="label_algorithm">Algorithmus</string>
<string name="label_ascii_armor">ASCII-Armor</string>
+ <string name="label_select_public_keys">Empfänger</string>
<string name="label_delete_after_encryption">Nach Verschlüsselung löschen</string>
<string name="label_delete_after_decryption">Nach Entschlüsselung löschen</string>
<string name="label_encryption_algorithm">Verschlüsselungsalgorithmus</string>
@@ -108,7 +111,6 @@
<string name="label_passphrase_cache_ttl">Passwort-Cache</string>
<string name="label_message_compression">Nachrichten-Komprimierung</string>
<string name="label_file_compression">Datei-Komprimierung</string>
- <string name="label_force_v3_signature">OpenPGPv3-Signaturen erzwingen</string>
<string name="label_key_servers">Schlüsselserver</string>
<string name="label_key_id">Schlüssel-ID</string>
<string name="label_creation">Erstellungsdatum</string>
@@ -119,19 +121,21 @@
<string name="label_name">Name</string>
<string name="label_comment">Kommentar</string>
<string name="label_email">E-Mail</string>
- <string name="label_send_key">Lade Schlüssel nach dem Signieren auf den ausgewählten Schlüsselserver hoch</string>
+ <string name="label_send_key">Schlüssel nach Beglaubigung auf ausgewählten Schlüsselserver hochladen</string>
<string name="label_fingerprint">Fingerabdruck</string>
<string name="select_keys_button_default">Auswählen</string>
<plurals name="select_keys_button">
<item quantity="one">%d ausgewählt</item>
<item quantity="other">%d ausgewählt</item>
</plurals>
+ <string name="user_id_no_name">&lt;kein Name&gt;</string>
<string name="none">&lt;keine&gt;</string>
<string name="no_key">&lt;kein Schlüssel&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">kann verschlüsseln</string>
<string name="can_sign">kann signieren</string>
<string name="expired">abgelaufen</string>
+ <string name="revoked">zurückgezogen</string>
<plurals name="n_key_servers">
<item quantity="one">%d Schlüsselserver</item>
<item quantity="other">%d Schlüsselserver</item>
@@ -213,9 +217,12 @@
<item quantity="one">%d Schlüssel gefunden.</item>
<item quantity="other">%d Schlüssel gefunden.</item>
</plurals>
- <string name="unknown_signature_key_touch_to_look_up">Unbekannte Unterschrift, zum Suchen berühren. </string>
- <string name="lookup_unknown_key">Unbekannter Schlüssel %s, soll dieser auf einem Schlüsselserver gesucht werden?</string>
- <string name="key_send_success">Schlüssel erfolgreich zum Server geschickt.</string>
+ <string name="unknown_signature">Unbekannte Signatur. Benutze den Button um den fehlenden Schlüssel nachzuschlagen.</string>
+ <plurals name="bad_keys_encountered">
+ <item quantity="one">%d schlechter privater Schlüssel ignoriert. Evtl. wurde er mit folgender Option exportiert:\n --export-secret-subkeys\nUnbedingt mit der Option \n --export-secret-keys\nexportieren.</item>
+ <item quantity="other">%d schlechte private Schlüssel ignoriert. Evtl. wurden sie mit folgender Option exportiert:\n --export-secret-subkeys\nUnbedingt mit der Option \n --export-secret-keys\nexportieren.</item>
+ </plurals>
+ <string name="key_send_success">Schlüssel wurde erfolgreich hochgeladen.</string>
<string name="key_sign_success">Schlüssel erfolgreich signiert</string>
<string name="list_empty">Diese Liste ist leer!</string>
<string name="nfc_successfull">Schlüssel erfolgreich mit NFC Beam gesendet!</string>
@@ -254,19 +261,22 @@
<string name="error_jelly_bean_needed">Android 4.1 alias Jelly Bean wird benötigt um Androids NFC-Beam nutzen zu können!</string>
<string name="error_nfc_needed">NFC steht auf diesem Gerät nicht zur Verfügung!</string>
<string name="error_nothing_import">Nichts zu importieren!</string>
+ <string name="error_expiry_must_come_after_creation">Ablaufdatum muss später sein als das Erstellungsdatum</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Bitte lösche ihn unter \'Meine Schlüssel\'!</item>
+ <item quantity="other">Bitte lösche sie unter \'Meine Schlüssel\'!</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">fertig.</string>
<string name="progress_saving">speichern...</string>
<string name="progress_importing">importieren...</string>
<string name="progress_exporting">exportieren...</string>
- <string name="progress_generating">erstelle Schlüssel, dies kann eine Weile dauern...</string>
<string name="progress_building_key">erstelle Schlüssel...</string>
<string name="progress_preparing_master_key">Hauptschlüssel wird vorbereitet...</string>
<string name="progress_certifying_master_key">Hauptschlüssel wird beglaubigt...</string>
<string name="progress_building_master_key">erstelle Hauptring...</string>
<string name="progress_adding_sub_keys">füge Unterschlüssel hinzu...</string>
<string name="progress_saving_key_ring">Schlüssel wird gespeichert...</string>
- <string name="progress_importing_secret_keys">importiere private Schlüssel...</string>
<plurals name="progress_exporting_key">
<item quantity="one">Schlüssel wird exportiert…</item>
<item quantity="other">Schlüssel werden exportiert…</item>
@@ -327,17 +337,15 @@
<string name="intent_send_encrypt">OpenPGP: Verschlüsseln</string>
<string name="intent_send_decrypt">OpenPGP: Entschlüsseln</string>
<!--Remote API-->
- <string name="api_no_apps">Keine registrierten Anwendungen vorhanden!</string>
<string name="api_settings_show_advanced">Erweiterte Einstellungen anzeigen</string>
<string name="api_settings_hide_advanced">Erweiterte Einstellungen ausblenden</string>
<string name="api_settings_no_key">Kein Schlüssel ausgewählt</string>
<string name="api_settings_select_key">Schlüssel auswählen</string>
<string name="api_settings_save">Speichern</string>
<string name="api_settings_cancel">Abbrechen</string>
- <string name="api_settings_revoke">Zugang widerufen</string>
+ <string name="api_settings_revoke">Zugriff widerufen</string>
<string name="api_settings_package_name">Paketname</string>
<string name="api_settings_package_signature">SHA-256 der Paketsignatur</string>
- <string name="api_register_text">Folgende Anwendung beantragt Zugriff zur API von OpenPGP Keychain.\n\nZugriff dauerhaft erlauben?</string>
<string name="api_register_allow">Zugriff erlauben</string>
<string name="api_register_disallow">Zugriff verbieten</string>
<string name="api_register_error_select_key">Bitte einen Schlüssel auswählen!</string>
@@ -363,6 +371,7 @@
<string name="key_list_empty_button_import">existierende Schlüssel importierst.</string>
<!--Key view-->
<string name="key_view_action_encrypt">Für diesen Kontakt verschlüsseln</string>
+ <string name="key_view_action_certify">Schlüssel dieses Kontakts beglaubigen</string>
<!--Navigation Drawer-->
<string name="nav_contacts">Kontakte</string>
<string name="nav_encrypt">Verschlüsseln</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
index 8f508a885..6efe9548d 100644
--- a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
@@ -10,7 +10,6 @@
<string name="title_edit_key">Editar clave</string>
<string name="title_preferences">Preferencias</string>
<string name="title_api_registered_apps">Aplicaciones registradas</string>
- <string name="title_key_server_preference">Preferencias del servidor de claves</string>
<string name="title_change_pass_phrase">Cambiar contraseña</string>
<string name="title_set_passphrase">Establecer contraseña</string>
<string name="title_send_email">Enviar correo electrónico...</string>
@@ -20,9 +19,7 @@
<string name="title_export_key">Exportar clave</string>
<string name="title_export_keys">Exportar claves</string>
<string name="title_key_not_found">Clave no encontrada</string>
- <string name="title_key_server_query">Solicitar al servidor de claves</string>
<string name="title_unknown_signature_key">Clave de firma desconocida</string>
- <string name="title_sign_key">Clave de firma</string>
<string name="title_help">Ayuda</string>
<!--section-->
<string name="section_user_ids">IDs de usuario</string>
@@ -31,13 +28,8 @@
<string name="section_defaults">Por defecto</string>
<string name="section_advanced">Avanzado</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Firmar (Portapapeles)</string>
- <string name="btn_encrypt_to_clipboard">Cifrar a portapapeles</string>
- <string name="btn_encrypt_and_send">Cifrar y enviar</string>
- <string name="btn_sign_and_send">Firmar y enviar</string>
<string name="btn_sign">Firmar</string>
<string name="btn_decrypt">Descifrar</string>
- <string name="btn_verify">Verificar</string>
<string name="btn_select_encrypt_keys">Escoger destinatarios</string>
<string name="btn_encrypt_file">Cifrar archivo</string>
<string name="btn_save">Guardar</string>
@@ -61,7 +53,6 @@
<string name="menu_create_key">Crear clave</string>
<string name="menu_create_key_expert">Crear clave (experto)</string>
<string name="menu_search">Buscar</string>
- <string name="menu_key_server">Importar desde servidor de claves</string>
<string name="menu_sign_key">Clave de firma</string>
<!--label-->
<string name="label_sign">Firmar</string>
@@ -80,8 +71,6 @@
<string name="label_symmetric">Contraseña</string>
<string name="label_message_compression">Compresión de mensaje</string>
<string name="label_file_compression">Compresión de archivo</string>
- <string name="label_force_v3_signature">Forzar firmas V3</string>
- <string name="label_key_servers">Servidores de claves</string>
<string name="label_key_id">ID de clave</string>
<string name="label_creation">Creación</string>
<string name="label_expiry">Expiración</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-es/strings.xml b/OpenPGP-Keychain/src/main/res/values-es/strings.xml
new file mode 100644
index 000000000..d6b0f9562
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-es/strings.xml
@@ -0,0 +1,393 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_manage_public_keys">Contactos</string>
+ <string name="title_manage_secret_keys">Claves secretas</string>
+ <string name="title_select_recipients">Seleccionar la clave pública</string>
+ <string name="title_select_secret_key">Seleccionar la clave secreta</string>
+ <string name="title_encrypt">Cifrar</string>
+ <string name="title_decrypt">Descifrar</string>
+ <string name="title_authentication">Frase de contraseña</string>
+ <string name="title_create_key">Crear clave</string>
+ <string name="title_edit_key"> Editar clave</string>
+ <string name="title_preferences"> Preferencias</string>
+ <string name="title_api_registered_apps">Aplicaciones registradas</string>
+ <string name="title_key_server_preference">Prioridad del servidor de claves</string>
+ <string name="title_change_pass_phrase">Cambiar la frase de contraseña</string>
+ <string name="title_set_passphrase">Establecer frase de contraseña</string>
+ <string name="title_send_email">Enviar email...</string>
+ <string name="title_encrypt_to_file">Cifrar hacia archivo</string>
+ <string name="title_decrypt_to_file">Descifrar hacia archivo</string>
+ <string name="title_import_keys">Importar claves</string>
+ <string name="title_export_key">Exportar clave</string>
+ <string name="title_export_keys">Exportar claves</string>
+ <string name="title_key_not_found">Clave no encontrada</string>
+ <string name="title_key_server_query">Consultar servidor de claves</string>
+ <string name="title_send_key">Cargar al servidor de claves</string>
+ <string name="title_unknown_signature_key">Clave de firma desconocida</string>
+ <string name="title_certify_key">Certificar clave</string>
+ <string name="title_key_details">Detalles de la clave</string>
+ <string name="title_help">Ayuda</string>
+ <!--section-->
+ <string name="section_user_ids">IDs de usuario</string>
+ <string name="section_keys">Claves</string>
+ <string name="section_general">General</string>
+ <string name="section_defaults">Predeterminados</string>
+ <string name="section_advanced">Avanzado</string>
+ <string name="section_master_key">Clave maestra</string>
+ <string name="section_master_user_id">ID del usuario principal</string>
+ <string name="section_actions">Acciones</string>
+ <string name="section_certification_key">Tu clave usada para las certificaciones</string>
+ <string name="section_upload_key">Cargar clave</string>
+ <string name="section_key_server">Servidor de claves</string>
+ <string name="section_encrypt_and_or_sign">Cifrar y/o firmar</string>
+ <string name="section_decrypt_verify">Descifrar y verificar</string>
+ <!--button-->
+ <string name="btn_sign">Firmar</string>
+ <string name="btn_certify">Certificar</string>
+ <string name="btn_decrypt">Descifrar</string>
+ <string name="btn_decrypt_verify">Descifrar y verificar</string>
+ <string name="btn_select_encrypt_keys">Seleccionar destinatarios</string>
+ <string name="btn_encrypt_file">Cifrar archivo</string>
+ <string name="btn_save">Guardar</string>
+ <string name="btn_do_not_save">Cancelar</string>
+ <string name="btn_delete">Eliminar</string>
+ <string name="btn_no_date">Ninguno</string>
+ <string name="btn_okay">De acuerdo</string>
+ <string name="btn_change_passphrase">Cambiar la frase de contraseña</string>
+ <string name="btn_set_passphrase">Establecer frase de contraseña</string>
+ <string name="btn_search">Buscar</string>
+ <string name="btn_export_to_server">Cargar al servidor de claves</string>
+ <string name="btn_next">Siguiente</string>
+ <string name="btn_back">Volver</string>
+ <string name="btn_clipboard">Portapapeles</string>
+ <string name="btn_share">Compartir con...</string>
+ <string name="btn_lookup_key">Buscar clave</string>
+ <!--menu-->
+ <string name="menu_preferences">Ajustes</string>
+ <string name="menu_help">Ayuda</string>
+ <string name="menu_import_from_file">Importar desde archivo</string>
+ <string name="menu_import_from_qr_code">Importar desde código QR</string>
+ <string name="menu_import">Importar</string>
+ <string name="menu_import_from_nfc">Importar desde NFC</string>
+ <string name="menu_export_keys">Exportar todas las claves</string>
+ <string name="menu_export_key">Exportar hacia archivo</string>
+ <string name="menu_delete_key">Borrar clave</string>
+ <string name="menu_create_key">Crear clave</string>
+ <string name="menu_create_key_expert">Crear clave (experto)</string>
+ <string name="menu_search">Buscar</string>
+ <string name="menu_key_server">Importar desde servidor de claves</string>
+ <string name="menu_update_key">Actualizar desde servidor de claves</string>
+ <string name="menu_export_key_to_server">Cargar al servidor de claves</string>
+ <string name="menu_share">Compartir</string>
+ <string name="menu_share_title_fingerprint">Compartir la huella digital...</string>
+ <string name="menu_share_title">Compartir la clave completa...</string>
+ <string name="menu_share_default_fingerprint">con...</string>
+ <string name="menu_share_default">con...</string>
+ <string name="menu_share_qr_code">con código QR</string>
+ <string name="menu_share_qr_code_fingerprint">con código QR</string>
+ <string name="menu_share_nfc">con NFC</string>
+ <string name="menu_copy_to_clipboard">Copiar al portapapeles</string>
+ <string name="menu_sign_key"> Clave de firma</string>
+ <string name="menu_beam_preferences">Ajustes de Beam</string>
+ <string name="menu_key_edit_cancel">Cancelar</string>
+ <string name="menu_encrypt_to">Cifrar hacia...</string>
+ <!--label-->
+ <string name="label_sign">Firmar</string>
+ <string name="label_message">Mensaje</string>
+ <string name="label_file">Archivo</string>
+ <string name="label_no_passphrase">No hay frase de contraseña</string>
+ <string name="label_passphrase">Frase de contraseña</string>
+ <string name="label_passphrase_again">De nuevo</string>
+ <string name="label_algorithm">Algoritmo</string>
+ <string name="label_ascii_armor">Armadura ASCII</string>
+ <string name="label_select_public_keys">Destinatarios</string>
+ <string name="label_delete_after_encryption">Borrar después del cifrado</string>
+ <string name="label_delete_after_decryption">Borrar después del descifrado</string>
+ <string name="label_encryption_algorithm">Algoritmo de cifrado</string>
+ <string name="label_hash_algorithm">Algoritmo de Hash</string>
+ <string name="label_asymmetric">Clave pública</string>
+ <string name="label_symmetric">Frase de contraseña</string>
+ <string name="label_passphrase_cache_ttl">Caché de frase de contraseña</string>
+ <string name="label_message_compression">Compresión de mensaje</string>
+ <string name="label_file_compression">Compresión de archivo</string>
+ <string name="label_force_v3_signature">Forzar firmas OpenPGPv3 antiguas</string>
+ <string name="label_key_servers">Servidores de claves</string>
+ <string name="label_key_id">ID de clave</string>
+ <string name="label_creation">Creación</string>
+ <string name="label_expiry">Caducidad</string>
+ <string name="label_usage">Uso</string>
+ <string name="label_key_size">Tamaño de clave</string>
+ <string name="label_main_user_id">ID del usuario principal</string>
+ <string name="label_name">Nombre</string>
+ <string name="label_comment">Comentario</string>
+ <string name="label_email">Email</string>
+ <string name="label_send_key">Cargar clave al servidor de claves seleccionado después de la certificación</string>
+ <string name="label_fingerprint">Huella digital</string>
+ <string name="select_keys_button_default">Seleccionar</string>
+ <plurals name="select_keys_button">
+ <item quantity="one">%d seleccionado</item>
+ <item quantity="other">%d seleccionados</item>
+ </plurals>
+ <string name="user_id_no_name">&lt;sin nombre&gt;</string>
+ <string name="none">&lt;ninguna&gt;</string>
+ <string name="no_key">&lt;sin clave&gt;</string>
+ <string name="unknown_status"></string>
+ <string name="can_encrypt">se puede cifrar</string>
+ <string name="can_sign">se puede firmar</string>
+ <string name="expired">caducado</string>
+ <string name="revoked">revocado</string>
+ <plurals name="n_key_servers">
+ <item quantity="one">%d servidor de claves</item>
+ <item quantity="other">%d servidores de claves</item>
+ </plurals>
+ <string name="fingerprint">Huella digital:</string>
+ <string name="secret_key">Clave secreta:</string>
+ <!--choice-->
+ <string name="choice_none">Ninguna</string>
+ <string name="choice_sign_only">Solo firmar</string>
+ <string name="choice_encrypt_only">Solo cifrar</string>
+ <string name="choice_sign_and_encrypt">Firmar y cifrar</string>
+ <string name="choice_15secs">15 segs</string>
+ <string name="choice_1min">1 min</string>
+ <string name="choice_3mins">3 mins</string>
+ <string name="choice_5mins">5 mins</string>
+ <string name="choice_10mins">10 mins</string>
+ <string name="choice_20mins">20 mins</string>
+ <string name="choice_40mins">40 mins</string>
+ <string name="choice_1hour">1 hora</string>
+ <string name="choice_2hours">2 horas</string>
+ <string name="choice_4hours">4 horas</string>
+ <string name="choice_8hours">8 horas</string>
+ <string name="choice_forever">para siempre</string>
+ <string name="dsa">DSA</string>
+ <string name="elgamal">ElGamal</string>
+ <string name="rsa">RSA</string>
+ <string name="filemanager_title_open">Abrir...</string>
+ <string name="warning">Advertencia</string>
+ <string name="error">Error</string>
+ <string name="error_message">Error: %s</string>
+ <!--sentences-->
+ <string name="wrong_passphrase">Frase de contraseña incorrecta.</string>
+ <string name="using_clipboard_content">Usando el contenido del portapapeles.</string>
+ <string name="set_a_passphrase">Establece una frase de contraseña antes.</string>
+ <string name="no_filemanager_installed">No hay un gestor de archivos compatible instalado.</string>
+ <string name="passphrases_do_not_match">Las frases de contraseña no coinciden.</string>
+ <string name="passphrase_must_not_be_empty">Las frases de contraseña no pueden estar vacías.</string>
+ <string name="passphrase_for_symmetric_encryption">Cifrado simétrico.</string>
+ <string name="passphrase_for">Introducir la frase de contraseña para \'%s\'</string>
+ <string name="file_delete_confirmation">¿Estás seguro de que quieres borrar\n%s?</string>
+ <string name="file_delete_successful">Borrado satisfactoriamente.</string>
+ <string name="no_file_selected">Selecciona un archivo antes.</string>
+ <string name="decryption_successful">Descifrado satisfactoriamente.</string>
+ <string name="encryption_successful">Cifrado satisfactoriamente.</string>
+ <string name="encryption_to_clipboard_successful">Cifrado satisfactoriamente al portapapeles.</string>
+ <string name="enter_passphrase_twice">Introduce la frase de contraseña dos veces.</string>
+ <string name="select_encryption_key">Selecciona al menos una clave de cifrado.</string>
+ <string name="select_encryption_or_signature_key">Selecciona al menos una clave de cifrado o de firma.</string>
+ <string name="specify_file_to_encrypt_to">Por favor, especifica hacia qué archivo quieres cifrar.\nADVERTENCIA: El archivo se sobreescribirá si ya existiese.</string>
+ <string name="specify_file_to_decrypt_to">Por favor, especifica hacia qué archivo quieres descifrar.\nADVERTENCIA: El archivo se sobreescribirá si ya existiese.</string>
+ <string name="specify_file_to_export_to">Por favor, especifica hacia qué archivo quieres exportar.\nADVERTENCIA: El archivo se sobreescribirá si ya existiese.</string>
+ <string name="specify_file_to_export_secret_keys_to">Por favor, especifica hacia qué archivo quieres exportar.\nADVERTENCIA: Estás a punto de exportar claves SECRETAS.\nADVERTENCIA: El archivo se sobreescribirá si ya existiese.</string>
+ <string name="key_deletion_confirmation">¿Quieres realmente borrar la clave \'%s\'?\n¡No podrás deshacerlo!</string>
+ <string name="key_deletion_confirmation_multi">¿Quieres realmente borrar todas las claves seleccionadas?\n¡No podrás deshacerlo!</string>
+ <string name="secret_key_deletion_confirmation">¿Quieres realmente borrar la clave SECRETA \'%s\'?\n¡No podrás deshacerlo!</string>
+ <plurals name="keys_added_and_updated_1">
+ <item quantity="one">%d clave añadida satisfactoriamente</item>
+ <item quantity="other">%d claves añadidas satisfactoriamente</item>
+ </plurals>
+ <plurals name="keys_added_and_updated_2">
+ <item quantity="one">y actualizada %d clave.</item>
+ <item quantity="other">y actualizadas %d claves.</item>
+ </plurals>
+ <plurals name="keys_added">
+ <item quantity="one">%d clave añadida satisfactoriamente.</item>
+ <item quantity="other">%d claves añadidas satisfactoriamente.</item>
+ </plurals>
+ <plurals name="keys_updated">
+ <item quantity="one">%d clave actualizada satisfactoriamente.</item>
+ <item quantity="other">%d claves actualizadas satisfactoriamente.</item>
+ </plurals>
+ <string name="no_keys_added_or_updated">No se han añadido o actualizado claves.</string>
+ <string name="key_exported">Se ha exportado 1 clave satisfactoriamente.</string>
+ <string name="keys_exported">%d claves exportadas satisfactoriamente.</string>
+ <string name="no_keys_exported">No se han exportado claves.</string>
+ <string name="key_creation_el_gamal_info">Nota: solo las subclaves son compatibles con ElGamal, y para ElGamal debe usarse el tamaño de clave más próximo de 1536, 2048, 3072, 4096, o 8192.</string>
+ <string name="key_not_found">No se puede encontrar la clave %08X.</string>
+ <plurals name="keys_found">
+ <item quantity="one">Se ha encontrado %d clave.</item>
+ <item quantity="other">Se han encontrado %d claves.</item>
+ </plurals>
+ <string name="unknown_signature">Firma desconocida, pulsa el botón para buscar la clave extraviada.</string>
+ <plurals name="bad_keys_encountered">
+ <item quantity="one">%d mala clave secreta ignorada. Quizás hayas exportado con la opción\n--export-secret-subkeys\nAsegúrate de que exportas con\n--export-secret-keys\nen su lugar.</item>
+ <item quantity="other">%d malas claves secretas ignoradas. Quizás hayas exportado con la opción\n--export-secret-subkeys\nAsegúrate de que exportas con\n--export-secret-keys\nen su lugar.</item>
+ </plurals>
+ <string name="key_send_success">Clave cargada al servidor satisfactoriamente</string>
+ <string name="key_sign_success">Clave firmada satisfactoriamente</string>
+ <string name="list_empty">¡Esta lista está vacía!</string>
+ <string name="nfc_successfull">¡Clave enviada satisfactoriamente con NFC Beam!</string>
+ <string name="key_copied_to_clipboard">¡La clave ha sido copiada al portapapeles!</string>
+ <string name="key_has_already_been_signed">¡La clave ya ha sido firmada!</string>
+ <string name="select_key_to_sign">¡Por favor, selecciona la clave que se usará para firmar!</string>
+ <string name="key_too_big_for_sharing">¡La clave es demasiado grande para ser compartida de esta forma!</string>
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <string name="error_file_delete_failed">ha fallado el borrado de \'%s\'</string>
+ <string name="error_file_not_found">archivo no encontrado</string>
+ <string name="error_no_secret_key_found">no se ha encontrado una clave secreta adecuada</string>
+ <string name="error_no_known_encryption_found">se ha encontrado un tipo de cifrado no conocido</string>
+ <string name="error_external_storage_not_ready">el almacenamiento externo no está preparado</string>
+ <string name="error_invalid_email">email incorrecto \'%s\'</string>
+ <string name="error_key_size_minimum512bit">el tamaño de clave debe ser de al menos 512bit</string>
+ <string name="error_master_key_must_not_be_el_gamal">la clave maestra no puede ser una clave ElGamal</string>
+ <string name="error_unknown_algorithm_choice">elegido algoritmo desconocido</string>
+ <string name="error_user_id_needs_a_name">necesitas determinar un nombre</string>
+ <string name="error_user_id_needs_an_email_address">tienes que determinar una dirección de email</string>
+ <string name="error_key_needs_a_user_id">necesitas al menos una ID de usuario</string>
+ <string name="error_main_user_id_must_not_be_empty">la ID del usuario principal no puede estar vacía</string>
+ <string name="error_key_needs_master_key">necesitas al menos una clave maestra</string>
+ <string name="error_no_encryption_keys_or_passphrase">no has proporcionado ninguna clave de cifrado o frase de contraseña</string>
+ <string name="error_signature_failed">la firma ha fallado</string>
+ <string name="error_no_signature_passphrase">no has proporcionado una frase de contraseña</string>
+ <string name="error_no_signature_key">no has proporcionado una clave de firma</string>
+ <string name="error_invalid_data">cifrado de datos no válido</string>
+ <string name="error_corrupt_data">datos corrompidos</string>
+ <string name="error_integrity_check_failed">¡ha fallado la comprobación de integridad! ¡Los datos han sido modificados!</string>
+ <string name="error_no_symmetric_encryption_packet">no se ha podido encontrar un paquete con cifrado simétrico</string>
+ <string name="error_wrong_passphrase">frase de contraseña incorrecta</string>
+ <string name="error_saving_keys">error al guardar algunas claves</string>
+ <string name="error_could_not_extract_private_key">no se puede extraer la clave privada</string>
+ <string name="error_only_files_are_supported">Dirigir datos binarios sin un archivo real en el sistema de archivos es incompatible. Esto solo es compatible con ACTION_ENCRYPT_STREAM_AND_RETURN.</string>
+ <string name="error_jelly_bean_needed">!Necesitas Android 4.1 alias Jelly Bean para poder usar la característica NFC Beam!</string>
+ <string name="error_nfc_needed">¡NFC no está disponible en tu dispositivo!</string>
+ <string name="error_nothing_import">¡Nada que importar!</string>
+ <string name="error_expiry_must_come_after_creation">la fecha de caducidad debe ser posterior a la fecha de creación</string>
+ <string name="error_can_not_delete_contact">no puedes eliminar este contacto porque eres tú mismo.</string>
+ <string name="error_can_not_delete_contacts">no puedes eliminar los siguientes contactos porque son tú mismo:\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Por favor, bórralo desde la pantalla \'Mis claves\'!</item>
+ <item quantity="other">Por favor, bórralos desde la pantalla \'Mis claves\'!</item>
+ </plurals>
+ <!--progress dialogs, usually ending in '…'-->
+ <string name="progress_done">hecho.</string>
+ <string name="progress_saving">guardando...</string>
+ <string name="progress_importing">importando...</string>
+ <string name="progress_exporting">exportando...</string>
+ <string name="progress_generating">generando la clave, esto puede tardar más de 3 minutos...</string>
+ <string name="progress_building_key">construyendo la clave...</string>
+ <string name="progress_preparing_master_key">preparando la clave maestra...</string>
+ <string name="progress_certifying_master_key">certificando la clave maestra...</string>
+ <string name="progress_building_master_key">construyendo el anillo maestro...</string>
+ <string name="progress_adding_sub_keys">añadiendo las subclaves...</string>
+ <string name="progress_saving_key_ring">guardando claves...</string>
+ <plurals name="progress_exporting_key">
+ <item quantity="one">exportando clave...</item>
+ <item quantity="other">exportando claves...</item>
+ </plurals>
+ <string name="progress_extracting_signature_key">extrayendo la clave de firma...</string>
+ <string name="progress_extracting_key">extrayendo la clave...</string>
+ <string name="progress_preparing_streams">preparando las transmisiones...</string>
+ <string name="progress_encrypting">cifrando los datos...</string>
+ <string name="progress_decrypting">descifrando los datos...</string>
+ <string name="progress_preparing_signature">preparando la firma...</string>
+ <string name="progress_generating_signature">generando la firma...</string>
+ <string name="progress_processing_signature">procesando la firma...</string>
+ <string name="progress_verifying_signature">verificando la firma...</string>
+ <string name="progress_signing">firmando...</string>
+ <string name="progress_reading_data">leyendo los datos...</string>
+ <string name="progress_finding_key">localizando la clave...</string>
+ <string name="progress_decompressing_data">descomprimiendo los datos...</string>
+ <string name="progress_verifying_integrity">verificando la integridad...</string>
+ <string name="progress_deleting_securely">borrando \'%s\' de forma segura…</string>
+ <string name="progress_querying">consultando...</string>
+ <!--action strings-->
+ <string name="hint_public_keys">Buscar claves públicas</string>
+ <string name="hint_secret_keys">Buscar claves secretas</string>
+ <string name="action_share_key_with">Compartir la clave con...</string>
+ <!--key bit length selections-->
+ <string name="key_size_512">512</string>
+ <string name="key_size_1024">1024</string>
+ <string name="key_size_2048">2048</string>
+ <string name="key_size_4096">4096</string>
+ <!--compression-->
+ <string name="compression_fast">rápido</string>
+ <string name="compression_very_slow">muy lento</string>
+ <!--Help-->
+ <string name="help_tab_start">Comenzar</string>
+ <string name="help_tab_nfc_beam">NFC Beam</string>
+ <string name="help_tab_changelog">Registro de cambios</string>
+ <string name="help_tab_about">A cerca de</string>
+ <string name="help_about_version">Versión:</string>
+ <!--Import-->
+ <string name="import_import">Importar las claves seleccionadas</string>
+ <string name="import_sign_and_upload">Importar, firmar y cargar las claves seleccionadas</string>
+ <string name="import_from_clipboard">Importar desde el portapapeles</string>
+ <plurals name="import_qr_code_missing">
+ <item quantity="one">El código QR con ID %s se ha extraviado</item>
+ <item quantity="other">Los códigos QR con IDs %s se han extraviado</item>
+ </plurals>
+ <string name="import_qr_code_start_with_one">Por favor, comienza con el código QR de ID 1</string>
+ <string name="import_qr_code_wrong">¡El código QR está deformado! ¡Por favor, prueba de nuevo!</string>
+ <string name="import_qr_code_finished">¡El escaneo del código QR ha finalizado!</string>
+ <string name="import_qr_code_too_short_fingerprint">La huella digital contenida en este código QR es demasiado corta (&lt; 16 caracteres)</string>
+ <string name="import_qr_scan_button">Escanea el código QR con \'Barcode Scanner\'</string>
+ <string name="import_nfc_text">Para recibir las claves a través de NFC, el dispositivo tiene que estar desbloqueado.</string>
+ <string name="import_nfc_help_button">Ayuda</string>
+ <string name="import_clipboard_button">Tomar la clave desde el portapapeles</string>
+ <!--Intent labels-->
+ <string name="intent_decrypt_file">OpenPGP: Descifrar archivo</string>
+ <string name="intent_import_key">OpenPGP: Importar clave</string>
+ <string name="intent_send_encrypt">OpenPGP: Cifrar</string>
+ <string name="intent_send_decrypt">OpenPGP: Descifrar</string>
+ <!--Remote API-->
+ <string name="api_no_apps">¡No hay aplicaciones registradas¡\n\nLas aplicaciones de terceros pueden pedir acceso a OpenPGP Keychain. Después de recibir permiso, se mostrarán aquí.</string>
+ <string name="api_settings_show_advanced">Mostrar la configuración avanzada</string>
+ <string name="api_settings_hide_advanced">Ocultar la configuración avanzada</string>
+ <string name="api_settings_no_key">No se ha seleccionado ninguna clave</string>
+ <string name="api_settings_select_key">Seleccionar clave</string>
+ <string name="api_settings_save">Guardar</string>
+ <string name="api_settings_cancel">Cancelar</string>
+ <string name="api_settings_revoke">Revocar acceso</string>
+ <string name="api_settings_package_name">Nombre de paquete</string>
+ <string name="api_settings_package_signature">SHA-256 de firma de paquete</string>
+ <string name="api_register_text">La aplicación mostrada pide acceso a OpenPGP Keychain.\n¿Permitir acceso?\n\nAVISO: Si no sabes por qué ha aparecido esta pantalla, ¡deniega el acceso! Puedes revocar el acceso más tarde usando la ventana \'Aplicaciones Registradas\'.</string>
+ <string name="api_register_allow">Permitir el acceso</string>
+ <string name="api_register_disallow">Denegar el acceso</string>
+ <string name="api_register_error_select_key">¡Por favor, selecciona una clave!</string>
+ <string name="api_select_pub_keys_missing_text">No se han encontrado claves públicas para estas IDs de usuario:</string>
+ <string name="api_select_pub_keys_dublicates_text">Existe más de una clave pública para estos IDs de usuario:</string>
+ <string name="api_select_pub_keys_text">¡Por favor, revisa la lista de destinatarios!</string>
+ <string name="api_error_wrong_signature">¡La comprobación de la firma ha fallado! ¿Has instalado esta app desde una fuente distinta? Si estás seguro de que esto no es un ataque, revoca el registro de esta app en OpenPGP Keychain y regístrala de nuevo.</string>
+ <!--Share-->
+ <string name="share_qr_code_dialog_title">Compartir con código QR</string>
+ <string name="share_qr_code_dialog_start">Pasa por todos los códigos QR usando \'Siguiente\', y escanéalos de uno en uno.</string>
+ <string name="share_qr_code_dialog_fingerprint_text">Huella digital:</string>
+ <string name="share_qr_code_dialog_progress">Código QR con ID %1$d de %2$d</string>
+ <string name="share_nfc_dialog">Compartir con NFC</string>
+ <!--Key list-->
+ <plurals name="key_list_selected_keys">
+ <item quantity="one">1 clave seleccionada.</item>
+ <item quantity="other">%d claves seleccionadas.</item>
+ </plurals>
+ <string name="key_list_empty_text1">Aún no hay claves disponibles...</string>
+ <string name="key_list_empty_text2">Puedes empezar por</string>
+ <string name="key_list_empty_text3">o</string>
+ <string name="key_list_empty_button_create">crear tu propia clave</string>
+ <string name="key_list_empty_button_import">importar claves</string>
+ <!--Key view-->
+ <string name="key_view_action_encrypt">Cifrar hacia este contacto</string>
+ <string name="key_view_action_certify">Certificar la clave de este contacto</string>
+ <string name="key_view_tab_main">Información</string>
+ <string name="key_view_tab_certs">Certificaciones</string>
+ <!--Navigation Drawer-->
+ <string name="nav_contacts">Contactos</string>
+ <string name="nav_encrypt">Cifrar</string>
+ <string name="nav_decrypt">Descifrar</string>
+ <string name="nav_import">Importar claves</string>
+ <string name="nav_secret_keys">Mis claves</string>
+ <string name="nav_apps">Aplicaciones registradas</string>
+ <string name="drawer_open">Abrir el Navigation Drawer</string>
+ <string name="drawer_close">Cerrar el Navigation Drawer</string>
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
index d427403dd..016090d61 100644
--- a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
@@ -12,7 +12,7 @@
<string name="title_edit_key">Modifier une clef</string>
<string name="title_preferences">Préférences</string>
<string name="title_api_registered_apps">Applications enregistrées</string>
- <string name="title_key_server_preference">Serveurs de clefs préférés</string>
+ <string name="title_key_server_preference">Préférences du serveur de clefs</string>
<string name="title_change_pass_phrase">Changer la phrase de passe</string>
<string name="title_set_passphrase">Définir la phrase de passe</string>
<string name="title_send_email">Envoyer un courriel...</string>
@@ -25,7 +25,7 @@
<string name="title_key_server_query">Interroger le serveur de clefs</string>
<string name="title_send_key">Téléverser vers le serveur de clefs</string>
<string name="title_unknown_signature_key">Clef de signature inconnue</string>
- <string name="title_sign_key">Signer la clef</string>
+ <string name="title_certify_key">Certifier la clef</string>
<string name="title_key_details">Détails sur la clef</string>
<string name="title_help">Aide</string>
<!--section-->
@@ -37,17 +37,16 @@
<string name="section_master_key">Clef maîtresse</string>
<string name="section_master_user_id">ID utilisateur maître</string>
<string name="section_actions">Actions</string>
- <string name="section_signing_key">Votre clef utilisée pour la signature</string>
+ <string name="section_certification_key">Votre clef utilisée pour la certification</string>
<string name="section_upload_key">Téléverser la clef</string>
<string name="section_key_server">Serveur de clefs</string>
+ <string name="section_encrypt_and_or_sign">Chiffrer et/ou signer</string>
+ <string name="section_decrypt_verify">Déchiffrer et vérifier</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Signer (presse-papiers)</string>
- <string name="btn_encrypt_to_clipboard">Chiffrer vers le presse-papiers</string>
- <string name="btn_encrypt_and_send">Chiffrer et envoyer...</string>
- <string name="btn_sign_and_send">Signer et envoyer...</string>
<string name="btn_sign">Signer</string>
+ <string name="btn_certify">Certifier</string>
<string name="btn_decrypt">Déchiffrer</string>
- <string name="btn_verify">Vérifier</string>
+ <string name="btn_decrypt_verify">Déchiffrer et vérifier</string>
<string name="btn_select_encrypt_keys">Choisir les destinataires</string>
<string name="btn_encrypt_file">Chiffrer le fichier</string>
<string name="btn_save">Enregistrer</string>
@@ -61,6 +60,9 @@
<string name="btn_export_to_server">Téléverser vers le serveur de clefs</string>
<string name="btn_next">Suivant</string>
<string name="btn_back">Retour</string>
+ <string name="btn_clipboard">Presse-papiers</string>
+ <string name="btn_share">Partager avec...</string>
+ <string name="btn_lookup_key">Rechercher la clef</string>
<!--menu-->
<string name="menu_preferences">Paramètres</string>
<string name="menu_help">Aide</string>
@@ -109,7 +111,6 @@
<string name="label_passphrase_cache_ttl">Cache de la phrase de passe</string>
<string name="label_message_compression">Compression des messages</string>
<string name="label_file_compression">Compression des fichiers</string>
- <string name="label_force_v3_signature">Forcer les signatures V3</string>
<string name="label_key_servers">Serveurs de clefs</string>
<string name="label_key_id">ID de le clef</string>
<string name="label_creation">Création</string>
@@ -120,7 +121,7 @@
<string name="label_name">Nom</string>
<string name="label_comment">Commentaire</string>
<string name="label_email">Courriel</string>
- <string name="label_send_key">Téléverser la clef vers le serveur de clefs choisi après signature</string>
+ <string name="label_send_key">Téléverser la clef vers le serveur de clefs choisi après certification</string>
<string name="label_fingerprint">Empreinte</string>
<string name="select_keys_button_default">Choisir</string>
<plurals name="select_keys_button">
@@ -134,9 +135,10 @@
<string name="can_encrypt">peut chiffrer</string>
<string name="can_sign">peut signer</string>
<string name="expired">expiré</string>
+ <string name="revoked">révoquée</string>
<plurals name="n_key_servers">
- <item quantity="one">%d serveur de clef</item>
- <item quantity="other">%d serveurs de clef</item>
+ <item quantity="one">%d serveur de clefs</item>
+ <item quantity="other">%d serveurs de clefs</item>
</plurals>
<string name="fingerprint">Empreinte :</string>
<string name="secret_key">Clef secrète :</string>
@@ -215,13 +217,12 @@
<item quantity="one">%d clef trouvée.</item>
<item quantity="other">%d clefs trouvées.</item>
</plurals>
- <string name="unknown_signature_key_touch_to_look_up">Signature inconnue. Toucher pour rechercher la clef.</string>
+ <string name="unknown_signature">Signature inconnue. Cliquer sur le bouton pour rechercher la clef manquante.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d mauvaise clef ignorée. Vous avez peut-être exporté avec l\'option\n --export-secret-subkeys\nAssurez-vous d\'exporter plutôt avec\n --export-secret-keys.</item>
<item quantity="other">%d mauvaises clefs ignorées. Vous avez peut-être exporté avec l\'option\n --export-secret-subkeys\nAssurez-vous d\'exporter plutôt avec\n --export-secret-keys.</item>
</plurals>
- <string name="lookup_unknown_key">Clef %s inconnue, voulez-vous essayer de la trouver sur un serveur de clefs ?</string>
- <string name="key_send_success">Clef envoyée vers le serveur avec succès</string>
+ <string name="key_send_success">Clef téléversée vers le serveur avec succès</string>
<string name="key_sign_success">Clef signée avec succès</string>
<string name="list_empty">Cette liste est vide !</string>
<string name="nfc_successfull">Clef envoyée par NFC BEAM avec succès !</string>
@@ -234,7 +235,7 @@
they will be put after "error_message", e.g. "Error: file not found"-->
<string name="error_file_delete_failed">échec lors de la suppression de « %s »</string>
<string name="error_file_not_found">fichier introuvable</string>
- <string name="error_no_secret_key_found">aucune clé secrète adéquate n\'a été trouvée</string>
+ <string name="error_no_secret_key_found">aucune clefs secrète adéquate n\'a été trouvée</string>
<string name="error_no_known_encryption_found">aucune sorte de chiffrement connu n\'a été trouvé</string>
<string name="error_external_storage_not_ready">le stockage externe n\'est pas prêt</string>
<string name="error_invalid_email">courriel « %s » invalide</string>
@@ -261,19 +262,24 @@
<string name="error_nfc_needed">NFC n\'est pas disponible sur votre appareil !</string>
<string name="error_nothing_import">Rien à importer !</string>
<string name="error_expiry_must_come_after_creation">la date d\'expiration doit venir après la date de création</string>
+ <string name="error_can_not_delete_contact">vous ne pouvez pas supprimer ce contact car c\'est le vôtre.</string>
+ <string name="error_can_not_delete_contacts">vous ne pouvez pas supprimer les contacts suivants car c\'est les vôtres.\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Veuillez le supprimer depuis l\'écran « Mes Clefs »!</item>
+ <item quantity="other">Veuillez les supprimer depuis l\'écran « Mes Clefs »!</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">fait.</string>
<string name="progress_saving">sauvegarde...</string>
<string name="progress_importing">importation...</string>
<string name="progress_exporting">exportation...</string>
- <string name="progress_generating">génération de la clef, ceci peut prendre un moment...</string>
+ <string name="progress_generating">génération de la clef, ceci peut prendre jusqu\'à 3 minutes...</string>
<string name="progress_building_key">assemblage de la clef...</string>
<string name="progress_preparing_master_key">préparation de la clef maîtresse...</string>
<string name="progress_certifying_master_key">certification de la clef maîtresse...</string>
<string name="progress_building_master_key">assemblage du trousseau maître...</string>
<string name="progress_adding_sub_keys">ajout des sous-clefs...</string>
<string name="progress_saving_key_ring">sauvegarde de la clef...</string>
- <string name="progress_importing_secret_keys">Importation des clefs secrètes...</string>
<plurals name="progress_exporting_key">
<item quantity="one">exportation de la clef...</item>
<item quantity="other">exportation des clefs...</item>
@@ -334,7 +340,7 @@
<string name="intent_send_encrypt">OpenPGP : chiffrer</string>
<string name="intent_send_decrypt">OpenPGP : déchiffrer</string>
<!--Remote API-->
- <string name="api_no_apps">Aucune application enregistrée !</string>
+ <string name="api_no_apps">Aucune application enregistrée !\n\nLes applications tierces peuvent demander l\'accès au Porte-clefs OpenPGP. Après avoir autoriser l\'accès, elles seront listées ici.</string>
<string name="api_settings_show_advanced">Afficher les paramètres avancés</string>
<string name="api_settings_hide_advanced">Masquer les paramètres avancés</string>
<string name="api_settings_no_key">Aucune clef choisie</string>
@@ -344,7 +350,7 @@
<string name="api_settings_revoke">Révoquer l\'accès</string>
<string name="api_settings_package_name">Nom du paquet</string>
<string name="api_settings_package_signature">SHA-256 de la signature du paquet</string>
- <string name="api_register_text">L\'application suivante demande l\'accès à l\'API du Porte-clefs OpenPGP.\n\nPermettre l\'accès permanent ?</string>
+ <string name="api_register_text">L\'application affichée demande l\'accès au Porte-clefs OpenPGP.\nPermettre l\'accès ?\n\nAvertissement : si vous ne savez pas pourquoi cet écran est apparu, refusé l\'accès ! Vous pourrez révoquer l\'accès plus tard en utilisant l\'écran « Applications enregistrées ».</string>
<string name="api_register_allow">Permettre l\'accès</string>
<string name="api_register_disallow">Enlever l\'accès</string>
<string name="api_register_error_select_key">Veuillez choisir une clef !</string>
@@ -370,6 +376,9 @@
<string name="key_list_empty_button_import">Importer des clefs.</string>
<!--Key view-->
<string name="key_view_action_encrypt">Chiffrer vers ce contact</string>
+ <string name="key_view_action_certify">Certifier la clef de ce contact</string>
+ <string name="key_view_tab_main">Infos</string>
+ <string name="key_view_tab_certs">Certifications</string>
<!--Navigation Drawer-->
<string name="nav_contacts">Contacts</string>
<string name="nav_encrypt">Chiffrer</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
index 44424561b..e404addfa 100644
--- a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
@@ -15,7 +15,6 @@
<string name="title_export_key">Esportare Chiave</string>
<string name="title_export_keys">Esportare Chiavi</string>
<string name="title_key_not_found">Chiave Non Trovata</string>
- <string name="title_sign_key">Firma Chiave</string>
<string name="title_help">Aiuto</string>
<!--section-->
<string name="section_user_ids">ID Utente</string>
@@ -23,10 +22,8 @@
<string name="section_general">Generale</string>
<string name="section_advanced">Avanzato</string>
<!--button-->
- <string name="btn_sign_and_send">Firmare ed inviare...</string>
<string name="btn_sign">Firmare</string>
<string name="btn_decrypt">Decifrare</string>
- <string name="btn_verify">Verificare</string>
<string name="btn_encrypt_file">Cifrare File</string>
<string name="btn_save">Salva</string>
<string name="btn_do_not_save">Cancella</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-ja/strings.xml b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml
new file mode 100644
index 000000000..15043c93a
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml
@@ -0,0 +1,381 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_manage_public_keys">連絡先</string>
+ <string name="title_manage_secret_keys">秘密鍵</string>
+ <string name="title_select_recipients">公開鍵の選択</string>
+ <string name="title_select_secret_key">秘密鍵の選択</string>
+ <string name="title_encrypt">暗号化</string>
+ <string name="title_decrypt">復号化</string>
+ <string name="title_authentication">パスフレーズ</string>
+ <string name="title_create_key">鍵の生成</string>
+ <string name="title_edit_key">鍵の編集</string>
+ <string name="title_preferences">設定</string>
+ <string name="title_api_registered_apps">登録済みのアプリケーション</string>
+ <string name="title_key_server_preference">鍵サーバ設定</string>
+ <string name="title_change_pass_phrase">パスフレーズの変更</string>
+ <string name="title_set_passphrase">パスフレーズの設定</string>
+ <string name="title_send_email">メールの送信...</string>
+ <string name="title_encrypt_to_file">暗号化してファイルに</string>
+ <string name="title_decrypt_to_file">復号化してファイルに</string>
+ <string name="title_import_keys">鍵のインポート</string>
+ <string name="title_export_key">鍵のエクスポート</string>
+ <string name="title_export_keys">複数鍵のエクスポート</string>
+ <string name="title_key_not_found">鍵が見当りません</string>
+ <string name="title_key_server_query">鍵サーバへの要求</string>
+ <string name="title_send_key">鍵サーバへアップロード</string>
+ <string name="title_unknown_signature_key">不明な署名の鍵です</string>
+ <string name="title_certify_key">鍵検証</string>
+ <string name="title_key_details">鍵の概要</string>
+ <string name="title_help">ヘルプ</string>
+ <!--section-->
+ <string name="section_user_ids">ユーザID</string>
+ <string name="section_keys">鍵</string>
+ <string name="section_general">一般</string>
+ <string name="section_defaults">デフォルト</string>
+ <string name="section_advanced">拡張</string>
+ <string name="section_master_key">主鍵</string>
+ <string name="section_master_user_id">主ユーザID</string>
+ <string name="section_actions">アクション</string>
+ <string name="section_certification_key">あなたの鍵を証明に利用します</string>
+ <string name="section_upload_key">鍵のアップロード</string>
+ <string name="section_key_server">鍵サーバ</string>
+ <string name="section_encrypt_and_or_sign">暗号化と/もしくは署名</string>
+ <string name="section_decrypt_verify">復号化と検証</string>
+ <!--button-->
+ <string name="btn_sign">署名</string>
+ <string name="btn_certify">検証</string>
+ <string name="btn_decrypt">復号化</string>
+ <string name="btn_decrypt_verify">復号化と検証</string>
+ <string name="btn_select_encrypt_keys">受信者の選択</string>
+ <string name="btn_encrypt_file">ファイル暗号化</string>
+ <string name="btn_save">保存</string>
+ <string name="btn_do_not_save">キャンセル</string>
+ <string name="btn_delete">削除</string>
+ <string name="btn_no_date">無し</string>
+ <string name="btn_okay">OK</string>
+ <string name="btn_change_passphrase">パスフレーズの変更</string>
+ <string name="btn_set_passphrase">パスフレーズの設定</string>
+ <string name="btn_search">検索</string>
+ <string name="btn_export_to_server">鍵サーバへアップロード</string>
+ <string name="btn_next">次</string>
+ <string name="btn_back">戻る</string>
+ <string name="btn_clipboard">クリップボード</string>
+ <string name="btn_share">共有...</string>
+ <string name="btn_lookup_key">鍵検出</string>
+ <!--menu-->
+ <string name="menu_preferences">設定</string>
+ <string name="menu_help">ヘルプ</string>
+ <string name="menu_import_from_file">ファイルからインポート</string>
+ <string name="menu_import_from_qr_code">QRコードからインポート</string>
+ <string name="menu_import">インポート</string>
+ <string name="menu_import_from_nfc">NFCからインポート</string>
+ <string name="menu_export_keys">すべての鍵のエクスポート</string>
+ <string name="menu_export_key">ファイルへのエクスポート</string>
+ <string name="menu_delete_key">鍵の削除</string>
+ <string name="menu_create_key">鍵の生成</string>
+ <string name="menu_create_key_expert">鍵の生成(上級)</string>
+ <string name="menu_search">検索</string>
+ <string name="menu_key_server">鍵サーバからのインポート</string>
+ <string name="menu_update_key">鍵サーバからの更新</string>
+ <string name="menu_export_key_to_server">鍵サーバへのアップロード</string>
+ <string name="menu_share">共有</string>
+ <string name="menu_share_title_fingerprint">指紋の共有...</string>
+ <string name="menu_share_title">すべての鍵の共有...</string>
+ <string name="menu_share_default_fingerprint">...(指紋)</string>
+ <string name="menu_share_default">...(鍵)</string>
+ <string name="menu_share_qr_code">QRコードで共有(鍵)</string>
+ <string name="menu_share_qr_code_fingerprint">QRコードで共有(指紋)</string>
+ <string name="menu_share_nfc">NFCで共有</string>
+ <string name="menu_copy_to_clipboard">クリップボードへコピー</string>
+ <string name="menu_sign_key">鍵を署名</string>
+ <string name="menu_beam_preferences">Beamの設定</string>
+ <string name="menu_key_edit_cancel">キャンセル</string>
+ <string name="menu_encrypt_to">暗号化...</string>
+ <!--label-->
+ <string name="label_sign">署名</string>
+ <string name="label_message">メッセージ</string>
+ <string name="label_file">ファイル</string>
+ <string name="label_no_passphrase">パスフレーズなし</string>
+ <string name="label_passphrase">パスフレーズ</string>
+ <string name="label_passphrase_again">もう一度</string>
+ <string name="label_algorithm">アルゴリズム</string>
+ <string name="label_ascii_armor">アスキー形式</string>
+ <string name="label_select_public_keys">受信者</string>
+ <string name="label_delete_after_encryption">暗号化後に削除</string>
+ <string name="label_delete_after_decryption">復号化後に削除</string>
+ <string name="label_encryption_algorithm">暗号化アルゴリズム</string>
+ <string name="label_hash_algorithm">ハッシュアルゴリズム</string>
+ <string name="label_asymmetric">公開鍵</string>
+ <string name="label_symmetric">パスフレーズ</string>
+ <string name="label_passphrase_cache_ttl">パスフレーズキャッシュ</string>
+ <string name="label_message_compression">メッセージの圧縮</string>
+ <string name="label_file_compression">ファイルの圧縮</string>
+ <string name="label_force_v3_signature">強制的に古いOpenPGPV3形式の署名にする</string>
+ <string name="label_key_servers">鍵サーバ</string>
+ <string name="label_key_id">鍵ID</string>
+ <string name="label_creation">生成</string>
+ <string name="label_expiry">満了</string>
+ <string name="label_usage">使い方</string>
+ <string name="label_key_size">鍵サイズ</string>
+ <string name="label_main_user_id">主ユーザID</string>
+ <string name="label_name">名前</string>
+ <string name="label_comment">コメント</string>
+ <string name="label_email">Eメールアドレス</string>
+ <string name="label_send_key">証明後選択した鍵サーバに鍵をアップロード</string>
+ <string name="label_fingerprint">指紋</string>
+ <string name="select_keys_button_default">選択</string>
+ <plurals name="select_keys_button">
+ <item quantity="other">%d を選択</item>
+ </plurals>
+ <string name="user_id_no_name">&lt;名前なし&gt;</string>
+ <string name="none">&lt;無し&gt;</string>
+ <string name="no_key">&lt;鍵無し&gt;</string>
+ <string name="unknown_status"></string>
+ <string name="can_encrypt">暗号化可能</string>
+ <string name="can_sign">署名可能</string>
+ <string name="expired">期限切れ</string>
+ <string name="revoked">破棄</string>
+ <plurals name="n_key_servers">
+ <item quantity="other">%d の鍵サーバ</item>
+ </plurals>
+ <string name="fingerprint">指紋:</string>
+ <string name="secret_key">秘密鍵:</string>
+ <!--choice-->
+ <string name="choice_none">無し</string>
+ <string name="choice_sign_only">署名のみ</string>
+ <string name="choice_encrypt_only">暗号化のみ</string>
+ <string name="choice_sign_and_encrypt">署名と暗号化</string>
+ <string name="choice_15secs">15秒</string>
+ <string name="choice_1min">1分</string>
+ <string name="choice_3mins">3分</string>
+ <string name="choice_5mins">5分</string>
+ <string name="choice_10mins">10分</string>
+ <string name="choice_20mins">20分</string>
+ <string name="choice_40mins">40分</string>
+ <string name="choice_1hour">1時間</string>
+ <string name="choice_2hours">2時間</string>
+ <string name="choice_4hours">4時間</string>
+ <string name="choice_8hours">8時間</string>
+ <string name="choice_forever">永遠</string>
+ <string name="dsa">DSA</string>
+ <string name="elgamal">ElGamal</string>
+ <string name="rsa">RSA</string>
+ <string name="filemanager_title_open">開く...</string>
+ <string name="warning">注意</string>
+ <string name="error">エラー</string>
+ <string name="error_message">エラー: %s</string>
+ <!--sentences-->
+ <string name="wrong_passphrase">良くないパスフレーズ</string>
+ <string name="using_clipboard_content">クリップボードの内容を使う。</string>
+ <string name="set_a_passphrase">最初にパスフレーズを設定してください。</string>
+ <string name="no_filemanager_installed">互換性のないファイルマネージャがインストールされています。</string>
+ <string name="passphrases_do_not_match">パスフレーズが一致しません。</string>
+ <string name="passphrase_must_not_be_empty">空のパスフレーズは受け付けません。</string>
+ <string name="passphrase_for_symmetric_encryption">対称暗号。</string>
+ <string name="passphrase_for">\'%s\' にパスフレーズを入れてください。</string>
+ <string name="file_delete_confirmation">%s を削除してもかまいませんか?</string>
+ <string name="file_delete_successful">削除に成功しました。</string>
+ <string name="no_file_selected">最初にファイルを選択してください。</string>
+ <string name="decryption_successful">復号化に成功しました。</string>
+ <string name="encryption_successful">暗号化に成功しました。</string>
+ <string name="encryption_to_clipboard_successful">クリップボードの中身の暗号化に成功しました。</string>
+ <string name="enter_passphrase_twice">もう一度パスフレーズを入れてください。</string>
+ <string name="select_encryption_key">少なくとも1つの暗号化鍵を選択して下さい。</string>
+ <string name="select_encryption_or_signature_key">少なくとも1つの暗号化鍵か署名鍵を選択して下さい。</string>
+ <string name="specify_file_to_encrypt_to">どのファイルを暗号化するか決めてください。\n注意: 既存のファイルがあると上書きされます。</string>
+ <string name="specify_file_to_decrypt_to">どのファイルを復号化するか決めてください。\n注意: 既存のファイルがあると上書きされます。</string>
+ <string name="specify_file_to_export_to">どのファイルをエクスポートするか決めてください。\n注意: 既存のファイルがあると上書きされます。</string>
+ <string name="specify_file_to_export_secret_keys_to">どのファイルをエクスポートするか決めてください。\n注意: 秘密鍵をエクスポートしています。\n注意: 既存のファイルがあると上書きされます。</string>
+ <string name="key_deletion_confirmation">鍵\'%s\'を本当に削除してもよいですか?\nこれは元に戻せません!</string>
+ <string name="key_deletion_confirmation_multi">選択したすべての鍵を本当に削除してよいですか?\nこれは元に戻せません。</string>
+ <string name="secret_key_deletion_confirmation">秘密鍵\'%s\'を本当に削除してもよいですか?\nこれは元に戻せません!</string>
+ <plurals name="keys_added_and_updated_1">
+ <item quantity="other">%d の鍵を追加しました</item>
+ </plurals>
+ <plurals name="keys_added_and_updated_2">
+ <item quantity="other">そして %d の鍵をアップロードしました。</item>
+ </plurals>
+ <plurals name="keys_added">
+ <item quantity="other">%d の鍵を追加しました。</item>
+ </plurals>
+ <plurals name="keys_updated">
+ <item quantity="other">%d の鍵をアップロードしました。</item>
+ </plurals>
+ <string name="no_keys_added_or_updated">鍵の追加もしくは更新はありませんでした。</string>
+ <string name="key_exported">1つの鍵をエクスポートしました。</string>
+ <string name="keys_exported">%d の鍵をエクスポートしました。</string>
+ <string name="no_keys_exported">鍵をエクスポートしていません。</string>
+ <string name="key_creation_el_gamal_info">備考: 副鍵として ElGamalだけがサポートされ, ElGamal は鍵サイズとして1536, 2048, 3072, 4096, 8192 だけが使えます。</string>
+ <string name="key_not_found">鍵 %08X は見付かりませんでした。</string>
+ <plurals name="keys_found">
+ <item quantity="other">%d の鍵を発見。</item>
+ </plurals>
+ <string name="unknown_signature">不明な署名、ボタンを押して見付からない鍵を検出してください。</string>
+ <plurals name="bad_keys_encountered">
+ <item quantity="other">%d の問題ある鍵を無視しました。 おそらく次のオプションでエクスポートしています\n --export-secret-subkeys\n代りに次のオプションでエクスポートしてください。\n --export-secret-keys</item>
+ </plurals>
+ <string name="key_send_success">鍵を鍵サーバにアップロードしました</string>
+ <string name="key_sign_success">鍵に署名しました。</string>
+ <string name="list_empty">このリストは空です!</string>
+ <string name="nfc_successfull">NFCビームで鍵を送信しました!</string>
+ <string name="key_copied_to_clipboard">鍵はクリプボードにコピーされました!</string>
+ <string name="key_has_already_been_signed">鍵はすでに署名されています!</string>
+ <string name="select_key_to_sign">署名に使う鍵を選択して下さい!</string>
+ <string name="key_too_big_for_sharing">この共有方法では鍵が大きすぎます!</string>
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <string name="error_file_delete_failed">\'%s\' の削除に失敗</string>
+ <string name="error_file_not_found">ファイルが見付かりません</string>
+ <string name="error_no_secret_key_found">組になっている秘密鍵が見付かりません</string>
+ <string name="error_no_known_encryption_found">暗号化法が既知の種類内から見付かりません</string>
+ <string name="error_external_storage_not_ready">外部ストレージが準備できていません</string>
+ <string name="error_invalid_email">\'%s\' は不正なEメールアドレスです</string>
+ <string name="error_key_size_minimum512bit">鍵サイズは最低でも512bit必要です</string>
+ <string name="error_master_key_must_not_be_el_gamal">主鍵を ElGamal にすることはできません</string>
+ <string name="error_unknown_algorithm_choice">未知のアルゴリズムを選択しています</string>
+ <string name="error_user_id_needs_a_name">名前を特定する必要があります</string>
+ <string name="error_user_id_needs_an_email_address">Eメールアドレスを特定する必要があります</string>
+ <string name="error_key_needs_a_user_id">最低でも1つのユーザIDが必要です</string>
+ <string name="error_main_user_id_must_not_be_empty">主ユーザIDは空にすることはできません</string>
+ <string name="error_key_needs_master_key">主鍵が最低でも1つ必要です</string>
+ <string name="error_no_encryption_keys_or_passphrase">鍵が暗号化されていないかパスフレーズが与えられていません</string>
+ <string name="error_signature_failed">署名に失敗</string>
+ <string name="error_no_signature_passphrase">パスフレーズが与えられていません</string>
+ <string name="error_no_signature_key">署名鍵を与えられていません</string>
+ <string name="error_invalid_data">暗号化データが不正です</string>
+ <string name="error_corrupt_data">壊れたデータ</string>
+ <string name="error_integrity_check_failed">完全性チェックが失敗しました! データに変更があります!</string>
+ <string name="error_no_symmetric_encryption_packet">対称鍵暗号のパケットが見付かりませんでした</string>
+ <string name="error_wrong_passphrase">正しくないパスフレーズです</string>
+ <string name="error_saving_keys">鍵の保存エラー</string>
+ <string name="error_could_not_extract_private_key">秘密鍵を取り出すことができません</string>
+ <string name="error_only_files_are_supported">ファイルシステムに存在するファイルではないバイナリデータはサポートされません。 ACTION_ENCRYPT_STREAM_AND_RETURN でのみサポートされます。</string>
+ <string name="error_jelly_bean_needed">Android NFC Beam機能を使うにはAndroid 4.1 (Jelly Bean) が必要です!</string>
+ <string name="error_nfc_needed">あなたのデバイスにはNFCが存在しません!</string>
+ <string name="error_nothing_import">インポートするものがありません!</string>
+ <string name="error_expiry_must_come_after_creation">期限日時は生成日時より後である必要があります</string>
+ <string name="error_can_not_delete_contact">この連絡先はあなたなので削除できません。</string>
+ <string name="error_can_not_delete_contacts">この連絡先はあなたなので削除できません。:\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="other">\'自分の鍵\'画面から削除してください!</item>
+ </plurals>
+ <!--progress dialogs, usually ending in '…'-->
+ <string name="progress_done">完了。</string>
+ <string name="progress_saving">保存...</string>
+ <string name="progress_importing">インポート...</string>
+ <string name="progress_exporting">エクスポート...</string>
+ <string name="progress_generating">鍵の生成、3分ほどかかります...</string>
+ <string name="progress_building_key">鍵の構築中...</string>
+ <string name="progress_preparing_master_key">主鍵の準備中...</string>
+ <string name="progress_certifying_master_key">主鍵の検証中...</string>
+ <string name="progress_building_master_key">主鍵輪の構築中...</string>
+ <string name="progress_adding_sub_keys">副鍵の追加中...</string>
+ <string name="progress_saving_key_ring">鍵の保存...</string>
+ <plurals name="progress_exporting_key">
+ <item quantity="other">鍵のエクスポート...</item>
+ </plurals>
+ <string name="progress_extracting_signature_key">署名鍵の取り出し中...</string>
+ <string name="progress_extracting_key">鍵の取り出し中...</string>
+ <string name="progress_preparing_streams">ストリームの準備中...</string>
+ <string name="progress_encrypting">データの暗号化中...</string>
+ <string name="progress_decrypting">データの復号化中...</string>
+ <string name="progress_preparing_signature">署名の準備中...</string>
+ <string name="progress_generating_signature">署名の生成中...</string>
+ <string name="progress_processing_signature">署名処理中...</string>
+ <string name="progress_verifying_signature">署名の検証中...</string>
+ <string name="progress_signing">署名中...</string>
+ <string name="progress_reading_data">データ読み込み中...</string>
+ <string name="progress_finding_key">鍵検索中...</string>
+ <string name="progress_decompressing_data">データの展開中...</string>
+ <string name="progress_verifying_integrity">完全性の検証中...</string>
+ <string name="progress_deleting_securely">\'%s\' を完全に削除中…</string>
+ <string name="progress_querying">要求中...</string>
+ <!--action strings-->
+ <string name="hint_public_keys">公開鍵の検索</string>
+ <string name="hint_secret_keys">秘密鍵の検索</string>
+ <string name="action_share_key_with">鍵の共有...</string>
+ <!--key bit length selections-->
+ <string name="key_size_512">512</string>
+ <string name="key_size_1024">1024</string>
+ <string name="key_size_2048">2048</string>
+ <string name="key_size_4096">4096</string>
+ <!--compression-->
+ <string name="compression_fast">早い</string>
+ <string name="compression_very_slow">とても遅い</string>
+ <!--Help-->
+ <string name="help_tab_start">開始</string>
+ <string name="help_tab_nfc_beam">NFC Beam</string>
+ <string name="help_tab_changelog">Changelog</string>
+ <string name="help_tab_about">これについて</string>
+ <string name="help_about_version">バージョン:</string>
+ <!--Import-->
+ <string name="import_import">選択した鍵のインポート</string>
+ <string name="import_sign_and_upload">選択した鍵のインポート、署名、そしてアップロード</string>
+ <string name="import_from_clipboard">クリップボードからインポート</string>
+ <plurals name="import_qr_code_missing">
+ <item quantity="other">ID %s のQRコードがありません</item>
+ </plurals>
+ <string name="import_qr_code_start_with_one">QRコードをID 1で始めてください</string>
+ <string name="import_qr_code_wrong">不適QRコード! もう一度!</string>
+ <string name="import_qr_code_finished">QRコードの読み取り完了!</string>
+ <string name="import_qr_code_too_short_fingerprint">QRコードに含まれる指紋が短かすぎます (&lt; 16 文字)</string>
+ <string name="import_qr_scan_button">\'バーコードスキャナー\'でQRコードをスキャンする</string>
+ <string name="import_nfc_text">NFCで鍵を受信しました、デバイスのロックを解除する必要があります。</string>
+ <string name="import_nfc_help_button">ヘルプ</string>
+ <string name="import_clipboard_button">クリップボードから鍵を取得</string>
+ <!--Intent labels-->
+ <string name="intent_decrypt_file">OpenPGP: ファイル復号</string>
+ <string name="intent_import_key">OpenPGP: 鍵のインポート</string>
+ <string name="intent_send_encrypt">OpenPGP: 暗号化</string>
+ <string name="intent_send_decrypt">OpenPGP: 復号化</string>
+ <!--Remote API-->
+ <string name="api_no_apps">登録されていないアプリケーション!\n\nサードパーティアプリケーションはOpenPGP Keychainにアクセスを要求できます。アクセスを与えた後、それらはここにリストされます。</string>
+ <string name="api_settings_show_advanced">拡張設定を表示</string>
+ <string name="api_settings_hide_advanced">拡張設定を非表示</string>
+ <string name="api_settings_no_key">鍵が選択されていない</string>
+ <string name="api_settings_select_key">鍵の選択</string>
+ <string name="api_settings_save">保存</string>
+ <string name="api_settings_cancel">キャンセル</string>
+ <string name="api_settings_revoke">破棄されたアクセス</string>
+ <string name="api_settings_package_name">パッケージ名</string>
+ <string name="api_settings_package_signature">パッケージの署名 SHA-256</string>
+ <string name="api_register_text">表示されているアプリケーションはOpenPGP Keychainへのアクセスを要求しています。\nアクセスを許可しますか?\n\n注意: もしなぜスクリーンに表れたかわからないなら、アクセスを許可しないでください! あなたは\'登録済みアプリケーション\'スクリーンを使って、以降のアクセスを破棄するこもできます。</string>
+ <string name="api_register_allow">許可されたアクセス</string>
+ <string name="api_register_disallow">許可されないアクセス</string>
+ <string name="api_register_error_select_key">鍵を選択してください!</string>
+ <string name="api_select_pub_keys_missing_text">このユーザIDについて公開鍵が見付かりません:</string>
+ <string name="api_select_pub_keys_dublicates_text">このユーザIDについて1つ以上の公開鍵が存在します:</string>
+ <string name="api_select_pub_keys_text">受信者リストを確認してください!</string>
+ <string name="api_error_wrong_signature">署名チェックが失敗! 違うところからこのアプリをインストールしましたか? もし攻撃されてでなくそうであるなら、OpenPGP Keychainにあるこのアプリの登録を破棄し、再度アプリを登録してください。</string>
+ <!--Share-->
+ <string name="share_qr_code_dialog_title">QRコードで共有</string>
+ <string name="share_qr_code_dialog_start">すべてのQRコードを見る場合、\'次\' を押して一つ一つスキャンしてください。</string>
+ <string name="share_qr_code_dialog_fingerprint_text">指紋:</string>
+ <string name="share_qr_code_dialog_progress">%2$d の ID %1$d のQRコード</string>
+ <string name="share_nfc_dialog">NFCで共有</string>
+ <!--Key list-->
+ <plurals name="key_list_selected_keys">
+ <item quantity="other">%d の鍵を選択。</item>
+ </plurals>
+ <string name="key_list_empty_text1">すでにその鍵は存在しません...</string>
+ <string name="key_list_empty_text2">で始める</string>
+ <string name="key_list_empty_text3">もしくは</string>
+ <string name="key_list_empty_button_create">あなた所有の鍵を作る</string>
+ <string name="key_list_empty_button_import">鍵のインポート。</string>
+ <!--Key view-->
+ <string name="key_view_action_encrypt">この連絡先を暗号化</string>
+ <string name="key_view_action_certify">この連絡先の鍵を検証</string>
+ <string name="key_view_tab_main">情報</string>
+ <string name="key_view_tab_certs">証明</string>
+ <!--Navigation Drawer-->
+ <string name="nav_contacts">連絡先</string>
+ <string name="nav_encrypt">暗号化</string>
+ <string name="nav_decrypt">復号化</string>
+ <string name="nav_import">鍵のインポート</string>
+ <string name="nav_secret_keys">自分の鍵</string>
+ <string name="nav_apps">登録済みのアプリ</string>
+ <string name="drawer_open">ナビゲーションドロワーを開く</string>
+ <string name="drawer_close">ナビゲーションドロワーを閉める</string>
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
index b0d792708..72a8fdea8 100644
--- a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
@@ -10,7 +10,6 @@
<string name="title_edit_key">Sleutel bewerken</string>
<string name="title_preferences">Instellingen</string>
<string name="title_api_registered_apps">Geregistreerde apps</string>
- <string name="title_key_server_preference">Instellingen sleutelserver</string>
<string name="title_change_pass_phrase">Wachtwoord wijzigen</string>
<string name="title_set_passphrase">Wachtwoord instellen</string>
<string name="title_send_email">E-mail verzenden...</string>
@@ -20,9 +19,7 @@
<string name="title_export_key">Sleutels exporteren</string>
<string name="title_export_keys">Sleutels exporteren</string>
<string name="title_key_not_found">Sleutel niet gevonden</string>
- <string name="title_key_server_query">Sleutelserver verzoek zenden</string>
<string name="title_unknown_signature_key">Onbekende handtekeningssleutel</string>
- <string name="title_sign_key">Sleutel ondertekenen</string>
<string name="title_help">Help</string>
<!--section-->
<string name="section_user_ids">Gebruikers-id\'s</string>
@@ -31,13 +28,8 @@
<string name="section_defaults">Standaard</string>
<string name="section_advanced">Geavanceerd</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Ondertekenen (klembord)</string>
- <string name="btn_encrypt_to_clipboard">Versleutelen naar klembord</string>
- <string name="btn_encrypt_and_send">Versleutelen en verzenden...</string>
- <string name="btn_sign_and_send">Ondertekenen en verzenden...</string>
<string name="btn_sign">Ondertekenen</string>
<string name="btn_decrypt">Ontsleutelen</string>
- <string name="btn_verify">Verifiëren</string>
<string name="btn_select_encrypt_keys">Ontvangers selecteren</string>
<string name="btn_encrypt_file">Bestand versleutelen</string>
<string name="btn_save">Opslaan</string>
@@ -61,7 +53,6 @@
<string name="menu_create_key">Sleutel aanmaken</string>
<string name="menu_create_key_expert">Sleutel aanmaken (expert)</string>
<string name="menu_search">Zoeken</string>
- <string name="menu_key_server">Importeren uit sleutelserver</string>
<string name="menu_sign_key">Sleutel ondertekenen</string>
<string name="menu_beam_preferences">Beam-instellingen</string>
<!--label-->
@@ -82,8 +73,6 @@
<string name="label_passphrase_cache_ttl">Wachtwoordcache</string>
<string name="label_message_compression">Berichtcompressie</string>
<string name="label_file_compression">Bestandscompressie</string>
- <string name="label_force_v3_signature">V3-handtekeningen afdwingen</string>
- <string name="label_key_servers">Sleutelservers</string>
<string name="label_key_id">Sleutel-id</string>
<string name="label_creation">Aanmaak</string>
<string name="label_expiry">Verlopen</string>
@@ -149,9 +138,6 @@
<string name="no_keys_exported">Geen sleutels geëxporteerd.</string>
<string name="key_creation_el_gamal_info">Opmerking: alleen sub-sleutels ondersteunen ElGamal, en voor ElGamal wordt de dichtstbijzijnde sleutelgrootte van 1536, 2048, 4096 of 8192 gebruikt.</string>
<string name="key_not_found">Kan de sleutel %08X niet vinden.</string>
- <string name="unknown_signature_key_touch_to_look_up">Onbekende handtekening, tik om sleutel op te zoeken.</string>
- <string name="lookup_unknown_key">Onbekende sleutel %s, wilt u het bij een sleutelserver opvragen?</string>
- <string name="key_send_success">Sleutel succesvol verzonden naar server</string>
<string name="key_sign_success">Sleutel succesvol ondertekend</string>
<string name="list_empty">Lijst is leeg</string>
<string name="nfc_successfull">Sleutel succesvol verzonden met Beam</string>
@@ -189,13 +175,11 @@
<string name="progress_saving">opslaan...</string>
<string name="progress_importing">importeren...</string>
<string name="progress_exporting">exporteren...</string>
- <string name="progress_generating">sleutel genereren, een ogenblik geduld...</string>
<string name="progress_building_key">sleutel maken...</string>
<string name="progress_preparing_master_key">hoofdsleutel voorbereiden...</string>
<string name="progress_certifying_master_key">hoofdsleutel certificeren...</string>
<string name="progress_building_master_key">hoofdsleutelbos maken...</string>
<string name="progress_adding_sub_keys">sub-sleutels toevoegen...</string>
- <string name="progress_importing_secret_keys">privésleutels importeren...</string>
<string name="progress_extracting_signature_key">ondertekeningssleutel uitpakken...</string>
<string name="progress_extracting_key">sleutel uitpakken...</string>
<string name="progress_preparing_streams">streams voorbereiden...</string>
@@ -241,13 +225,11 @@
<string name="intent_send_encrypt">OpenPGP: versleutelen</string>
<string name="intent_send_decrypt">OpenPGP: ontsleutelen</string>
<!--Remote API-->
- <string name="api_no_apps">Geen geregistreerde apps</string>
<string name="api_settings_no_key">Geen sleutel geselecteerd</string>
<string name="api_settings_select_key">Sleutel selecteren</string>
<string name="api_settings_save">Opslaan</string>
<string name="api_settings_cancel">Annuleren</string>
<string name="api_settings_revoke">Toegang herroepen</string>
- <string name="api_register_text">De volgende app vraagt toegang to de KeyChain-API van OpenPGP\n\nAltijd toestaan?</string>
<string name="api_register_allow">Toegang toestaan</string>
<string name="api_register_disallow">Toegang weigeren</string>
<string name="api_register_error_select_key">Selecteert u a.u.b. een sleutel</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
index 91ec2d1af..cbc394766 100644
--- a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
@@ -25,7 +25,7 @@
<string name="title_key_server_query">Запросить сервер ключей</string>
<string name="title_send_key">Загрузить на сервер ключей</string>
<string name="title_unknown_signature_key">Неизвестная подпись</string>
- <string name="title_sign_key">Ключ для подписи</string>
+ <string name="title_certify_key">Сертифицировать ключ</string>
<string name="title_key_details">Сведения о ключе</string>
<string name="title_help">Помощь</string>
<!--section-->
@@ -37,17 +37,16 @@
<string name="section_master_key">Основной ключ</string>
<string name="section_master_user_id">Владелец</string>
<string name="section_actions">Действия</string>
- <string name="section_signing_key">Ваш ключ, используемый для подписания</string>
+ <string name="section_certification_key">Ваш ключ для сертификации</string>
<string name="section_upload_key">Загрузить ключ</string>
<string name="section_key_server">Сервер ключей</string>
+ <string name="section_encrypt_and_or_sign">Зашифровать и/или Подписать</string>
+ <string name="section_decrypt_verify">Расшифровать и проверить</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Подписать (Буфер обмена)</string>
- <string name="btn_encrypt_to_clipboard">Зашифровать в Буфер обмена</string>
- <string name="btn_encrypt_and_send">Зашифровать и отправить...</string>
- <string name="btn_sign_and_send">Подписать и отправить...</string>
<string name="btn_sign">Подписать</string>
+ <string name="btn_certify">Сертифицировать</string>
<string name="btn_decrypt">Расшифровать</string>
- <string name="btn_verify">Проверить</string>
+ <string name="btn_decrypt_verify">Расшифровать и проверить</string>
<string name="btn_select_encrypt_keys">Выбрать получателей</string>
<string name="btn_encrypt_file">Зашифровать файл</string>
<string name="btn_save">Сохранить</string>
@@ -61,6 +60,9 @@
<string name="btn_export_to_server">Загрузить на сервер ключей</string>
<string name="btn_next">Далее</string>
<string name="btn_back">Назад</string>
+ <string name="btn_clipboard">Буфер обмена</string>
+ <string name="btn_share">Поделиться...</string>
+ <string name="btn_lookup_key">Найти ключ</string>
<!--menu-->
<string name="menu_preferences">Настройки</string>
<string name="menu_help">Помощь</string>
@@ -109,7 +111,6 @@
<string name="label_passphrase_cache_ttl">Помнить пароль</string>
<string name="label_message_compression">Сжатие сообщения</string>
<string name="label_file_compression">Сжатие файла</string>
- <string name="label_force_v3_signature">Использовать V3 подписи</string>
<string name="label_key_servers">Серверы ключей</string>
<string name="label_key_id">ID ключа</string>
<string name="label_creation">Создан</string>
@@ -120,7 +121,7 @@
<string name="label_name">Имя</string>
<string name="label_comment">Комментарий</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Загрузить подписанный ключ на сервер</string>
+ <string name="label_send_key">После сертификации загрузить ключ на сервер</string>
<string name="label_fingerprint">Отпечаток</string>
<string name="select_keys_button_default">Выбрать</string>
<plurals name="select_keys_button">
@@ -134,7 +135,8 @@
<string name="unknown_status"></string>
<string name="can_encrypt">шифрование</string>
<string name="can_sign">подпись</string>
- <string name="expired">годен до</string>
+ <string name="expired">просрочен</string>
+ <string name="revoked">отозван</string>
<plurals name="n_key_servers">
<item quantity="one">%d сервер ключей</item>
<item quantity="few">%d серверов ключей</item>
@@ -222,14 +224,13 @@
<item quantity="few">Найдено %d ключей.</item>
<item quantity="other">Найдено %d ключей.</item>
</plurals>
- <string name="unknown_signature_key_touch_to_look_up">Неизвестная подпись. Нажмите для выбора ключа.</string>
+ <string name="unknown_signature">Неизвестная подпись. Нажмите кнопку, что бы найти ключ.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d плохой секретный ключ проигнорирован. Возможно, вы экспортируете с параметром\n--export-secret-subkeys\nВместо этого используйте\n--export-secret-keys</item>
<item quantity="few">%d плохих секретных ключей проигнорировано. Возможно, вы экспортируете с параметром\n--export-secret-subkeys\nВместо этого используйте\n--export-secret-keys\n</item>
<item quantity="other">%d плохих секретных ключей проигнорировано. Возможно, вы экспортируете с параметром\n--export-secret-subkeys\nВместо этого используйте\n--export-secret-keys\n</item>
</plurals>
- <string name="lookup_unknown_key">Неизвестный ключ %s. Хотите искать на сервере ключей?</string>
- <string name="key_send_success">Ключ успешно отправлен на сервер</string>
+ <string name="key_send_success">Ключ успешно загружен на сервер</string>
<string name="key_sign_success">Ключ успешно подписан</string>
<string name="list_empty">Список пуст!</string>
<string name="nfc_successfull">Ключ успешно передан через NFC!</string>
@@ -269,19 +270,25 @@
<string name="error_nfc_needed">Ваше устройство не поддерживает NFC!</string>
<string name="error_nothing_import">Нет данных для импорта!</string>
<string name="error_expiry_must_come_after_creation">срок годности не может быть раньше даты создания</string>
+ <string name="error_can_not_delete_contact">нельзя удалить свой собственный контакт. Пожалуйста, удалите его в разделе \'Мои ключи\'!</string>
+ <string name="error_can_not_delete_contacts">это ваши собственные контакты, их нельзя удалить:\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Пожалуйста, удалите его в разделе \'Мои ключи\'!</item>
+ <item quantity="few">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item>
+ <item quantity="other">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">готово.</string>
<string name="progress_saving">сохранение...</string>
<string name="progress_importing">импорт...</string>
<string name="progress_exporting">экспорт...</string>
- <string name="progress_generating">создание ключа... на это нужно время...</string>
+ <string name="progress_generating">создание ключа. это может занять до 3 минут...</string>
<string name="progress_building_key">создание ключа...</string>
<string name="progress_preparing_master_key">подготовка основного ключа...</string>
<string name="progress_certifying_master_key">сертификация основного ключа...</string>
<string name="progress_building_master_key">создание основной связки...</string>
<string name="progress_adding_sub_keys">добавление доп. ключей...</string>
<string name="progress_saving_key_ring">сохранение ключа...</string>
- <string name="progress_importing_secret_keys">импорт секретных ключей...</string>
<plurals name="progress_exporting_key">
<item quantity="one">экспорт ключа...</item>
<item quantity="few">экспорт ключей...</item>
@@ -344,7 +351,7 @@
<string name="intent_send_encrypt">OpenPGP: Зашифровать</string>
<string name="intent_send_decrypt">OpenPGP: Расшифровать</string>
<!--Remote API-->
- <string name="api_no_apps">Нет связанных приложений!</string>
+ <string name="api_no_apps">Нет связанных программ!\n\nСторонние программы могут запросить доступ к OpenPGP Keychain, после чего они будут отражаться здесь.</string>
<string name="api_settings_show_advanced">Показать расширенные настройки</string>
<string name="api_settings_hide_advanced">Скрыть расширенные настройки</string>
<string name="api_settings_no_key">Ключ не выбран</string>
@@ -354,7 +361,7 @@
<string name="api_settings_revoke">Отозвать доступ</string>
<string name="api_settings_package_name">Наименование пакета</string>
<string name="api_settings_package_signature">SHA-256 подписи пакета</string>
- <string name="api_register_text">Приложение запрашивает доступ к OpenPGP Keychain API.\nРазрешить доступ?</string>
+ <string name="api_register_text">Данное приложение запрашивает доступ к OpenPGP Keychain.\nРазрешить доступ?\n\nВНИМАНИЕ: Если вы не знаете почему возник этот запрос, откажите в доступе!\nПозже вы можете отозвать право доступа в разделе \"Зарегистрированные программы\".</string>
<string name="api_register_allow">Разрешить доступ</string>
<string name="api_register_disallow">Запретить доступ</string>
<string name="api_register_error_select_key">Пожалуйста, выберите ключ!</string>
@@ -381,6 +388,9 @@
<string name="key_list_empty_button_import">Импортировать ключи</string>
<!--Key view-->
<string name="key_view_action_encrypt">Зашифровать для этого получателя</string>
+ <string name="key_view_action_certify">Сертифицировать ключ этого контакта</string>
+ <string name="key_view_tab_main">Информация</string>
+ <string name="key_view_tab_certs">Сертификация</string>
<!--Navigation Drawer-->
<string name="nav_contacts">Контакты</string>
<string name="nav_encrypt">Зашифровать</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-tr/strings.xml b/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
index d9fe8713e..5bb5225b5 100644
--- a/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
@@ -7,14 +7,11 @@
<string name="title_create_key">Anahtar oluştur</string>
<string name="title_edit_key">Anahtarı düzenle</string>
<string name="title_preferences">Seçenekler</string>
- <string name="title_key_server_preference">Anahtar Sunucusu Seçenekleri</string>
<string name="title_import_keys">Anahtarları Al</string>
<string name="title_export_key">Anahtarı Ver</string>
<string name="title_export_keys">Anahtarları Ver</string>
<string name="title_key_not_found">Anahtar Bulunamadı</string>
- <string name="title_key_server_query">Anahtar Sunucusunu Sorgula</string>
<string name="title_unknown_signature_key">Bilinmeyen İmza Anahtarı</string>
- <string name="title_sign_key">Anahtarı İmzala</string>
<string name="title_key_details">Anahtar Detayları</string>
<string name="title_help">Yardım</string>
<!--section-->
@@ -24,21 +21,14 @@
<string name="section_defaults">Varsayılanlar</string>
<string name="section_advanced">Gelişmiş</string>
<string name="section_upload_key">Anahtar Yükle</string>
- <string name="section_key_server">Anahtar Sunucusu</string>
<!--button-->
- <string name="btn_sign_to_clipboard">İmzala (Pano)</string>
- <string name="btn_encrypt_to_clipboard">Panoya Şifrele</string>
- <string name="btn_encrypt_and_send">Şifrele ve gönder...</string>
- <string name="btn_sign_and_send">İmzala ve gönder...</string>
<string name="btn_sign">İmzala</string>
- <string name="btn_verify">Doğrula</string>
<string name="btn_select_encrypt_keys">Alıcıları Seç</string>
<string name="btn_save">Kaydet</string>
<string name="btn_do_not_save">İptal</string>
<string name="btn_delete">Sil</string>
<string name="btn_okay">Tamam</string>
<string name="btn_search">Ara</string>
- <string name="btn_export_to_server">Sunucuya Anahtar Yükle</string>
<string name="btn_next">İleri</string>
<string name="btn_back">Geri</string>
<!--menu-->
@@ -53,7 +43,6 @@
<string name="menu_create_key">Anahtar oluştur</string>
<string name="menu_create_key_expert">Anahtar oluştur (uzman)</string>
<string name="menu_search">Ara</string>
- <string name="menu_key_server">Anahtar sunucusundan al</string>
<string name="menu_copy_to_clipboard">Panoya kopyala</string>
<string name="menu_sign_key">Anahtarı imzala</string>
<string name="menu_key_edit_cancel">İptal</string>
@@ -64,7 +53,6 @@
<string name="label_passphrase_again">Tekrar</string>
<string name="label_algorithm">Algoritma</string>
<string name="label_asymmetric">Açık Anahtar</string>
- <string name="label_key_servers">Anahtar Sunucuları</string>
<string name="label_creation">Oluşturma</string>
<string name="label_usage">Kullanım</string>
<string name="label_key_size">Anahtar Boyutu</string>
@@ -97,7 +85,6 @@
<string name="no_file_selected">Önce bir dosya seçin.</string>
<string name="encryption_successful">Başarıyla şifrelendi.</string>
<string name="key_not_found">Anahtar %08X bulunamadı.</string>
- <string name="key_send_success">Anahtar sunucuya başarıyla gönderildi</string>
<string name="key_sign_success">Anahtar başarıyla imzalandı</string>
<string name="list_empty">Liste boş!</string>
<!--errors
@@ -112,7 +99,6 @@
<string name="progress_saving">kaydediliyor...</string>
<string name="progress_importing">alıyor...</string>
<string name="progress_exporting">veriyor...</string>
- <string name="progress_generating">anahtar üretiliyor, bu biraz süre alabilir...</string>
<string name="progress_building_key">anahtar oluşturuluyor...</string>
<string name="progress_preparing_signature">imza hazırlanıyor...</string>
<string name="progress_generating_signature">imza oluşturuluyor...</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
index ac40311b0..47cbb38b3 100644
--- a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
@@ -22,10 +22,10 @@
<string name="title_export_key">Експортувати ключ</string>
<string name="title_export_keys">Експортувати ключі</string>
<string name="title_key_not_found">Ключ не знайдено</string>
- <string name="title_key_server_query">Сервер запиту ключа</string>
+ <string name="title_key_server_query">Сервер ключа запиту</string>
<string name="title_send_key">Завантажити на сервер ключів</string>
<string name="title_unknown_signature_key">Невідомий підпис ключа</string>
- <string name="title_sign_key">Підписати ключ</string>
+ <string name="title_certify_key">Сертифікувати ключ</string>
<string name="title_key_details">Подробиці про ключ</string>
<string name="title_help">Довідка</string>
<!--section-->
@@ -37,17 +37,16 @@
<string name="section_master_key">Основний ключ</string>
<string name="section_master_user_id">ІД основного ключа</string>
<string name="section_actions">Дії</string>
- <string name="section_signing_key">Ваш ключ, використаний для підпису</string>
+ <string name="section_certification_key">Ваш ключ використаний для сертифікації</string>
<string name="section_upload_key">Завантажити ключ</string>
<string name="section_key_server">Сервер ключів</string>
+ <string name="section_encrypt_and_or_sign">Шифрувати і/або підписати</string>
+ <string name="section_decrypt_verify">Розшифрувати і Перевірити</string>
<!--button-->
- <string name="btn_sign_to_clipboard">Підпис (буфер обміну)</string>
- <string name="btn_encrypt_to_clipboard">Зашифрувати у буфер обміну</string>
- <string name="btn_encrypt_and_send">Шифрувати і надіслати…</string>
- <string name="btn_sign_and_send">Підписати і надіслати…</string>
<string name="btn_sign">Підписати</string>
+ <string name="btn_certify">Сертифікувати</string>
<string name="btn_decrypt">Розшифрувати</string>
- <string name="btn_verify">Перевірити</string>
+ <string name="btn_decrypt_verify">Розшифрувати і Перевірити</string>
<string name="btn_select_encrypt_keys">Вибрати одержувачів</string>
<string name="btn_encrypt_file">Шифрувати файл</string>
<string name="btn_save">Зберегти</string>
@@ -61,6 +60,9 @@
<string name="btn_export_to_server">Завантажити на сервер ключів</string>
<string name="btn_next">Далі</string>
<string name="btn_back">Назад</string>
+ <string name="btn_clipboard">Буфер обміну</string>
+ <string name="btn_share">Поділитися через…</string>
+ <string name="btn_lookup_key">Шукати ключ</string>
<!--menu-->
<string name="menu_preferences">Параметри</string>
<string name="menu_help">Довідка</string>
@@ -109,7 +111,7 @@
<string name="label_passphrase_cache_ttl">Кеш парольної фрази</string>
<string name="label_message_compression">Стиснення повідомлення</string>
<string name="label_file_compression">Стиснення файлу</string>
- <string name="label_force_v3_signature">Примусові підписи V3</string>
+ <string name="label_force_v3_signature">Примусово старі підписи OpenPGPv3</string>
<string name="label_key_servers">Сервери ключів</string>
<string name="label_key_id">ІД ключа</string>
<string name="label_creation">Створення</string>
@@ -120,7 +122,7 @@
<string name="label_name">Назва</string>
<string name="label_comment">Коментар</string>
<string name="label_email">Ел. пошта</string>
- <string name="label_send_key">Завантажити ключ на вибраний сервер ключів після підписування</string>
+ <string name="label_send_key">Завантажити ключ до вибраного сервера ключів після сертифікації</string>
<string name="label_fingerprint">Відбиток</string>
<string name="select_keys_button_default">Вибрати</string>
<plurals name="select_keys_button">
@@ -135,6 +137,7 @@
<string name="can_encrypt">можна зашифрувати</string>
<string name="can_sign">можна підписати</string>
<string name="expired">закінчився</string>
+ <string name="revoked">скасовано</string>
<plurals name="n_key_servers">
<item quantity="one">%d сервер ключів</item>
<item quantity="few">%d сервери ключів</item>
@@ -222,14 +225,13 @@
<item quantity="few">Знайдено %d ключі.</item>
<item quantity="other">Знайдено %d ключів.</item>
</plurals>
- <string name="unknown_signature_key_touch_to_look_up">Невідомий підпис, натисніть, щоб шукати ключ.</string>
+ <string name="unknown_signature">Невідомий підпис, натисніть кнопку для пошуку втраченого ключа.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d поганий секретний ключ проігнорований. Можливо ви експортували з параметром\n --export-secret-subkeys\nЗробіть ваш експорт з \n --export-secret-keys\nнатомість.</item>
<item quantity="few">%d погані секретні ключі проігноровані. Можливо ви експортували з параметром\n --export-secret-subkeys\nЗробіть ваш експорт з \n --export-secret-keys\nнатомість.</item>
<item quantity="other">%d поганих секретних ключів проігноровано. Можливо ви експортували з параметром\n --export-secret-subkeys\nЗробіть ваш експорт з \n --export-secret-keys\nнатомість.</item>
</plurals>
- <string name="lookup_unknown_key">Невідомий ключ %s, ви хочете віднайти його на сервері ключів?</string>
- <string name="key_send_success">Успішно надіслано ключ на сервер</string>
+ <string name="key_send_success">Успішно завантажено ключ на сервер</string>
<string name="key_sign_success">Успішно підписаний ключ</string>
<string name="list_empty">Цей список - порожній!</string>
<string name="nfc_successfull">Успішно відправлений ключ з NFC променем!</string>
@@ -260,6 +262,7 @@
<string name="error_no_signature_key">не подано ключ підпису</string>
<string name="error_invalid_data">недійсні дані шифрування</string>
<string name="error_corrupt_data">пошкодити дані</string>
+ <string name="error_integrity_check_failed">Невдала перевірка цілісності! Дані вже змінено!</string>
<string name="error_no_symmetric_encryption_packet">не знайдено пакунок з симетричним шифруванням</string>
<string name="error_wrong_passphrase">помилкова парольна фраза</string>
<string name="error_saving_keys">помилка збереження деяких ключів</string>
@@ -269,19 +272,25 @@
<string name="error_nfc_needed">NFC недоступний на вашому пристрої!</string>
<string name="error_nothing_import">Нема що імпортувати!</string>
<string name="error_expiry_must_come_after_creation">дата завершення дії має йти після дати створення</string>
+ <string name="error_can_not_delete_contact">ви не можете вилучити цей контакт, тому що він ваш власний.</string>
+ <string name="error_can_not_delete_contacts">ви не можете вилучити наступні контакти, тому що вони - ваші власні:\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Будь ласка, вилучіть його з екрану „Мої ключі“!</item>
+ <item quantity="few">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item>
+ <item quantity="other">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">готово.</string>
<string name="progress_saving">збереження…</string>
<string name="progress_importing">імпортується…</string>
<string name="progress_exporting">експортується…</string>
- <string name="progress_generating">генерується ключ, зачекайте…</string>
+ <string name="progress_generating">генерується ключ, вона може тривати до 3 хвилин…</string>
<string name="progress_building_key">будується ключ…</string>
<string name="progress_preparing_master_key">підготовка основного ключа…</string>
<string name="progress_certifying_master_key">сертифікація основного ключа…</string>
<string name="progress_building_master_key">побудова основного кільця…</string>
<string name="progress_adding_sub_keys">додавання підключів…</string>
<string name="progress_saving_key_ring">зберігається ключ…</string>
- <string name="progress_importing_secret_keys">імпортуються секретні ключі…</string>
<plurals name="progress_exporting_key">
<item quantity="one">експортується ключ…</item>
<item quantity="few">експортуються ключі…</item>
@@ -344,7 +353,7 @@
<string name="intent_send_encrypt">OpenPGP: зашифрувати</string>
<string name="intent_send_decrypt">OpenPGP: розшифрувати</string>
<!--Remote API-->
- <string name="api_no_apps">Немає зареєстрованих програм!</string>
+ <string name="api_no_apps">Нема зареєстрованих програм!\n\nСтороні програми можуть вимагати доступ до OpenPGP Keychain. Після надання доступу вони будуть наведені тут.</string>
<string name="api_settings_show_advanced">Показати додаткові налаштування</string>
<string name="api_settings_hide_advanced">Приховати додаткові налаштування</string>
<string name="api_settings_no_key">Не вибрано ключа</string>
@@ -354,7 +363,7 @@
<string name="api_settings_revoke">Відкликати доступ</string>
<string name="api_settings_package_name">Назва пакунку</string>
<string name="api_settings_package_signature">SHA-256 підписку пакунку</string>
- <string name="api_register_text">Наступна програм запитала доступ до OpenPGP Keychain API.\n\nДозволити постійний доступ?</string>
+ <string name="api_register_text">Показана програма запитує доступ до OpenPGP Keychain.\nДозволити доступ?\n\nУВАГА: якщо ви не знаєте, чому цей екран появився, не дозволяйте доступ! Ви можете відкликати доступ пізніше, використовуючи екран \'Зареєстровані програми\'.</string>
<string name="api_register_allow">Дозволити доступ</string>
<string name="api_register_disallow">Не дозволити доступ</string>
<string name="api_register_error_select_key">Будь ласка, виберіть ключ!</string>
@@ -381,6 +390,9 @@
<string name="key_list_empty_button_import">імпортуюся ключі.</string>
<!--Key view-->
<string name="key_view_action_encrypt">Зашифрувати у цей контакт</string>
+ <string name="key_view_action_certify">Сертифікувати ключ цього контакту</string>
+ <string name="key_view_tab_main">Інформація</string>
+ <string name="key_view_tab_certs">Сертифікати</string>
<!--Navigation Drawer-->
<string name="nav_contacts">Контакти</string>
<string name="nav_encrypt">Зашифрувати</string>
diff --git a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
index 6bb115049..30d6a3518 100644
--- a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
@@ -1,26 +1,164 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--title-->
+ <string name="title_encrypt">加密</string>
+ <string name="title_decrypt">解密</string>
+ <string name="title_key_server_preference">密钥服务器偏好</string>
+ <string name="title_key_server_query">查询密钥服务器</string>
+ <string name="title_send_key">上传到密钥服务器</string>
<!--section-->
+ <string name="section_master_key">主密钥</string>
+ <string name="section_key_server">密钥服务器</string>
+ <string name="section_decrypt_verify">解密并验证</string>
<!--button-->
+ <string name="btn_decrypt_verify">解密并验证</string>
+ <string name="btn_clipboard">剪贴板</string>
<!--menu-->
+ <string name="menu_help">帮助</string>
+ <string name="menu_import">导入</string>
+ <string name="menu_delete_key">删除密钥</string>
+ <string name="menu_create_key">创建密钥</string>
+ <string name="menu_create_key_expert">创建密钥(专家)</string>
+ <string name="menu_search">搜索</string>
+ <string name="menu_share">分享</string>
+ <string name="menu_copy_to_clipboard">复制到剪贴板</string>
+ <string name="menu_sign_key">签署密钥</string>
+ <string name="menu_key_edit_cancel">取消</string>
+ <string name="menu_encrypt_to">加密到...</string>
<!--label-->
+ <string name="label_sign">签署</string>
+ <string name="label_message">讯息</string>
+ <string name="label_file">文件</string>
+ <string name="label_no_passphrase">没有密语</string>
+ <string name="label_passphrase">密语</string>
+ <string name="label_algorithm">算法</string>
+ <string name="label_select_public_keys">收件人</string>
+ <string name="label_delete_after_encryption">加密后删除</string>
+ <string name="label_delete_after_decryption">解密后删除</string>
+ <string name="label_encryption_algorithm">加密算法</string>
+ <string name="label_hash_algorithm">哈希算法</string>
+ <string name="label_asymmetric">公共密钥</string>
+ <string name="label_symmetric">密语</string>
+ <string name="label_passphrase_cache_ttl">密语缓存</string>
+ <string name="label_comment">注解</string>
+ <string name="label_email">电子邮件</string>
+ <string name="label_fingerprint">指纹</string>
<string name="unknown_status"></string>
+ <string name="can_encrypt">可以加密</string>
+ <string name="can_sign">可以签署</string>
+ <string name="expired">过期了</string>
<!--choice-->
+ <string name="choice_none">没有</string>
+ <string name="choice_sign_only">仅签署</string>
+ <string name="choice_encrypt_only">仅加密</string>
+ <string name="choice_sign_and_encrypt">签署并加密</string>
+ <string name="choice_15secs">15秒</string>
+ <string name="choice_1min">1分钟</string>
+ <string name="choice_3mins">3分钟</string>
+ <string name="choice_5mins">5分钟</string>
+ <string name="choice_10mins">10分钟</string>
+ <string name="choice_20mins">20分钟</string>
+ <string name="choice_40mins">40分钟</string>
+ <string name="choice_1hour">1小时</string>
+ <string name="choice_2hours">2小时</string>
+ <string name="choice_4hours">4小时</string>
+ <string name="choice_8hours">8小时</string>
+ <string name="choice_forever">永远</string>
+ <string name="filemanager_title_open">打开...</string>
+ <string name="warning">警告</string>
+ <string name="error">错误</string>
<!--sentences-->
+ <string name="set_a_passphrase">先设置密钥</string>
+ <string name="no_filemanager_installed">安装了不匹配的文件管理器</string>
+ <string name="passphrases_do_not_match">密钥不匹配</string>
+ <string name="passphrase_must_not_be_empty">不允许空的密钥</string>
+ <string name="passphrase_for_symmetric_encryption">对称加密</string>
+ <string name="file_delete_successful">删除成功</string>
+ <string name="no_file_selected">先选择一个文件</string>
+ <string name="decryption_successful">解密成功</string>
+ <string name="encryption_successful">加密成功</string>
+ <string name="encryption_to_clipboard_successful">成功地加密到了剪贴板</string>
+ <string name="enter_passphrase_twice">输入两次密钥</string>
+ <string name="select_encryption_key">选择至少一个加密密钥</string>
+ <string name="select_encryption_or_signature_key">选择至少一个加密密钥或者签名密钥</string>
+ <string name="key_exported">成功地导出了1个密钥</string>
+ <string name="no_keys_exported">没有密钥被导出</string>
+ <string name="key_send_success">成功地上传了密钥到服务器</string>
+ <string name="list_empty">这个列表是空的!</string>
<!--errors
no punctuation, all lowercase,
they will be put after "error_message", e.g. "Error: file not found"-->
+ <string name="error_file_not_found">没有找到文件</string>
+ <string name="error_external_storage_not_ready">外置存储没有准备好</string>
+ <string name="error_invalid_email">无效的email \'%s\'</string>
+ <string name="error_key_size_minimum512bit">密钥的大小必须至少512位</string>
+ <string name="error_unknown_algorithm_choice">位置的算法选择</string>
+ <string name="error_user_id_needs_a_name">你需要指定一个名字</string>
+ <string name="error_user_id_needs_an_email_address">你需要指定一个电子邮件地址</string>
+ <string name="error_key_needs_a_user_id">需要至少一个用户id</string>
+ <string name="error_main_user_id_must_not_be_empty">主用户id不能是空的</string>
+ <string name="error_key_needs_master_key">需要至少一个主密钥</string>
+ <string name="error_signature_failed">签名失败</string>
+ <string name="error_no_signature_passphrase">没有提供密语</string>
+ <string name="error_no_signature_key">没有提供密钥</string>
+ <string name="error_invalid_data">不是有效的加密数据</string>
+ <string name="error_corrupt_data">损坏的数据</string>
+ <string name="error_wrong_passphrase">错误的密语</string>
<!--progress dialogs, usually ending in '…'-->
+ <string name="progress_done">完成。</string>
+ <string name="progress_saving">保存...</string>
+ <string name="progress_importing">导入中...</string>
+ <string name="progress_exporting">导出中...</string>
+ <string name="progress_building_key">建立密钥</string>
+ <string name="progress_preparing_master_key">正在准备主密钥</string>
+ <string name="progress_verifying_signature">正在验证签名...</string>
+ <string name="progress_signing">正在签名...</string>
+ <string name="progress_reading_data">正在读取数据</string>
+ <string name="progress_finding_key">正在查找密钥</string>
+ <string name="progress_querying">正在查询</string>
<!--action strings-->
<!--key bit length selections-->
+ <string name="key_size_512">512</string>
+ <string name="key_size_1024">1024</string>
+ <string name="key_size_2048">2048</string>
+ <string name="key_size_4096">4096</string>
<!--compression-->
+ <string name="compression_fast">快</string>
+ <string name="compression_very_slow">非常慢</string>
<!--Help-->
+ <string name="help_tab_start">开始</string>
+ <string name="help_tab_changelog">更新日志</string>
+ <string name="help_tab_about">关于</string>
+ <string name="help_about_version">版本:</string>
<!--Import-->
+ <string name="import_from_clipboard">从剪贴板导入</string>
+ <string name="import_qr_code_finished">二维码扫描完成!</string>
+ <string name="import_nfc_help_button">帮助</string>
<!--Intent labels-->
+ <string name="intent_decrypt_file">OpenPGP: 解密文件</string>
+ <string name="intent_import_key">OpenPGP: 导入密钥</string>
+ <string name="intent_send_encrypt">OpenPGP: 加密</string>
+ <string name="intent_send_decrypt">OpenPGP: 解密</string>
<!--Remote API-->
+ <string name="api_settings_show_advanced">显示高级设置</string>
+ <string name="api_settings_hide_advanced">隐藏高级设置</string>
+ <string name="api_settings_select_key">选择密钥</string>
+ <string name="api_settings_save">保存</string>
+ <string name="api_settings_cancel">取消</string>
+ <string name="api_settings_revoke">撤销访问</string>
+ <string name="api_register_allow">允许访问</string>
+ <string name="api_register_disallow">不允许访问</string>
+ <string name="api_register_error_select_key">请选择一个密钥</string>
+ <string name="api_select_pub_keys_text">请重审收件人列表</string>
<!--Share-->
+ <string name="share_qr_code_dialog_fingerprint_text">指纹:</string>
+ <string name="share_nfc_dialog">使用NFC分享</string>
<!--Key list-->
+ <string name="key_list_empty_text3">或者</string>
<!--Key view-->
<!--Navigation Drawer-->
+ <string name="nav_encrypt">加密</string>
+ <string name="nav_decrypt">解密</string>
+ <string name="nav_import">导入密钥</string>
+ <string name="nav_secret_keys">我的密钥</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values/static_strings.xml b/OpenPGP-Keychain/src/main/res/values/static_strings.xml
index 3c9cf6673..faf1e687a 100644
--- a/OpenPGP-Keychain/src/main/res/values/static_strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values/static_strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <string name="app_name" translatable="false">OpenPGP Keychain</string>
+ <string name="app_name" translatable="false">OpenKeychain</string>
</resources> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml
index 64c9be32d..861a50eaa 100644
--- a/OpenPGP-Keychain/src/main/res/values/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values/strings.xml
@@ -13,7 +13,7 @@
<string name="title_edit_key">Edit Key</string>
<string name="title_preferences">Preferences</string>
<string name="title_api_registered_apps">Registered Applications</string>
- <string name="title_key_server_preference">Key Server Preference</string>
+ <string name="title_key_server_preference">Keyserver Preference</string>
<string name="title_change_pass_phrase">Change Passphrase</string>
<string name="title_set_passphrase">Set Passphrase</string>
<string name="title_send_email">"Send Mail…"</string>
@@ -23,10 +23,10 @@
<string name="title_export_key">Export Key</string>
<string name="title_export_keys">Export Keys</string>
<string name="title_key_not_found">Key Not Found</string>
- <string name="title_key_server_query">Query Key Server</string>
- <string name="title_send_key">Upload to Key Server</string>
+ <string name="title_key_server_query">Query Keyserver</string>
+ <string name="title_send_key">Upload to Keyserver</string>
<string name="title_unknown_signature_key">Unknown Signature Key</string>
- <string name="title_sign_key">Sign Key</string>
+ <string name="title_certify_key">Certify Key</string>
<string name="title_key_details">Key Details</string>
<string name="title_help">Help</string>
@@ -39,14 +39,15 @@
<string name="section_master_key">Master Key</string>
<string name="section_master_user_id">Master User ID</string>
<string name="section_actions">Actions</string>
- <string name="section_signing_key">Your Key used for Signing</string>
+ <string name="section_certification_key">Your Key used for certification</string>
<string name="section_upload_key">Upload Key</string>
- <string name="section_key_server">Key Server</string>
+ <string name="section_key_server">Keyserver</string>
<string name="section_encrypt_and_or_sign">Encrypt and/or Sign</string>
<string name="section_decrypt_verify">Decrypt and Verify</string>
<!-- button -->
<string name="btn_sign">Sign</string>
+ <string name="btn_certify">Certify</string>
<string name="btn_decrypt">Decrypt</string>
<string name="btn_decrypt_verify">Decrypt and Verify</string>
<string name="btn_select_encrypt_keys">Select Recipients</string>
@@ -59,12 +60,12 @@
<string name="btn_change_passphrase">Change New Passphrase</string>
<string name="btn_set_passphrase">Set New Passphrase</string>
<string name="btn_search">Search</string>
- <string name="btn_export_to_server">Upload To Key Server</string>
+ <string name="btn_export_to_server">Upload To Keyserver</string>
<string name="btn_next">Next</string>
<string name="btn_back">Back</string>
<string name="btn_clipboard">Clipboard</string>
<string name="btn_share">Share with…</string>
-
+ <string name="btn_lookup_key">Lookup key</string>
<!-- menu -->
<string name="menu_preferences">Settings</string>
@@ -79,8 +80,8 @@
<string name="menu_create_key">Create key</string>
<string name="menu_create_key_expert">Create key (expert)</string>
<string name="menu_search">Search</string>
- <string name="menu_key_server">Import from key server</string>
- <string name="menu_update_key">Update from key server</string>
+ <string name="menu_key_server">Import from keyserver</string>
+ <string name="menu_update_key">Update from keyserver</string>
<string name="menu_export_key_to_server">Upload to key server</string>
<string name="menu_share">Share</string>
<string name="menu_share_title_fingerprint">Share fingerprint…</string>
@@ -115,8 +116,8 @@
<string name="label_passphrase_cache_ttl">Passphrase Cache</string>
<string name="label_message_compression">Message Compression</string>
<string name="label_file_compression">File Compression</string>
- <string name="label_force_v3_signature">Force V3 Signatures</string>
- <string name="label_key_servers">Key Servers</string>
+ <string name="label_force_v3_signature">Force old OpenPGPv3 Signatures</string>
+ <string name="label_key_servers">Keyservers</string>
<string name="label_key_id">Key ID</string>
<string name="label_creation">Creation</string>
<string name="label_expiry">Expiry</string>
@@ -126,7 +127,7 @@
<string name="label_name">Name</string>
<string name="label_comment">Comment</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Upload key to selected key server after signing</string>
+ <string name="label_send_key">Upload key to selected keyserver after certification</string>
<string name="label_fingerprint">Fingerprint</string>
<string name="select_keys_button_default">Select</string>
@@ -142,10 +143,11 @@
<string name="can_encrypt">can encrypt</string>
<string name="can_sign">can sign</string>
<string name="expired">expired</string>
+ <string name="revoked">revoked</string>
<plurals name="n_key_servers">
- <item quantity="one">%d key server</item>
- <item quantity="other">%d key servers</item>
+ <item quantity="one">%d keyserver</item>
+ <item quantity="other">%d keyservers</item>
</plurals>
<string name="fingerprint">Fingerprint:</string>
@@ -235,15 +237,14 @@
<item quantity="other">Found %d keys.</item>
</plurals>
- <string name="unknown_signature_key_touch_to_look_up">Unknown signature, touch to look up key.</string>
+ <string name="unknown_signature">Unknown signature, click button to lookup the missing key.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d bad secret key ignored. Perhaps you exported with the option\n --export-secret-subkeys\nMake sure you export with\n --export-secret-keys\ninstead.</item>
<item quantity="other">%d bad secret keys ignored. Perhaps you exported with the option\n --export-secret-subkeys\nMake sure you export with\n --export-secret-keys\ninstead.</item>
</plurals>
- <string name="lookup_unknown_key">Unknown key %s, do you want to try finding it on a keyserver?</string>
- <string name="key_send_success">Successfully sent key to server</string>
+ <string name="key_send_success">Successfully uploaded key to server</string>
<string name="key_sign_success">Successfully signed key</string>
<string name="list_empty">This list is empty!</string>
<string name="nfc_successfull">Successfully sent key with NFC Beam!</string>
@@ -277,6 +278,7 @@
<string name="error_no_signature_key">no signature key given</string>
<string name="error_invalid_data">not valid encryption data</string>
<string name="error_corrupt_data">corrupt data</string>
+ <string name="error_integrity_check_failed">integrity check failed! Data has been modified!</string>
<string name="error_no_symmetric_encryption_packet">couldn\'t find a packet with symmetric encryption</string>
<string name="error_wrong_passphrase">wrong passphrase</string>
<string name="error_saving_keys">error saving some keys</string>
@@ -287,13 +289,19 @@
<string name="error_nothing_import">Nothing to import!</string>
<string name="error_expiry_must_come_after_creation">expiry date must come after creation date</string>
<string name="error_save_first">please save the keyring first</string>
+ <string name="error_can_not_delete_contact">you can not delete this contact because it is your own.</string>
+ <string name="error_can_not_delete_contacts">you can not delete the following contacts because they are your own:\n%s</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Please delete it from the \'My Keys\' screen!</item>
+ <item quantity="other">Please delete them from the \'My Keys\' screen!</item>
+ </plurals>
<!-- progress dialogs, usually ending in '…' -->
<string name="progress_done">done.</string>
<string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string>
- <string name="progress_generating">generating key, this can take a while…</string>
+ <string name="progress_generating">generating key, this can take up to 3 minutes…</string>
<string name="progress_building_key">building key…</string>
<string name="progress_preparing_master_key">preparing master key…</string>
<string name="progress_certifying_master_key">certifying master key…</string>
@@ -365,13 +373,13 @@
<string name="import_clipboard_button">Get key from clipboard</string>
<!-- Intent labels -->
- <string name="intent_decrypt_file">OpenPGP: Decrypt File</string>
- <string name="intent_import_key">OpenPGP: Import Key</string>
- <string name="intent_send_encrypt">OpenPGP: Encrypt</string>
- <string name="intent_send_decrypt">OpenPGP: Decrypt</string>
+ <string name="intent_decrypt_file">OpenKeychain: Decrypt File</string>
+ <string name="intent_import_key">OpenKeychain: Import Key</string>
+ <string name="intent_send_encrypt">OpenKeychain: Encrypt</string>
+ <string name="intent_send_decrypt">OpenKeychain: Decrypt</string>
<!-- Remote API -->
- <string name="api_no_apps">No registered applications!</string>
+ <string name="api_no_apps">No registered applications!\n\nThird-party applications can request access to OpenKeychain. After granting access, they will be listed here.</string>
<string name="api_settings_show_advanced">Show advanced settings</string>
<string name="api_settings_hide_advanced">Hide advanced settings</string>
<string name="api_settings_no_key">No key selected</string>
@@ -381,14 +389,14 @@
<string name="api_settings_revoke">Revoke access</string>
<string name="api_settings_package_name">Package Name</string>
<string name="api_settings_package_signature">SHA-256 of Package Signature</string>
- <string name="api_register_text">The following application requests access to OpenPGP Keychain\'s API.\n\nAllow permanent access?</string>
+ <string name="api_register_text">The displayed application requests access to OpenKeychain.\nAllow access?\n\nWARNING: If you do not know why this screen appeared, disallow access! You can revoke access later using the \'Registered Applications\' screen.</string>
<string name="api_register_allow">Allow access</string>
<string name="api_register_disallow">Disallow access</string>
<string name="api_register_error_select_key">Please select a key!</string>
<string name="api_select_pub_keys_missing_text">No public keys were found for these user ids:</string>
<string name="api_select_pub_keys_dublicates_text">More than one public key exist for these user ids:</string>
<string name="api_select_pub_keys_text">Please review the list of recipients!</string>
- <string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenPGP Keychain and then register the app again.</string>
+ <string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenKeychain and then register the app again.</string>
<!-- Share -->
<string name="share_qr_code_dialog_title">Share with QR Code</string>
@@ -411,6 +419,9 @@
<!-- Key view -->
<string name="key_view_action_encrypt">Encrypt to this contact</string>
+ <string name="key_view_action_certify">Certify this contact\'s key</string>
+ <string name="key_view_tab_main">Info</string>
+ <string name="key_view_tab_certs">Certifications</string>
<!-- Navigation Drawer -->
<string name="nav_contacts">Contacts</string>