aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-08-28 11:00:18 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-08-28 11:00:18 +0200
commitc0ebc926117d3e444c7c32bf3251880852000df6 (patch)
treeb84926b3eee5cf1cfd6d38a2c3bec23e8f0b6779
parentad69e47cec58287d82978b28416db50f6c3feb77 (diff)
parentb193965e585d0d492cf2744e3c86ecc9e45b71d4 (diff)
downloadopen-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.tar.gz
open-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.tar.bz2
open-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.zip
Merge branch 'master' into yubikey
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
-rw-r--r--.travis.yml4
-rw-r--r--CHANGELOG1
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java495
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java30
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java30
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java25
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java73
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java4
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java20
-rw-r--r--OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc29
-rw-r--r--OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc29
-rw-r--r--OpenKeychain-Test/src/test/resources/cooperpair/readme3
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java38
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java63
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java71
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java131
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java751
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java92
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java38
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java323
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java150
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java56
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java92
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java154
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java58
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java72
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java99
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java65
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java150
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java169
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java27
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java75
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java41
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java334
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java85
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java135
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java232
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java62
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java65
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java29
-rw-r--r--OpenKeychain/src/main/res/layout-large/api_apps_list_activity.xml22
-rw-r--r--OpenKeychain/src/main/res/layout-large/decrypt_activity.xml19
-rw-r--r--OpenKeychain/src/main/res/layout-large/encrypt_activity.xml16
-rw-r--r--OpenKeychain/src/main/res/layout-large/key_list_activity.xml14
-rw-r--r--OpenKeychain/src/main/res/layout/add_subkey_dialog.xml20
-rw-r--r--OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml6
-rw-r--r--OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml10
-rw-r--r--OpenKeychain/src/main/res/layout/certify_key_activity.xml16
-rw-r--r--OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml10
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_content.xml8
-rw-r--r--OpenKeychain/src/main/res/layout/foldable_linearlayout.xml5
-rw-r--r--OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_activity.xml11
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_content.xml18
-rw-r--r--OpenKeychain/src/main/res/layout/keyspinner_key.xml (renamed from OpenKeychain/src/main/res/layout/encrypt_asymmetric_signkey.xml)0
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_activity.xml10
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml59
-rw-r--r--OpenKeychain/src/main/res/menu/key_list.xml6
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_about.html8
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html10
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_start.html22
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_wot.html2
-rw-r--r--OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html8
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_about.html2
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_changelog.html45
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_start.html6
-rw-r--r--OpenKeychain/src/main/res/raw-es/help_changelog.html141
-rw-r--r--OpenKeychain/src/main/res/raw-et/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-fr/help_changelog.html7
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_about.html12
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_changelog.html171
-rw-r--r--OpenKeychain/src/main/res/raw-ja/help_changelog.html5
-rw-r--r--OpenKeychain/src/main/res/raw-nl/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_about.html54
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_changelog.html171
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_nfc_beam.html12
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_start.html22
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_wot.html17
-rw-r--r--OpenKeychain/src/main/res/raw-pt/nfc_beam_share.html11
-rw-r--r--OpenKeychain/src/main/res/raw-ru/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-sl/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-tr/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw-uk/help_about.html20
-rw-r--r--OpenKeychain/src/main/res/raw-uk/help_changelog.html171
-rw-r--r--OpenKeychain/src/main/res/raw-zh/help_changelog.html9
-rw-r--r--OpenKeychain/src/main/res/raw/help_changelog.html1
-rw-r--r--OpenKeychain/src/main/res/values-cs/strings.xml125
-rw-r--r--OpenKeychain/src/main/res/values-de/strings.xml95
-rw-r--r--OpenKeychain/src/main/res/values-es/strings.xml89
-rw-r--r--OpenKeychain/src/main/res/values-et/strings.xml1
-rw-r--r--OpenKeychain/src/main/res/values-fr/strings.xml99
-rw-r--r--OpenKeychain/src/main/res/values-it/strings.xml146
-rw-r--r--OpenKeychain/src/main/res/values-ja/strings.xml71
-rw-r--r--OpenKeychain/src/main/res/values-nl/strings.xml4
-rw-r--r--OpenKeychain/src/main/res/values-pl/strings.xml2
-rw-r--r--OpenKeychain/src/main/res/values-pt/strings.xml44
-rw-r--r--OpenKeychain/src/main/res/values-ru/strings.xml7
-rw-r--r--OpenKeychain/src/main/res/values-sl/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-tr/strings.xml1
-rw-r--r--OpenKeychain/src/main/res/values-uk/strings.xml220
-rw-r--r--OpenKeychain/src/main/res/values-zh/strings.xml1
-rw-r--r--OpenKeychain/src/main/res/values/attr.xml2
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml104
-rw-r--r--OpenKeychain/src/main/res/xml/account_desc.xml7
-rw-r--r--OpenKeychain/src/main/res/xml/adv_preferences.xml17
-rw-r--r--OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml5
-rw-r--r--OpenKeychain/src/main/res/xml/gen_preferences.xml19
-rw-r--r--OpenKeychain/src/main/res/xml/preference_headers.xml17
-rw-r--r--OpenKeychain/src/main/res/xml/preference_headers_legacy.xml17
-rw-r--r--OpenKeychain/src/main/res/xml/sync_adapter_desc.xml10
-rw-r--r--README.md3
-rw-r--r--Resources/graphics/function.pngbin0 -> 97519 bytes
-rw-r--r--Resources/graphics/function.svg4042
m---------extern/KeybaseLib0
m---------extern/StickyListHeaders0
m---------extern/spongycastle0
171 files changed, 9423 insertions, 2095 deletions
diff --git a/.travis.yml b/.travis.yml
index ef69eb556..2cf2f98f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,6 +15,6 @@ before_install:
- ./prepare-tests.sh
install: echo "Installation done"
script:
- - gradle assemble -S -q
- - gradle --info OpenKeychain-Test:testDebug
+ - ./gradlew assemble -S -q
+ - ./gradlew --info OpenKeychain-Test:testDebug
diff --git a/CHANGELOG b/CHANGELOG
index 8804a9c63..196fc9937 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@
* New icons to show status of key (by Brennan Novak)
* Important bug fix: Importing of large key collections from a file is now possible
* Notification showing cached passphrases
+* Keys are connected to Android's contacts
This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 8e7d395fd..6a023c486 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.pgp;
import junit.framework.AssertionFailedError;
@@ -16,11 +34,13 @@ import org.spongycastle.bcpg.SecretSubkeyPacket;
import org.spongycastle.bcpg.SignaturePacket;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
-import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.support.KeyringBuilder;
@@ -31,6 +51,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -42,7 +63,7 @@ import java.util.Random;
public class PgpKeyOperationTest {
static UncachedKeyRing staticRing;
- static String passphrase;
+ final static String passphrase = genPassphrase();
UncachedKeyRing ring;
PgpKeyOperation op;
@@ -50,37 +71,29 @@ public class PgpKeyOperationTest {
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
- @BeforeClass public static void setUpOnce() throws Exception {
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
- {
- String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
- Random r = new Random();
- StringBuilder passbuilder = new StringBuilder();
- // 20% chance for an empty passphrase
- for(int i = 0, j = r.nextInt(10) > 2 ? r.nextInt(20) : 0; i < j; i++) {
- passbuilder.append(chars.charAt(r.nextInt(chars.length())));
- }
- passphrase = passbuilder.toString();
- System.out.println("Passphrase is '" + passphrase + "'");
- }
-
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
parcel.mNewPassphrase = passphrase;
PgpKeyOperation op = new PgpKeyOperation(null);
- staticRing = op.createSecretKeyRing(parcel).getRing();
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+ Assert.assertTrue("initial test key creation must succeed", result.success());
+ Assert.assertNotNull("initial test key creation must succeed", result.getRing());
- Assert.assertNotNull("initial test key creation must succeed", staticRing);
+ staticRing = result.getRing();
// we sleep here for a second, to make sure all new certificates have different timestamps
Thread.sleep(1000);
@@ -107,57 +120,55 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, new Random().nextInt(256)+255, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
-
- Assert.assertNull("creating ring with < 512 bytes keysize should fail", ring);
+ assertFailure("creating ring with < 512 bytes keysize should fail", parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.ELGAMAL, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
-
- Assert.assertNull("creating ring with ElGamal master key should fail", ring);
+ assertFailure("creating ring with ElGamal master key should fail", parcel,
+ LogType.MSG_CR_ERROR_FLAGS_ELGAMAL);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- 12345, 1024, KeyFlags.CERTIFY_OTHER, null));
- parcel.mAddUserIds.add("shy");
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, null));
+ parcel.mAddUserIds.add("lotus");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring with bad algorithm choice should fail", ring);
+ assertFailure("creating master key with null expiry should fail", parcel,
+ LogType.MSG_CR_ERROR_NULL_EXPIRY);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring with non-certifying master key should fail", ring);
+ assertFailure("creating ring with non-certifying master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_CERTIFY);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring without user ids should fail", ring);
+ assertFailure("creating ring without user ids should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_USER_ID);
}
{
@@ -165,8 +176,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- UncachedKeyRing ring = op.createSecretKeyRing(parcel).getRing();
- Assert.assertNull("creating ring without subkeys should fail", ring);
+ assertFailure("creating ring with no master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_MASTER);
}
}
@@ -177,9 +188,9 @@ public class PgpKeyOperationTest {
public void testMasterFlags() throws Exception {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("luna");
- ring = op.createSecretKeyRing(parcel).getRing();
+ ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
Assert.assertEquals("the keyring should contain only the master key",
1, KeyringTestingHelper.itToList(ring.getPublicKeys()).size());
@@ -239,10 +250,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId() -1;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("keyring modification with bad master key id should fail", modified);
+ assertModifyFailure("keyring modification with bad master key id should fail",
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -251,10 +260,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = null;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("keyring modification with null master key id should fail", modified);
+ assertModifyFailure("keyring modification with null master key id should fail",
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -264,10 +271,8 @@ public class PgpKeyOperationTest {
// some byte, off by one
parcel.mFingerprint[5] += 1;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("keyring modification with bad fingerprint should fail", modified);
+ assertModifyFailure("keyring modification with bad fingerprint should fail",
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -275,10 +280,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId();
parcel.mFingerprint = null;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("keyring modification with null fingerprint should fail", modified);
+ assertModifyFailure("keyring modification with null fingerprint should fail",
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -286,10 +289,9 @@ public class PgpKeyOperationTest {
if (badphrase.equals(passphrase)) {
badphrase = "a";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, badphrase).getRing();
- Assert.assertNull("keyring modification with bad passphrase should fail", modified);
+ assertModifyFailure("keyring modification with bad passphrase should fail",
+ ring, parcel, badphrase, LogType.MSG_MF_UNLOCK_ERROR);
}
}
@@ -300,7 +302,7 @@ public class PgpKeyOperationTest {
long expiry = new Date().getTime() / 1000 + 159;
int flags = KeyFlags.SIGN_DATA;
int bits = 1024 + new Random().nextInt(8);
- parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, bits, flags, expiry));
+ parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, bits, null, flags, expiry));
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
@@ -336,28 +338,32 @@ public class PgpKeyOperationTest {
Assert.assertEquals("added key must have expected flags",
flags, newKey.getKeyUsage());
Assert.assertEquals("added key must have expected bitsize",
- bits, newKey.getBitStrength());
+ bits, (int) newKey.getBitStrength());
{ // bad keysize should fail
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, new Random().nextInt(512), null, KeyFlags.SIGN_DATA, 0L));
+ assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
+ }
- Assert.assertNull("creating a subkey with keysize < 512 should fail", modified);
+ {
+ parcel.reset();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, null));
+
+ assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NULL_EXPIRY);
}
{ // a past expiry should fail
parcel.reset();
- parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
+ parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA,
new Date().getTime()/1000-10));
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("creating subkey with past expiry date should fail", modified);
+ assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
}
@@ -394,6 +400,20 @@ public class PgpKeyOperationTest {
ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
}
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
+ }
+
{
int flags = KeyFlags.SIGN_DATA | KeyFlags.ENCRYPT_COMMS;
parcel.reset();
@@ -418,26 +438,169 @@ public class PgpKeyOperationTest {
expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
}
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("old packet must be signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+
+ Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.SUBKEY_BINDING, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
{ // a past expiry should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("setting subkey expiry to a past date should fail", modified);
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
- { // modifying nonexistent keyring should fail
+ { // modifying nonexistent subkey should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
+ assertModifyFailure("modifying non-existent subkey should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_SUBKEY_MISSING);
+ }
+
+ }
+
+ @Test
+ public void testMasterModify() throws Exception {
+
+ long expiry = new Date().getTime()/1000 + 1024;
+ long keyId = ring.getMasterKeyId();
+
+ UncachedKeyRing modified = ring;
+
+ // to make this check less trivial, we add a user id, change the primary one and revoke one
+ parcel.mAddUserIds.add("aloe");
+ parcel.mChangePrimaryUserId = "aloe";
+ parcel.mRevokeUserIds.add("pink");
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ {
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ // this implies that only the two non-revoked signatures were changed!
+ Assert.assertEquals("two extra packets in original", 2, onlyA.size());
+ Assert.assertEquals("two extra packets in modified", 2, onlyB.size());
+
+ Assert.assertEquals("first original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+ Assert.assertEquals("second original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(1).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(0).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(1).tag);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey().getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey().getExpiryTime().getTime() / 1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey().getKeyUsage(), modified.getPublicKey().getKeyUsage());
+ }
+
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
- Assert.assertNull("modifying non-existent subkey should fail", modified);
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
}
+ {
+ int flags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA;
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, flags, null));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("modified key must have expected flags",
+ flags, modified.getPublicKey(keyId).getKeyUsage());
+ Assert.assertNotNull("key must retain its expiry",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("key expiry must be unchanged",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ }
+
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
+ { // if we revoke everything, nothing is left to properly sign...
+ parcel.reset();
+ parcel.mRevokeUserIds.add("twi");
+ parcel.mRevokeUserIds.add("pink");
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.CERTIFY_OTHER, null));
+
+ assertModifyFailure("master key modification with all user ids revoked should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_MASTER_NONE);
+ }
+
+ { // any flag not including CERTIFY_OTHER should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.SIGN_DATA, null));
+
+ assertModifyFailure("setting master key flags without certify should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NO_CERTIFY);
+ }
+
+ { // a past expiry should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
+
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
+ }
+
+ }
+
+ @Test
+ public void testMasterRevoke() throws Exception {
+
+ parcel.reset();
+ parcel.mRevokeSubKeys.add(ring.getMasterKeyId());
+
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("no extra packets in original", 0, onlyA.size());
+ Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());
+
+ Packet p;
+
+ p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be secret subkey", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.KEY_REVOCATION, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertTrue("subkey must actually be revoked",
+ modified.getPublicKey().isRevoked());
+
}
@Test
@@ -555,10 +718,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangePrimaryUserId = uid;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
- UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("setting primary user id to a revoked user id should fail", otherModified);
+ assertModifyFailure("setting primary user id to a revoked user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_REVOKED_PRIMARY);
}
@@ -596,6 +757,14 @@ public class PgpKeyOperationTest {
ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
}
+ { // revocation of non-existent user id should fail
+ parcel.reset();
+ parcel.mRevokeUserIds.add("nonexistent");
+
+ assertModifyFailure("revocation of nonexistent user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_NOEXIST_REVOKE);
+ }
+
}
@Test
@@ -603,9 +772,8 @@ public class PgpKeyOperationTest {
{
parcel.mAddUserIds.add("");
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- UncachedKeyRing modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNull("adding an empty user id should fail", modified);
+ assertModifyFailure("adding an empty user id should fail", ring, parcel,
+ LogType.MSG_MF_UID_ERROR_EMPTY);
}
parcel.reset();
@@ -673,22 +841,87 @@ public class PgpKeyOperationTest {
parcel.mChangePrimaryUserId += "A";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
-
- Assert.assertNull("changing primary user id to a non-existent one should fail", modified);
+ assertModifyFailure("changing primary user id to a non-existent one should fail",
+ ring, parcel, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY);
}
// check for revoked primary user id already done in revoke test
}
+ @Test
+ public void testPassphraseChange() throws Exception {
+
+ // change passphrase to empty
+ parcel.mNewPassphrase = "";
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
+ 3, onlyB.size());
+
+ // remember secret key packet with no passphrase for later
+ RawPacket sKeyNoPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ // modify keyring, change to non-empty passphrase
+ String otherPassphrase = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase;
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, "");
+
+ RawPacket sKeyWithPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ String otherPassphrase2 = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase2;
+ {
+ // if we replace a secret key with one without passphrase
+ modified = KeyringTestingHelper.removePacket(modified, sKeyNoPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyNoPassphrase.buf, sKeyNoPassphrase.position);
+
+ // we should still be able to modify it (and change its passphrase) without errors
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertFalse("log must not contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain an empty passphrase retry notice",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY));
+ modified = result.getRing();
+ }
+
+ {
+ // if we add one subkey with a different passphrase, that should produce a warning but also work
+ modified = KeyringTestingHelper.removePacket(modified, sKeyWithPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position);
+
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase2);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertTrue("log must contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain a failed passphrase change warning",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_FAIL));
+ }
+
+ }
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB) {
- return applyModificationWithChecks(parcel, ring, onlyA, onlyB, true, true);
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
+ }
+
+ private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ UncachedKeyRing ring,
+ ArrayList<RawPacket> onlyA,
+ ArrayList<RawPacket> onlyB,
+ String passphrase) {
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
}
// applies a parcel modification while running some integrity checks
@@ -696,6 +929,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
+ String passphrase,
boolean canonicalize,
boolean constantCanonicalize) {
@@ -705,8 +939,10 @@ public class PgpKeyOperationTest {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
PgpKeyOperation op = new PgpKeyOperation(null);
- UncachedKeyRing rawModified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
- Assert.assertNotNull("key modification failed", rawModified);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+ Assert.assertTrue("key modification must succeed", result.success());
+ UncachedKeyRing rawModified = result.getRing();
+ Assert.assertNotNull("key modification must not return null", rawModified);
if (!canonicalize) {
Assert.assertTrue("keyring must differ from original", KeyringTestingHelper.diffKeyrings(
@@ -753,10 +989,75 @@ public class PgpKeyOperationTest {
*/
@Test
public void testConcat() throws Exception {
- byte[] actual = TestDataUtil.concatAll(new byte[]{1}, new byte[]{2,-2}, new byte[]{5},new byte[]{3});
+ byte[] actual = TestDataUtil.concatAll(new byte[]{1}, new byte[]{2, -2}, new byte[]{5}, new byte[]{3});
byte[] expected = new byte[]{1,2,-2,5,3};
Assert.assertEquals(java.util.Arrays.toString(expected), java.util.Arrays.toString(actual));
}
+ private void assertFailure(String reason, SaveKeyringParcel parcel, LogType expected) {
+
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
+
+ }
+
+ private void assertModifyFailure(String reason, UncachedKeyRing ring,
+ SaveKeyringParcel parcel, String passphrase, LogType expected)
+ throws Exception {
+
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
+
+ }
+
+ private void assertModifyFailure(String reason, UncachedKeyRing ring, SaveKeyringParcel parcel,
+ LogType expected)
+ throws Exception {
+
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
+
+ Assert.assertFalse(reason, result.success());
+ Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
+
+ }
+
+ private UncachedKeyRing assertCreateSuccess(String reason, SaveKeyringParcel parcel) {
+
+ EditKeyResult result = op.createSecretKeyRing(parcel);
+
+ Assert.assertTrue(reason, result.success());
+ Assert.assertNotNull(reason, result.getRing());
+
+ return result.getRing();
+
+ }
+
+ private static String genPassphrase() {
+ return genPassphrase(false);
+ }
+
+ private static String genPassphrase(boolean noEmpty) {
+ String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
+ Random r = new Random();
+ StringBuilder passbuilder = new StringBuilder();
+ // 20% chance for an empty passphrase
+ for(int i = 0, j = noEmpty || r.nextInt(10) > 2 ? r.nextInt(20)+1 : 0; i < j; i++) {
+ passbuilder.append(chars.charAt(r.nextInt(chars.length())));
+ }
+ System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
+ return passbuilder.toString();
+ }
}
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 535e9d01a..5792e8326 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.pgp;
import org.junit.BeforeClass;
@@ -13,6 +31,7 @@ import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -30,10 +49,12 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import java.io.ByteArrayInputStream;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -60,15 +81,16 @@ public class UncachedKeyringCanonicalizeTest {
@BeforeClass
public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -277,7 +299,7 @@ public class UncachedKeyringCanonicalizeTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("trix");
PgpKeyOperation op = new PgpKeyOperation(null);
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index 6e9381c06..64152a040 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.pgp;
import org.junit.Assert;
@@ -10,14 +28,17 @@ import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Iterator;
@@ -59,14 +80,15 @@ public class UncachedKeyringMergeTest {
@BeforeClass
public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -83,7 +105,7 @@ public class UncachedKeyringMergeTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
// passphrase is tested in PgpKeyOperationTest, just use empty here
@@ -189,7 +211,7 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
index cbd1bc502..636dae90c 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.pgp;
import org.junit.Assert;
@@ -13,6 +31,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import java.io.ByteArrayInputStream;
@@ -37,11 +56,11 @@ public class UncachedKeyringTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
new file mode 100644
index 000000000..b5d950f59
--- /dev/null
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.provider;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLog;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+@RunWith(RobolectricTestRunner.class)
+@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
+public class ProviderHelperSaveTest {
+
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ ShadowLog.stream = System.out;
+ }
+
+ @Test
+ public void testLongKeyIdCollision() throws Exception {
+
+ UncachedKeyRing first =
+ readRingFromResource("/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc");
+ UncachedKeyRing second =
+ readRingFromResource("/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc");
+
+ SaveKeyringResult result;
+
+ // insert both keys, second should fail
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(first);
+ Assert.assertTrue("first keyring import should succeed", result.success());
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(second);
+ Assert.assertFalse("second keyring import should fail", result.success());
+
+ new KeychainDatabase(Robolectric.application).clearDatabase();
+
+ // and the other way around
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(second);
+ Assert.assertTrue("first keyring import should succeed", result.success());
+ result = new ProviderHelper(Robolectric.application).savePublicKeyRing(first);
+ Assert.assertFalse("second keyring import should fail", result.success());
+
+ }
+
+ UncachedKeyRing readRingFromResource(String name) throws Exception {
+ return UncachedKeyRing.fromStream(ProviderHelperSaveTest.class.getResourceAsStream(name)).next();
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
index 015e134ea..c0ba3c9bb 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) Art O Cathain, Vincent Breitmoser
+ * Copyright (C) Art O Cathain
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -14,6 +15,7 @@
* 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.support;
import android.content.Context;
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
index b5708b46f..c5b53e95b 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * 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.util;
import android.os.Bundle;
@@ -25,7 +43,7 @@ public class FileImportCacheTest {
@Test
public void testInputOutput() throws Exception {
- FileImportCache<Bundle> cache = new FileImportCache<Bundle>(Robolectric.application);
+ FileImportCache<Bundle> cache = new FileImportCache<Bundle>(Robolectric.application, "test.pcl");
ArrayList<Bundle> list = new ArrayList<Bundle>();
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc b/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc
new file mode 100644
index 000000000..4f51252da
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF.asc
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBFJtd/UBEACpw/psXoGNM8RHczviD7FnGdjMQPEJQ+nuWQ2AEGYouulg5hFv
+0ChuSQVLiqQht2k5K2liyW1MeXoJ8tr9nSn/Zi9nttc0Wo6K7pvrDD40r2HNg305
+qLCzItr5st3x8cq2cIXvN4LOm2rqpBLZ/sqMmNiW2Y7/aAQqV1xtR35joHqamWHD
+UPOmzBMs07YSUjXgC1EMx8kWQSV6cuARj93kxWj8R6eoYHHfrWCEGR313wov6QST
+zIfVU7FqQqOmdLW3LaPHxcrI/TjsnkUN99qdlpjJH/YW925LDPJHAkliqPP5AvhU
+F9KbY2F8mcIZBCDd8TH+xXynuN3BbIU4kCwVbdx/tcpO1npuJcKB1Go/udyow/Ei
+Z3nHzJsCVkezvopek77wnwPaP0nAb7f4iIY3gJCoGirOx6N075TgF6MBe00q9oFE
+y4rvnUnU9/QzOOes95eUMhM+9eK1cuLFEV5t47DfxRdq+fQip3FJ2l6v19sZvQ0G
+j06pjYqg0of273rG8oXcDrFjb1Zqhj8x1mLl6u7d/ide5wTm9HylBWcYKQjIJJAi
+WIScxEPIOINDJKgsKTuKtoyNvISJ3xUeS1yzxiIb3YGLIyPgFFx0vFyqJfbkXq70
+m1n2xnJlkTidfzbZvc6EA7vRGSDYK6FqqhlGhc7UypUEVW8FM/jZNAOS6QARAUGt
+tCg5RTY2OTg2MTM2OEJDQTBCRTQyREFGN0REREEyNTJFQkI4RUJFMUFGiQI3BBMB
+CgAhBQJSg/uTAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEN2iUuu46+Gv
++Z0P+wQhkLwm+WGcEsS98Lei9O7hit/k4g/VkLUUQV7BOR3n8uRZIFkdOtpvrFU3
+aKf246uCy6GM48Oh+1U2cv5InX/WEuKaFo5uF6t79wyt18BUn1weDcU+DQdOSG4f
+fSnNa55wkN0l0svW4fGIthjmDTz6HZFntYD+9A20wZAqpPIs+vyG9Jp+e9E9Y/W/
+EFQbNlxHHb9+BMT2+DtNP+HSl3MPFlQPKOLZxyLAU5uzT0Sa0LxhrQy5FgkW6Jog
+sbAJVM9z0pZw+grzGPciM66ZW1rxeICvbYsdWLytRjqxpY8GS8XudyseUGd+dZim
+ptarsrE5yfSMg2gW5Z1PTc0tEMXJLUwtpyzQjpFpbb7dPuo2TUp09LgZKX63WCbS
+Nb1RTaGfkeYudOTo2rh4Jfg+Tb/JRpO6clo0rxAq8nPH2WmG+9TB8Zbb7YRzGWuV
+/e5SeVNR+zY8tXZKnmUIH1HIprc+BtT6Bupdvd0CT14Mg9MmsFvUXofwHLa4gahr
+8/iG9y3uHSA6Rhz++yOpyOmNvO1LDxsYNaRCIXQJbqgNwF5YNYlMPsEeY/CG7FOb
+Afv7rHiYtRRQfz2P4OF900DJO7QL9gdNXJ1+Hajy/5Lvvl7qwqMG4GvVQEsgFc5O
+jjFCUhE2i20j2kEMxvA5RLBH/fOoGARn87tiKSfb+pqLNZQb
+=fDJ8
+-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc b/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc
new file mode 100644
index 000000000..549bc51a2
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/A55120427374F3F7AA5F1166DDA252EBB8EBE1AF.asc
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBFKD+38BEADSv5l4xOx9hCRJVcybq6yK5hTpGSFf3xo1bkhoMvyC62ehb4jD
+MDLwwNRyzCBEWQJLbq/LLizPFN2qXFJpXJcsuqsHNYRtDqDBEjtriRQwSqHnqTXt
+c0K46FYHldCJQ4/tBXxPI+WwtXjcNRWaV7n2BvR/Jk+B5e4Zz3LPnN0C4w5vORHs
+hN1jil8A3Hs/F+OmlQYrU8ZtNwTpSo2EXxe2fVgSDCsKRyNsPZj++OyujPzW+yaN
+lJ9I/q6s9gvX9o9o7nwZbqBETipWsdRK6RfBdTKpnyLNordbWwWTk6GxN8T5Ppit
+P6a3UlQ71VuflcswCTmEQ1pEfZrlRFKa9psBOW+cZLNxT9h0jGFMh6/B3w48Sag+
+cFcPBFWParC+cAXBIURDxT9G6bzNLogg7YKoaPsyiXnLDH2VJUCXs27D2wPJL24Q
+S7npvsg63MPPssWgG5cauLznmNR4y5pQi6oH/C10v0zrUJy6FPJzQhYRhWOvhtz6
+j88RGMrFNNCdB2VACtn699D+ixu3nRlXHIKCT+xLSfgslVYifmJOCNljBLGHOQ1e
+FJxQuNVpmmxjvk/8kqK+pHLB9Qn6M1ZYzip7OyUL3OAWabCabgEw2bQmUhiBWD3u
+buv0WAVOJEAFvBCAeYNQzrQMY+Rc3RnvynG4pI6Tbo8wC6/IJcDOw516JwARASB3
+tChBNTUxMjA0MjczNzRGM0Y3QUE1RjExNjZEREEyNTJFQkI4RUJFMUFGiQI3BBMB
+CgAhBQJSg/uTAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEN2iUuu46+Gv
+9L0P/3tFu0LOZ/dAPjUNfKJCZqcIuVnD5xShMTsUbVx+QoXMy7rt4iRLD7ofGi/I
+vTAZehxk3sk/Slx5nbews+3NItyw6mcaP9HlmwKNr6k7BC2kJHcCxH4DNzhmIx1H
+3T/CggtHX42JBYKlGf22y+M8jAbvsPOUfTznx96mYNrOY6s1dJyn0kRleqJ8+tGj
+/5+0y90iZnGCa0FtacQkKUPkXwVodeZVxk8z5OEipShYKc+8dl+5WsvOzHqLC/KY
+xCGRb4JaqEMwouLNg8dTNAXXUvFGqJNDX4+andggogmI1hdD9xExfSU9cAGegg2t
+vvveC4S+CCHd+zt88iK5ze6F61RxwYhhNbkuFGjdgNGCpHtG/BQhKnYJuKEbq3oi
+mgNyxJERlfgaWXveiMG0AmACXN+jCkTtqZjQnsg2N2QDL3tjY7usmuiwRL1aVOFG
+Kw5/Cc+2nDeANS3Xi1403Ni269b1c6kNSoLe4zd0WsbO3Kouds8F8EQfeheXQe97
+ZxuvBOMsR9wHC3f0sl/vfxCGdUC+khmKk5taKnUeUFJmVmh5ghlVy8FySHGB0QHO
+zd8GUl59rFpQJNpNFQW2YKDhrcjxIr2AeJrdoDI6NsQ02+Qtep/bbq53hqtAD4jF
+t3S8vBbTXtRk6g2qn4ojF4SOIc8SAiZcURgVFuSJX8ngFbO4
+=OEw/
+-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file
diff --git a/OpenKeychain-Test/src/test/resources/cooperpair/readme b/OpenKeychain-Test/src/test/resources/cooperpair/readme
new file mode 100644
index 000000000..fecb372d9
--- /dev/null
+++ b/OpenKeychain-Test/src/test/resources/cooperpair/readme
@@ -0,0 +1,3 @@
+"Cooperpair" testcase under public domain license, by @coruus:
+
+https://github.com/coruus/cooperpair/tree/master/pgpv4
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index c10629c6d..e14fb44ba 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -3,8 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.sufficientlysecure.keychain"
android:installLocation="auto"
- android:versionCode="27000"
- android:versionName="2.7">
+ android:versionCode="28000"
+ android:versionName="2.8">
<!--
General remarks
@@ -176,7 +176,7 @@
android:label="@string/title_decrypt"
android:windowSoftInputMode="stateHidden">
- <!-- VIEW with mimeType application/pgp-encrypted -->
+ <!-- VIEW with mimeType application/octet-stream, application/pgp and text/pgp -->
<intent-filter android:label="@string/intent_send_decrypt">
<action android:name="android.intent.action.VIEW" />
@@ -184,7 +184,9 @@
<category android:name="android.intent.category.DEFAULT" />
<!-- mime type as defined in http://tools.ietf.org/html/rfc3156 -->
- <data android:mimeType="application/pgp-encrypted" />
+ <data android:mimeType="application/octet-stream" />
+ <data android:mimeType="application/pgp" />
+ <data android:mimeType="text/pgp" />
</intent-filter>
<!-- Keychain's own Actions -->
<!-- DECRYPT with text as extra -->
@@ -557,6 +559,10 @@
android:value=".ui.KeyListActivity" />
</activity>
<activity
+ android:name=".ui.ConsolidateDialogActivity"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:label="@string/app_name" />
+ <activity
android:name=".ui.HelpActivity"
android:label="@string/title_help" />
@@ -628,7 +634,10 @@
android:resource="@xml/account_desc" />
</service>
- <service android:name=".service.ContactSyncAdapterService">
+ <service
+ android:name=".service.ContactSyncAdapterService"
+ android:exported="true"
+ android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 755d74ac2..9f84da815 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -35,6 +35,9 @@ public final class Constants {
public static final String PACKAGE_NAME = "org.sufficientlysecure.keychain";
+ public static final String ACCOUNT_NAME = "OpenKeychain";
+ public static final String ACCOUNT_TYPE = PACKAGE_NAME + ".account";
+
// as defined in http://tools.ietf.org/html/rfc3156, section 7
public static final String NFC_MIME = "application/pgp-keys";
@@ -68,11 +71,14 @@ public final class Constants {
public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion";
public static final String WRITE_VERSION_HEADER = "writeVersionHeader";
public static final String FIRST_TIME = "firstTime";
+ public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
+ public static final String CACHED_CONSOLIDATE_SECRETS = "cachedConsolidateSecrets";
+ public static final String CACHED_CONSOLIDATE_PUBLICS = "cachedConsolidatePublics";
}
public static final class Defaults {
- public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, subkeys.pgp.net, hkps://pgp.mit.edu";
- public static final int KEY_SERVERS_VERSION = 2;
+ public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, hkps://pgp.mit.edu";
+ public static final int KEY_SERVERS_VERSION = 3;
}
public static final class DrawerItems {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 9b9880533..57d74967b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -20,15 +20,20 @@ package org.sufficientlysecure.keychain;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Application;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Environment;
+import android.provider.ContactsContract;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.helper.TlsHelper;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes;
@@ -89,14 +94,37 @@ public class KeychainApplication extends Application {
TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");
TemporaryStorageProvider.cleanUp(this);
+
+ checkConsolidateRecovery();
+
+ }
+
+ public void checkConsolidateRecovery() {
+
+ // restart consolidate process if it has been interruped before
+ if (Preferences.getPreferences(this).getCachedConsolidate()) {
+ // do something which calls ProviderHelper.consolidateDatabaseStep2 with a progressable
+ Intent consolidateIntent = new Intent(this, ConsolidateDialogActivity.class);
+ consolidateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(consolidateIntent);
+ }
+
}
public static void setupAccountAsNeeded(Context context) {
- AccountManager manager = AccountManager.get(context);
- Account[] accounts = manager.getAccountsByType(Constants.PACKAGE_NAME);
- if (accounts == null || accounts.length == 0) {
- Account dummy = new Account(context.getString(R.string.app_name), Constants.PACKAGE_NAME);
- manager.addAccountExplicitly(dummy, null, null);
+ // only enabled for Jelly Bean because we need some newer methods in our sync adapter
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ AccountManager manager = AccountManager.get(context);
+ Account[] accounts = manager.getAccountsByType(Constants.ACCOUNT_TYPE);
+ if (accounts == null || accounts.length == 0) {
+ Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
+ if (manager.addAccountExplicitly(account, null, null)) {
+ ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);
+ ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
+ } else {
+ Log.e(Constants.TAG, "Adding account failed!");
+ }
+ }
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
index 8697e49f7..016d6dc14 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.helper;
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.annotation.TargetApi;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -234,6 +235,25 @@ public class ContactHelper {
return new ArrayList<String>(mails);
}
+ public static List<String> getContactNames(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,
+ new String[]{ContactsContract.Contacts.DISPLAY_NAME},
+ null, null, null);
+ if (cursor == null) return null;
+
+ Set<String> names = new HashSet<String>();
+ while (cursor.moveToNext()) {
+ String name = cursor.getString(0);
+ if (name != null) {
+ names.add(name);
+ }
+ }
+ cursor.close();
+ return new ArrayList<String>(names);
+ }
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static Uri dataUriFromContactUri(Context context, Uri contactUri) {
Cursor contactMasterKey = context.getContentResolver().query(contactUri,
new String[]{ContactsContract.Data.DATA2}, null, null, null, null);
@@ -323,7 +343,7 @@ public class ContactHelper {
// Delete fingerprints that are no longer present in OK
for (String fingerprint : contactFingerprints) {
resolver.delete(ContactsContract.RawContacts.CONTENT_URI, ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION,
- new String[]{Constants.PACKAGE_NAME, fingerprint});
+ new String[]{Constants.ACCOUNT_TYPE, fingerprint});
}
}
@@ -334,7 +354,7 @@ public class ContactHelper {
private static Set<String> getRawContactFingerprints(ContentResolver resolver) {
HashSet<String> result = new HashSet<String>();
Cursor fingerprints = resolver.query(ContactsContract.RawContacts.CONTENT_URI, SOURCE_ID_PROJECTION,
- ACCOUNT_TYPE_SELECTION, new String[]{Constants.PACKAGE_NAME}, null);
+ ACCOUNT_TYPE_SELECTION, new String[]{Constants.ACCOUNT_TYPE}, null);
if (fingerprints != null) {
while (fingerprints.moveToNext()) {
result.add(fingerprints.getString(0));
@@ -349,10 +369,11 @@ public class ContactHelper {
*
* @return raw contact id or -1 if not found
*/
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static int findRawContactId(ContentResolver resolver, String fingerprint) {
int rawContactId = -1;
Cursor raw = resolver.query(ContactsContract.RawContacts.CONTENT_URI, ID_PROJECTION,
- ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION, new String[]{Constants.PACKAGE_NAME, fingerprint}, null, null);
+ ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION, new String[]{Constants.ACCOUNT_TYPE, fingerprint}, null, null);
if (raw != null) {
if (raw.moveToNext()) {
rawContactId = raw.getInt(0);
@@ -367,8 +388,8 @@ public class ContactHelper {
*/
private static void insertContact(ArrayList<ContentProviderOperation> ops, Context context, String fingerprint) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
- .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, context.getString(R.string.app_name))
- .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.PACKAGE_NAME)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.SOURCE_ID, fingerprint)
.build());
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 72e88d793..5190a550e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -25,7 +25,12 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Constants.Pref;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ListIterator;
import java.util.Vector;
/**
@@ -130,6 +135,36 @@ public class Preferences {
editor.commit();
}
+ public boolean getCachedConsolidate() {
+ return mSharedPreferences.getBoolean(Pref.CACHED_CONSOLIDATE, false);
+ }
+
+ public void setCachedConsolidate(boolean value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putBoolean(Pref.CACHED_CONSOLIDATE, value);
+ editor.commit();
+ }
+
+ public int getCachedConsolidateNumPublics() {
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_PUBLICS, -1);
+ }
+
+ public void setCachedConsolidateNumPublics(int value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putInt(Pref.CACHED_CONSOLIDATE_PUBLICS, value);
+ editor.commit();
+ }
+
+ public int getCachedConsolidateNumSecrets() {
+ return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_SECRETS, -1);
+ }
+
+ public void setCachedConsolidateNumSecrets(int value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putInt(Pref.CACHED_CONSOLIDATE_SECRETS, value);
+ editor.commit();
+ }
+
public boolean isFirstTime() {
return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
}
@@ -175,15 +210,24 @@ public class Preferences {
// migrate keyserver to hkps
if (mSharedPreferences.getInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, 0) !=
Constants.Defaults.KEY_SERVERS_VERSION) {
- String[] servers = getKeyServers();
- for (int i = 0; i < servers.length; i++) {
- if (servers[i].equals("pool.sks-keyservers.net")) {
- servers[i] = "hkps://hkps.pool.sks-keyservers.net";
- } else if (servers[i].equals("pgp.mit.edu")) {
- servers[i] = "hkps://pgp.mit.edu";
+ String[] serversArray = getKeyServers();
+ ArrayList<String> servers = new ArrayList<String>(Arrays.asList(serversArray));
+ ListIterator<String> it = servers.listIterator();
+ while (it.hasNext()) {
+ String server = it.next();
+ if (server.equals("pool.sks-keyservers.net")) {
+ // use HKPS!
+ it.set("hkps://hkps.pool.sks-keyservers.net");
+ } else if (server.equals("pgp.mit.edu")) {
+ // use HKPS!
+ it.set("hkps://pgp.mit.edu");
+ } else if (server.equals("subkeys.pgp.net")) {
+ // remove, because often down and no HKPS!
+ it.remove();
}
+
}
- setKeyServers(servers);
+ setKeyServers(servers.toArray(new String[servers.size()]));
mSharedPreferences.edit()
.putInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, Constants.Defaults.KEY_SERVERS_VERSION)
.commit();
@@ -193,6 +237,11 @@ public class Preferences {
if (mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, 0) == 0x21070001) {
setDefaultFileCompression(CompressionAlgorithmTags.UNCOMPRESSED);
}
+
+ // migrate away from MD5
+ if (mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, 0) == HashAlgorithmTags.MD5) {
+ setDefaultHashAlgorithm(HashAlgorithmTags.SHA512);
+ }
}
public void setWriteVersionHeader(boolean conceal) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index f617be62a..e30401180 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -24,8 +24,10 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Log;
-import java.io.DataOutputStream;
+import java.io.BufferedWriter;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -281,7 +283,7 @@ public class HkpKeyserver extends Keyserver {
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
final int algorithmId = Integer.decode(matcher.group(2));
- entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId));
+ entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId, null, null));
// group 1 contains the full fingerprint (v4) or the long key id if available
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
@@ -352,25 +354,38 @@ public class HkpKeyserver extends Keyserver {
@Override
public void add(String armoredKey) throws AddKeyException {
try {
- String query = getUrlPrefix() + mHost + ":" + mPort + "/pks/add";
+ String request = "/pks/add";
String params;
try {
- params = "keytext=" + URLEncoder.encode(armoredKey, "utf8");
+ params = "keytext=" + URLEncoder.encode(armoredKey, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AddKeyException();
}
- Log.d(Constants.TAG, "hkp keyserver add: " + query);
-
- HttpURLConnection connection = openConnection(new URL(query));
- connection.setRequestMethod("POST");
- connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- connection.setRequestProperty("Content-Length", Integer.toString(params.getBytes().length));
- connection.setDoOutput(true);
- DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
- wr.writeBytes(params);
- wr.flush();
- wr.close();
+ URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + request);
+
+ Log.d(Constants.TAG, "hkp keyserver add: " + url.toString());
+ Log.d(Constants.TAG, "params: " + params);
+
+ HttpURLConnection conn = openConnection(url);
+ conn.setRequestMethod("POST");
+ conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ conn.setRequestProperty("Content-Length", Integer.toString(params.getBytes().length));
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+
+ OutputStream os = conn.getOutputStream();
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
+ writer.write(params);
+ writer.flush();
+ writer.close();
+ os.close();
+
+ conn.connect();
+
+ Log.d(Constants.TAG, "response code: " + conn.getResponseCode());
+ Log.d(Constants.TAG, "answer: " + readAll(conn.getInputStream(), conn.getContentEncoding()));
} catch (IOException e) {
+ Log.e(Constants.TAG, "IOException", e);
throw new AddKeyException();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
index 30e93f957..da70f1505 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
@@ -39,7 +39,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
private boolean mExpired;
private Date mDate; // TODO: not displayed
private String mFingerprintHex;
- private int mBitStrength;
+ private Integer mBitStrength;
+ private String mCurveOid;
private String mAlgorithm;
private boolean mSecretKey;
private String mPrimaryUserId;
@@ -162,10 +163,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.mFingerprintHex = fingerprintHex;
}
- public int getBitStrength() {
+ public Integer getBitStrength() {
return mBitStrength;
}
+ public String getCurveOid() {
+ return mCurveOid;
+ }
+
public void setBitStrength(int bitStrength) {
this.mBitStrength = bitStrength;
}
@@ -258,13 +263,15 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mPrimaryUserId = mUserIds.get(0);
}
- this.mKeyId = key.getKeyId();
- this.mKeyIdHex = PgpKeyHelper.convertKeyIdToHex(mKeyId);
+ mKeyId = key.getKeyId();
+ mKeyIdHex = PgpKeyHelper.convertKeyIdToHex(mKeyId);
- this.mRevoked = key.isRevoked();
- this.mFingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
- this.mBitStrength = key.getBitStrength();
+ mRevoked = key.isRevoked();
+ mFingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
+ mBitStrength = key.getBitStrength();
+ mCurveOid = key.getCurveOid();
final int algorithm = key.getAlgorithm();
- this.mAlgorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm);
+ mAlgorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm, mBitStrength, mCurveOid);
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index 0ca6f07fd..cbd06da90 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -75,7 +75,7 @@ public class KeybaseKeyserver extends Keyserver {
entry.setExtraData(username);
final int algorithmId = match.getAlgorithmId();
- entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId));
+ entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId, null, null));
final int bitStrength = match.getBitStrength();
entry.setBitStrength(bitStrength);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
index 8609a7082..55e6be9b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index 1da66872d..8076a14f3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
index ce6498df1..7a63a7a42 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index 972e45c2e..2c27c5c37 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -60,10 +61,6 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
return mRing;
}
- public void encode(ArmoredOutputStream stream) throws IOException {
- getRing().encode(stream);
- }
-
/** Getter that returns the subkey that should be used for signing. */
CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index 877857553..c79dc45c3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
index 4f74a2336..d8b873d31 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
index 35020b815..3ef4b336e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index 7d113241b..828bee848 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -523,13 +523,7 @@ public class PgpDecryptVerify {
// update signature buffer if signature is also present
if (signature != null) {
- try {
- signature.update(buffer, 0, length);
- } catch (SignatureException e) {
- Log.e(Constants.TAG, "SignatureException -> Not a valid signature!", e);
- signatureResultBuilder.validSignature(false);
- signature = null;
- }
+ signature.update(buffer, 0, length);
}
alreadyWritten += length;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
index 1cf027721..db360f810 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
@@ -29,7 +29,6 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
import java.util.regex.Pattern;
@@ -68,76 +67,6 @@ public class PgpHelper {
}
}
-// public static final class content {
-// public static final int unknown = 0;
-// public static final int encrypted_data = 1;
-// public static final int keys = 2;
-// }
-//
-// public static int getStreamContent(Context context, InputStream inStream) throws IOException {
-//
-// InputStream in = PGPUtil.getDecoderStream(inStream);
-// PGPObjectFactory pgpF = new PGPObjectFactory(in);
-// Object object = pgpF.nextObject();
-// while (object != null) {
-// if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
-// return Id.content.keys;
-// } else if (object instanceof PGPEncryptedDataList) {
-// return Id.content.encrypted_data;
-// }
-// object = pgpF.nextObject();
-// }
-//
-// return Id.content.unknown;
-// }
-
- /**
- * Generate a random filename
- *
- * @param length
- * @return
- */
- public static String generateRandomFilename(int length) {
- SecureRandom random = new SecureRandom();
-
- byte bytes[] = new byte[length];
- random.nextBytes(bytes);
- String result = "";
- for (int i = 0; i < length; ++i) {
- int v = (bytes[i] + 256) % 64;
- if (v < 10) {
- result += (char) ('0' + v);
- } else if (v < 36) {
- result += (char) ('A' + v - 10);
- } else if (v < 62) {
- result += (char) ('a' + v - 36);
- } else if (v == 62) {
- result += '_';
- } else if (v == 63) {
- result += '.';
- }
- }
- return result;
- }
-
- /**
- * Go once through stream to get length of stream. The length is later used to display progress
- * when encrypting/decrypting
- *
- * @param in
- * @return
- * @throws IOException
- */
- public static long getLengthOfStream(InputStream in) throws IOException {
- long size = 0;
- long n = 0;
- byte dummy[] = new byte[0x10000];
- while ((n = in.read(dummy)) > 0) {
- size += n;
- }
- return size;
- }
-
/**
* Deletes file securely by overwriting it with random data before deleting it.
* <p/>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index f14eacda2..0bc3ac0ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -43,6 +44,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
public class PgpImportExport {
@@ -60,10 +62,14 @@ public class PgpImportExport {
private ProviderHelper mProviderHelper;
public PgpImportExport(Context context, Progressable progressable) {
+ this(context, new ProviderHelper(context), progressable);
+ }
+
+ public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable) {
super();
this.mContext = context;
this.mProgressable = progressable;
- this.mProviderHelper = new ProviderHelper(context);
+ this.mProviderHelper = providerHelper;
}
public PgpImportExport(Context context,
@@ -93,7 +99,7 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
+ public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) throws AddKeyException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
@@ -103,13 +109,9 @@ public class PgpImportExport {
String armoredKey = bos.toString("UTF-8");
server.add(armoredKey);
-
- return true;
} catch (IOException e) {
- return false;
- } catch (AddKeyException e) {
- // TODO: tell the user?
- return false;
+ Log.e(Constants.TAG, "IOException", e);
+ throw new AddKeyException();
} finally {
try {
if (aos != null) {
@@ -124,20 +126,23 @@ public class PgpImportExport {
/** Imports keys from given data. If keyIds is given only those are imported */
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
+ return importKeyRings(entries.iterator(), entries.size());
+ }
+ public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
- if (entries == null || entries.size() == 0) {
+ if (entries == null || !entries.hasNext()) {
return new ImportKeyResult(
- ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
+ ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0, 0);
}
- int newKeys = 0, oldKeys = 0, badKeys = 0;
+ int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;
int position = 0;
- int progSteps = 100 / entries.size();
- for (ParcelableKeyRing entry : entries) {
+ double progSteps = 100.0 / num;
+ for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) {
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -157,10 +162,10 @@ public class PgpImportExport {
SaveKeyringResult result;
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
}
if (!result.success()) {
badKeys += 1;
@@ -168,6 +173,9 @@ public class PgpImportExport {
oldKeys += 1;
} else {
newKeys += 1;
+ if (key.isSecret()) {
+ secret += 1;
+ }
}
} catch (IOException e) {
@@ -204,7 +212,7 @@ public class PgpImportExport {
}
}
- return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys);
+ return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
index 459b80be2..05acb86df 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
@@ -24,10 +24,16 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.util.Log;
import java.security.DigestException;
@@ -37,18 +43,14 @@ import java.util.Locale;
public class PgpKeyHelper {
- public static String getAlgorithmInfo(int algorithm) {
- return getAlgorithmInfo(null, algorithm, 0);
- }
-
- public static String getAlgorithmInfo(Context context, int algorithm) {
- return getAlgorithmInfo(context, algorithm, 0);
+ public static String getAlgorithmInfo(int algorithm, Integer keySize, String oid) {
+ return getAlgorithmInfo(null, algorithm, keySize, oid);
}
/**
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
*/
- public static String getAlgorithmInfo(Context context, int algorithm, int keySize) {
+ public static String getAlgorithmInfo(Context context, int algorithm, Integer keySize, String oid) {
String algorithmStr;
switch (algorithm) {
@@ -69,10 +71,19 @@ public class PgpKeyHelper {
break;
}
- case PublicKeyAlgorithmTags.ECDSA:
+ case PublicKeyAlgorithmTags.ECDSA: {
+ if (oid == null) {
+ return "ECDSA";
+ }
+ String oidName = PgpKeyHelper.getCurveInfo(context, oid);
+ return "ECDSA (" + oidName + ")";
+ }
case PublicKeyAlgorithmTags.ECDH: {
- algorithmStr = "ECC";
- break;
+ if (oid == null) {
+ return "ECDH";
+ }
+ String oidName = PgpKeyHelper.getCurveInfo(context, oid);
+ return "ECDH (" + oidName + ")";
}
default: {
@@ -90,6 +101,106 @@ public class PgpKeyHelper {
return algorithmStr;
}
+ public static String getAlgorithmInfo(Algorithm algorithm, Integer keySize, Curve curve) {
+ return getAlgorithmInfo(null, algorithm, keySize, curve);
+ }
+
+ /**
+ * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
+ */
+ public static String getAlgorithmInfo(Context context, Algorithm algorithm, Integer keySize, Curve curve) {
+ String algorithmStr;
+
+ switch (algorithm) {
+ case RSA: {
+ algorithmStr = "RSA";
+ break;
+ }
+ case DSA: {
+ algorithmStr = "DSA";
+ break;
+ }
+
+ case ELGAMAL: {
+ algorithmStr = "ElGamal";
+ break;
+ }
+
+ case ECDSA: {
+ algorithmStr = "ECDSA";
+ if (curve != null) {
+ algorithmStr += " (" + getCurveInfo(context, curve) + ")";
+ }
+ return algorithmStr;
+ }
+ case ECDH: {
+ algorithmStr = "ECDH";
+ if (curve != null) {
+ algorithmStr += " (" + getCurveInfo(context, curve) + ")";
+ }
+ return algorithmStr;
+ }
+
+ default: {
+ if (context != null) {
+ algorithmStr = context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ algorithmStr = "unknown";
+ }
+ break;
+ }
+ }
+ if (keySize != null && keySize > 0)
+ return algorithmStr + ", " + keySize + " bit";
+ else
+ return algorithmStr;
+ }
+
+ // Return name of a curve. These are names, no need for translation
+ public static String getCurveInfo(Context context, Curve curve) {
+ switch(curve) {
+ case NIST_P256:
+ return "NIST P-256";
+ case NIST_P384:
+ return "NIST P-384";
+ case NIST_P521:
+ return "NIST P-521";
+
+ /* see SaveKeyringParcel
+ case BRAINPOOL_P256:
+ return "Brainpool P-256";
+ case BRAINPOOL_P384:
+ return "Brainpool P-384";
+ case BRAINPOOL_P512:
+ return "Brainpool P-512";
+ */
+ }
+ if (context != null) {
+ return context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ return "unknown";
+ }
+ }
+
+ public static String getCurveInfo(Context context, String oidStr) {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(oidStr);
+
+ String name;
+ name = NISTNamedCurves.getName(oid);
+ if (name != null) {
+ return name;
+ }
+ name = TeleTrusTNamedCurves.getName(oid);
+ if (name != null) {
+ return name;
+ }
+ if (context != null) {
+ return context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ return "unknown";
+ }
+ }
+
/**
* Converts fingerprint to hex
* <p/>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index bb692555e..967a7caa9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -20,12 +20,12 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPKeyFlags;
import org.spongycastle.openpgp.PGPKeyPair;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
@@ -34,7 +34,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
@@ -53,6 +52,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -67,6 +68,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SignatureException;
+import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
@@ -84,15 +86,45 @@ import java.util.Stack;
public class PgpKeyOperation {
private Stack<Progressable> mProgress;
+ // most preferred is first
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
- SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
- SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
- SymmetricKeyAlgorithmTags.TRIPLE_DES};
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1,
- HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160};
+ SymmetricKeyAlgorithmTags.AES_256,
+ SymmetricKeyAlgorithmTags.AES_192,
+ SymmetricKeyAlgorithmTags.AES_128,
+ SymmetricKeyAlgorithmTags.CAST5
+ };
+ private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{
+ HashAlgorithmTags.SHA512,
+ HashAlgorithmTags.SHA384,
+ HashAlgorithmTags.SHA224,
+ HashAlgorithmTags.SHA256,
+ HashAlgorithmTags.RIPEMD160
+ };
private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
- CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP};
+ CompressionAlgorithmTags.ZLIB,
+ CompressionAlgorithmTags.BZIP2,
+ CompressionAlgorithmTags.ZIP
+ };
+
+ /*
+ * Note: s2kcount is a number between 0 and 0xff that controls the
+ * number of times to iterate the password hash before use. More
+ * iterations are useful against offline attacks, as it takes more
+ * time to check each password. The actual number of iterations is
+ * rather complex, and also depends on the hash function in use.
+ * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give
+ * you more iterations. As a rough rule of thumb, when using
+ * SHA256 as the hashing function, 0x10 gives you about 64
+ * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0,
+ * or about 1 million iterations. The maximum you can go to is
+ * 0xff, or about 2 million iterations. I'll use 0xc0 as a
+ * default -- about 130,000 iterations.
+ *
+ * http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html
+ */
+ private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512;
+ private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
+ private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x60;
public PgpKeyOperation(Progressable progress) {
super();
@@ -126,31 +158,65 @@ public class PgpKeyOperation {
mProgress.peek().setProgress(message, current, 100);
}
+ private ECGenParameterSpec getEccParameterSpec(Curve curve) {
+ switch (curve) {
+ case NIST_P256: return new ECGenParameterSpec("P-256");
+ case NIST_P384: return new ECGenParameterSpec("P-384");
+ case NIST_P521: return new ECGenParameterSpec("P-521");
+
+ // @see SaveKeyringParcel
+ // case BRAINPOOL_P256: return new ECGenParameterSpec("brainpoolp256r1");
+ // case BRAINPOOL_P384: return new ECGenParameterSpec("brainpoolp384r1");
+ // case BRAINPOOL_P512: return new ECGenParameterSpec("brainpoolp512r1");
+ }
+ throw new RuntimeException("Invalid choice! (can't happen)");
+ }
+
/** Creates new secret key. */
- private PGPKeyPair createKey(int algorithmChoice, int keySize, OperationLog log, int indent) {
+ private PGPKeyPair createKey(SubkeyAdd add, OperationLog log, int indent) {
try {
- if (keySize < 512) {
- log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
- return null;
+ // Some safety checks
+ if (add.mAlgorithm == Algorithm.ECDH || add.mAlgorithm == Algorithm.ECDSA) {
+ if (add.mCurve == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CURVE, indent);
+ return null;
+ }
+ } else {
+ if (add.mKeySize == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_KEYSIZE, indent);
+ return null;
+ }
+ if (add.mKeySize < 512) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
+ return null;
+ }
}
int algorithm;
KeyPairGenerator keyGen;
- switch (algorithmChoice) {
- case PublicKeyAlgorithmTags.DSA: {
+ switch (add.mAlgorithm) {
+ case DSA: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_DSA, indent);
+ return null;
+ }
progress(R.string.progress_generating_dsa, 30);
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
+ keyGen.initialize(add.mKeySize, new SecureRandom());
algorithm = PGPPublicKey.DSA;
break;
}
- case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: {
+ case ELGAMAL: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ELGAMAL, indent);
+ return null;
+ }
progress(R.string.progress_generating_elgamal, 30);
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- BigInteger p = Primes.getBestPrime(keySize);
+ BigInteger p = Primes.getBestPrime(add.mKeySize);
BigInteger g = new BigInteger("2");
ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
@@ -160,15 +226,44 @@ public class PgpKeyOperation {
break;
}
- case PublicKeyAlgorithmTags.RSA_GENERAL: {
+ case RSA: {
progress(R.string.progress_generating_rsa, 30);
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
+ keyGen.initialize(add.mKeySize, new SecureRandom());
algorithm = PGPPublicKey.RSA_GENERAL;
break;
}
+ case ECDSA: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDSA, indent);
+ return null;
+ }
+ progress(R.string.progress_generating_ecdsa, 30);
+ ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
+ keyGen = KeyPairGenerator.getInstance("ECDSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(ecParamSpec, new SecureRandom());
+
+ algorithm = PGPPublicKey.ECDSA;
+ break;
+ }
+
+ case ECDH: {
+ // make sure there are no sign or certify flags set
+ if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDH, indent);
+ return null;
+ }
+ progress(R.string.progress_generating_ecdh, 30);
+ ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
+ keyGen = KeyPairGenerator.getInstance("ECDH", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(ecParamSpec, new SecureRandom());
+
+ algorithm = PGPPublicKey.ECDH;
+ break;
+ }
+
default: {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
return null;
@@ -181,7 +276,8 @@ public class PgpKeyOperation {
} catch(NoSuchProviderException e) {
throw new RuntimeException(e);
} catch(NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
+ return null;
} catch(InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch(PGPException e) {
@@ -218,13 +314,13 @@ public class PgpKeyOperation {
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- if (add.mAlgorithm == PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT) {
- log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NULL_EXPIRY, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
subProgressPush(10, 30);
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ PGPKeyPair keyPair = createKey(add, log, indent);
subProgressPop();
// return null if this failed (an error will already have been logged by createKey)
@@ -234,13 +330,16 @@ public class PgpKeyOperation {
progress(R.string.progress_building_master_key, 40);
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
// Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+
+ // NOTE: only SHA1 is supported for key checksum calculations.
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, true, keyEncryptor);
@@ -248,7 +347,7 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100);
- return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log);
+ return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@@ -314,14 +413,17 @@ public class PgpKeyOperation {
// read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER
- int masterKeyFlags = readKeyFlags(masterSecretKey.getPublicKey()) | KeyFlags.CERTIFY_OTHER;
+ PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
+ int masterKeyFlags = readKeyFlags(masterPublicKey) | KeyFlags.CERTIFY_OTHER;
+ long masterKeyExpiry = masterPublicKey.getValidSeconds() == 0L ? 0L :
+ masterPublicKey.getCreationTime().getTime() / 1000 + masterPublicKey.getValidSeconds();
- return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log);
+ return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log);
}
private EditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
- int masterKeyFlags,
+ int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase,
OperationLog log) {
@@ -346,177 +448,196 @@ public class PgpKeyOperation {
}
}
- // work on master secret key
try {
- PGPPublicKey modifiedPublicKey = masterPublicKey;
+ { // work on master secret key
- // 2a. Add certificates for new user ids
- subProgressPush(15, 25);
- for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
- progress(R.string.progress_modify_adduid, (i-1) * (100 / saveParcel.mAddUserIds.size()));
- String userId = saveParcel.mAddUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
+ // 2a. Add certificates for new user ids
+ subProgressPush(15, 25);
+ for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
- if (userId.equals("")) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent+1);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
+ progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
+ String userId = saveParcel.mAddUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
- // this operation supersedes all previous binding and revocation certificates,
- // so remove those to retain assertions from canonicalization for later operations
- @SuppressWarnings("unchecked")
- Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
- if (it != null) {
- for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
- || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, cert);
- }
+ if (userId.equals("")) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- }
- // if it's supposed to be primary, we can do that here as well
- boolean isPrimary = saveParcel.mChangePrimaryUserId != null
- && userId.equals(saveParcel.mChangePrimaryUserId);
- // generate and add new certificate
- PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, isPrimary, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
+ // this operation supersedes all previous binding and revocation certificates,
+ // so remove those to retain assertions from canonicalization for later operations
+ @SuppressWarnings("unchecked")
+ Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
+ if (it != null) {
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
+ || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, cert);
+ }
+ }
+ }
- // 2b. Add revocations for revoked user ids
- subProgressPush(25, 40);
- for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+ // if it's supposed to be primary, we can do that here as well
+ boolean isPrimary = saveParcel.mChangePrimaryUserId != null
+ && userId.equals(saveParcel.mChangePrimaryUserId);
+ // generate and add new certificate
+ PGPSignature cert = generateUserIdSignature(masterPrivateKey,
+ masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
- progress(R.string.progress_modify_revokeuid, (i-1) * (100 / saveParcel.mRevokeUserIds.size()));
- String userId = saveParcel.mRevokeUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+ // 2b. Add revocations for revoked user ids
+ subProgressPush(25, 40);
+ for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+
+ progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
+ String userId = saveParcel.mRevokeUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+
+ // Make sure the user id exists (yes these are 10 LoC in Java!)
+ boolean exists = false;
+ //noinspection unchecked
+ for (String uid : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ if (userId.equals(uid)) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
- // a duplicate revocation will be removed during canonicalization, so no need to
- // take care of that here.
- PGPSignature cert = generateRevocationSignature(masterPrivateKey,
- masterPublicKey, userId);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
+ // a duplicate revocation will be removed during canonicalization, so no need to
+ // take care of that here.
+ PGPSignature cert = generateRevocationSignature(masterPrivateKey,
+ masterPublicKey, userId);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
- // 3. If primary user id changed, generate new certificates for both old and new
- if (saveParcel.mChangePrimaryUserId != null) {
- progress(R.string.progress_modify_primaryuid, 40);
+ // 3. If primary user id changed, generate new certificates for both old and new
+ if (saveParcel.mChangePrimaryUserId != null) {
+ progress(R.string.progress_modify_primaryuid, 40);
- // keep track if we actually changed one
- boolean ok = false;
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
- indent += 1;
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
+ indent += 1;
- // we work on the modifiedPublicKey here, to respect new or newly revoked uids
- // noinspection unchecked
- for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
- boolean isRevoked = false;
- PGPSignature currentCert = null;
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
// noinspection unchecked
- for (PGPSignature cert : new IterableIterator<PGPSignature>(
- modifiedPublicKey.getSignaturesForID(userId))) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
+ for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- // we know from canonicalization that if there is any revocation here, it
- // is valid and not superseded by a newer certification.
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
- isRevoked = true;
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ // revoked user ids cannot be primary!
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
continue;
}
- // we know from canonicalization that there is only one binding
- // certification here, so we can just work with the first one.
- if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- currentCert = cert;
- }
- }
- if (currentCert == null) {
- // no certificate found?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
- // we definitely should not update certifications of revoked keys, so just leave it.
- if (isRevoked) {
- // revoked user ids cannot be primary!
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ // if this is~ the/a primary user id
+ if (currentCert.getHashedSubPackets() != null
+ && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ // if it's the one we want, just leave it as is
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ ok = true;
+ continue;
+ }
+ // otherwise, generate new non-primary certification
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, false,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ continue;
}
- continue;
- }
- // if this is~ the/a primary user id
- if (currentCert.getHashedSubPackets() != null
- && currentCert.getHashedSubPackets().isPrimaryUserID()) {
- // if it's the one we want, just leave it as is
+ // if we are here, this is not currently a primary user id
+
+ // if it should be
if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ // add shiny new primary user id certificate
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, true,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
ok = true;
- continue;
}
- // otherwise, generate new non-primary certification
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, false, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- continue;
- }
- // if we are here, this is not currently a primary user id
-
- // if it should be
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- // add shiny new primary user id certificate
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- ok = true;
+ // user id is not primary and is not supposed to be - nothing to do here.
+
}
- // user id is not primary and is not supposed to be - nothing to do here.
+ indent -= 1;
+ if (!ok) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
}
- indent -= 1;
-
- if (!ok) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ // Update the secret key ring
+ if (modifiedPublicKey != masterPublicKey) {
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
+ masterPublicKey = modifiedPublicKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
- }
- // Update the secret key ring
- if (modifiedPublicKey != masterPublicKey) {
- masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
- masterPublicKey = modifiedPublicKey;
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
// 4a. For each subkey change, generate new subkey binding certificate
@@ -528,27 +649,47 @@ public class PgpKeyOperation {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- // TODO allow changes in master key? this implies generating new user id certs...
- if (change.mKeyId == masterPublicKey.getKeyID()) {
- Log.e(Constants.TAG, "changing the master key not supported");
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- PGPPublicKey pKey = sKey.getPublicKey();
// expiry must not be in the past
- if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
+ if (change.mExpiry != null && change.mExpiry != 0 &&
+ new Date(change.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ // if this is the master key, update uid certificates instead
+ if (change.mKeyId == masterPublicKey.getKeyID()) {
+ int flags = change.mFlags == null ? masterKeyFlags : change.mFlags;
+ long expiry = change.mExpiry == null ? masterKeyExpiry : change.mExpiry;
+
+ if ((flags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NO_CERTIFY, indent + 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ PGPPublicKey pKey =
+ updateMasterCertificates(masterPrivateKey, masterPublicKey,
+ flags, expiry, indent, log);
+ if (pKey == null) {
+ // error log entry has already been added by updateMasterCertificates itself
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, pKey);
+ masterPublicKey = pKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
+ continue;
+ }
+
+ // otherwise, continue working on the public key
+ PGPPublicKey pKey = sKey.getPublicKey();
+
// keep old flags, or replace with new ones
int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
long expiry;
@@ -565,7 +706,7 @@ public class PgpKeyOperation {
//noinspection unchecked
for (PGPSignature sig : new IterableIterator<PGPSignature>(pKey.getSignatures())) {
// special case: if there is a revocation, don't use expiry from before
- if (change.mExpiry == null
+ if ( (change.mExpiry == null || change.mExpiry == 0L)
&& sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
expiry = 0;
}
@@ -591,7 +732,7 @@ public class PgpKeyOperation {
PGPSecretKey sKey = sKR.getSecretKey(revocation);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -611,10 +752,16 @@ public class PgpKeyOperation {
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent,
+ PgpKeyHelper.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
+
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
- if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
+ if (add.mExpiry > 0L && new Date(add.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -623,9 +770,10 @@ public class PgpKeyOperation {
(i-1) * (100 / saveParcel.mAddSubKeys.size()),
i * (100 / saveParcel.mAddSubKeys.size())
);
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ PGPKeyPair keyPair = createKey(add, log, indent);
subProgressPop();
- if(keyPair == null) {
+ if (keyPair == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -633,21 +781,21 @@ public class PgpKeyOperation {
PGPPublicKey pKey = keyPair.getPublicKey();
PGPSignature cert = generateSubkeyBindingSignature(
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
- add.mFlags, add.mExpiry == null ? 0 : add.mExpiry);
+ add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
PGPSecretKey sKey; {
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
-
// Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
- sha1Calc, false, keyEncryptor);
+ // NOTE: only SHA1 is supported for key checksum calculations.
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+ sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
}
log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
@@ -662,21 +810,67 @@ public class PgpKeyOperation {
if (saveParcel.mNewPassphrase != null) {
progress(R.string.progress_modify_passphrase, 90);
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(HashAlgorithmTags.SHA1);
+ indent += 1;
+
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
+ .get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
// Build key encryptor based on new passphrase
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
saveParcel.mNewPassphrase.toCharArray());
- sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
+ // noinspection unchecked
+ for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_KEY, indent,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+
+ boolean ok = false;
+
+ try {
+ // try to set new passphrase
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, keyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e) {
+
+ // if this is the master key, error!
+ if (sKey.getKeyID() == masterPublicKey.getKeyID()) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PASSPHRASE_MASTER, indent+1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ // being in here means decrypt failed, likely due to a bad passphrase try
+ // again with an empty passphrase, maybe we can salvage this
+ try {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY, indent+1);
+ PBESecretKeyDecryptor emptyDecryptor =
+ new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, emptyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e2) {
+ // non-fatal but not ok, handled below
+ }
+ }
+
+ if (!ok) {
+ // for a subkey, it's merely a warning
+ log.add(LogLevel.WARN, LogType.MSG_MF_PASSPHRASE_FAIL, indent+1,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+ continue;
+ }
+
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
+
+ }
+
+ indent -= 1;
}
- // This one must only be thrown by
} catch (IOException e) {
+ Log.e(Constants.TAG, "encountered IOException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (PGPException e) {
@@ -684,6 +878,7 @@ public class PgpKeyOperation {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (SignatureException e) {
+ Log.e(Constants.TAG, "encountered SignatureException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SIG, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -694,21 +889,121 @@ public class PgpKeyOperation {
}
+ /** Update all (non-revoked) uid signatures with new flags and expiry time. */
+ private static PGPPublicKey updateMasterCertificates(
+ PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
+ int flags, long expiry, int indent, OperationLog log)
+ throws PGPException, IOException, SignatureException {
+
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_MASTER, indent);
+ indent += 1;
+
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
+
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
+ // noinspection unchecked
+ for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ continue;
+ }
+
+ // add shiny new user id certificate
+ boolean isPrimary = currentCert.getHashedSubPackets() != null &&
+ currentCert.getHashedSubPackets().isPrimaryUserID();
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ ok = true;
+
+ }
+
+ if (!ok) {
+ // might happen, theoretically, if there is a key with no uid..
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_MASTER_NONE, indent);
+ return null;
+ }
+
+ return modifiedPublicKey;
+
+ }
+
private static PGPSignature generateUserIdSignature(
- PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary, int flags)
+ PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
+ int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
- PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
- subHashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
- subHashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
- subHashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
- subHashedPacketsGen.setPrimaryUserID(false, primary);
- subHashedPacketsGen.setKeyFlags(false, flags);
- sGen.setHashedSubpackets(subHashedPacketsGen.generate());
+
+ PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ {
+ /*
+ * From RFC about critical subpackets:
+ * If a subpacket is encountered that is
+ * marked critical but is unknown to the evaluating software, the
+ * evaluator SHOULD consider the signature to be in error.
+ * An evaluator may "recognize" a subpacket, but not implement it. The
+ * purpose of the critical bit is to allow the signer to tell an
+ * evaluator that it would prefer a new, unknown feature to generate an
+ * error than be ignored.
+ */
+ /* non-critical subpackets: */
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
+ hashedPacketsGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
+ hashedPacketsGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
+ hashedPacketsGen.setPrimaryUserID(false, primary);
+
+ /* critical subpackets: we consider those important for a modern pgp implementation */
+ hashedPacketsGen.setSignatureCreationTime(true, new Date());
+ // Request that senders add the MDC to the message (authenticate unsigned messages)
+ hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
+ hashedPacketsGen.setKeyFlags(true, flags);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(
+ true, expiry - pKey.getCreationTime().getTime() / 1000);
+ }
+ }
+
+ sGen.setHashedSubpackets(hashedPacketsGen.generate());
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
}
@@ -717,11 +1012,11 @@ public class PgpKeyOperation {
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
@@ -731,11 +1026,11 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
@@ -765,38 +1060,38 @@ public class PgpKeyOperation {
throws IOException, PGPException, SignatureException {
// date for signing
- Date todayDate = new Date();
+ Date creationTime = new Date();
+
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature
if ((flags & KeyFlags.SIGN_DATA) > 0) {
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, todayDate);
+ subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ pKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
- unhashedPacketsGen.setEmbeddedSignature(false, certification);
+ unhashedPacketsGen.setEmbeddedSignature(true, certification);
}
PGPSignatureSubpacketGenerator hashedPacketsGen;
{
hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- hashedPacketsGen.setSignatureCreationTime(false, todayDate);
- hashedPacketsGen.setKeyFlags(false, flags);
- }
-
- if (expiry > 0) {
- long creationTime = pKey.getCreationTime().getTime() / 1000;
- hashedPacketsGen.setKeyExpirationTime(false, expiry - creationTime);
+ hashedPacketsGen.setSignatureCreationTime(true, creationTime);
+ hashedPacketsGen.setKeyFlags(true, flags);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(true,
+ expiry - pKey.getCreationTime().getTime() / 1000);
+ }
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index 3fe535f65..2e4eafe41 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -70,7 +70,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId;
private int mSignatureHashAlgorithm;
private String mSignaturePassphrase;
- private boolean mEncryptToSigner;
+ private long mAdditionalEncryptId;
private boolean mCleartextInput;
private String mOriginalFilename;
@@ -103,7 +103,7 @@ public class PgpSignEncrypt {
this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
- this.mEncryptToSigner = builder.mEncryptToSigner;
+ this.mAdditionalEncryptId = builder.mAdditionalEncryptId;
this.mCleartextInput = builder.mCleartextInput;
this.mNfcSignedHash = builder.mNfcSignedHash;
this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp;
@@ -127,7 +127,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId = Constants.key.none;
private int mSignatureHashAlgorithm = 0;
private String mSignaturePassphrase = null;
- private boolean mEncryptToSigner = false;
+ private long mAdditionalEncryptId = Constants.key.none;
private boolean mCleartextInput = false;
private String mOriginalFilename = "";
private byte[] mNfcSignedHash = null;
@@ -175,7 +175,7 @@ public class PgpSignEncrypt {
}
public Builder setSignatureMasterKeyId(long signatureMasterKeyId) {
- this.mSignatureMasterKeyId = signatureMasterKeyId;
+ mSignatureMasterKeyId = signatureMasterKeyId;
return this;
}
@@ -192,11 +192,11 @@ public class PgpSignEncrypt {
/**
* Also encrypt with the signing keyring
*
- * @param encryptToSigner
+ * @param additionalEncryptId
* @return
*/
- public Builder setEncryptToSigner(boolean encryptToSigner) {
- mEncryptToSigner = encryptToSigner;
+ public Builder setAdditionalEncryptId(long additionalEncryptId) {
+ mAdditionalEncryptId = additionalEncryptId;
return this;
}
@@ -288,10 +288,10 @@ public class PgpSignEncrypt {
+ "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
- // add signature key id to encryption ids (self-encrypt)
- if (enableEncryption && enableSignature && mEncryptToSigner) {
+ // add additional key id to encryption ids (mostly to do self-encryption)
+ if (enableEncryption && mAdditionalEncryptId != Constants.key.none) {
mEncryptionMasterKeyIds = Arrays.copyOf(mEncryptionMasterKeyIds, mEncryptionMasterKeyIds.length + 1);
- mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId;
+ mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mAdditionalEncryptId;
}
ArmoredOutputStream armorOut = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 73a51942d..f00383e0f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -44,6 +45,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
@@ -55,7 +58,8 @@ import java.util.TreeSet;
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
* used to move around pgp key rings in non crypto related (UI, mostly) code.
* It should be used for simple inspection only until it saved in the database,
- * all actual crypto operations should work with WrappedKeyRings exclusively.
+ * all actual crypto operations should work with CanonicalizedKeyRings
+ * exclusively.
*
* This class is also special in that it can hold either the PGPPublicKeyRing
* or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are
@@ -118,6 +122,10 @@ public class UncachedKeyRing {
return mRing.getPublicKey().getFingerprint();
}
+ public int getVersion() {
+ return mRing.getPublicKey().getVersion();
+ }
+
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
@@ -211,8 +219,7 @@ public class UncachedKeyRing {
aos.close();
}
- /** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
- * applied to public keyrings only.
+ /** "Canonicalizes" a public key, removing inconsistencies in the process.
*
* More specifically:
* - Remove all non-verifying self-certificates
@@ -229,9 +236,9 @@ public class UncachedKeyRing {
* - If the key is a secret key, remove all certificates by foreign keys
* - If no valid user id remains, log an error and return null
*
- * This operation writes an OperationLog which can be used as part of a OperationResultParcel.
+ * This operation writes an OperationLog which can be used as part of an OperationResultParcel.
*
- * @return A canonicalized key, or null on fatal error
+ * @return A canonicalized key, or null on fatal error (log will include a message in this case)
*
*/
@SuppressWarnings("ConstantConditions")
@@ -241,6 +248,12 @@ public class UncachedKeyRing {
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
indent += 1;
+ // do not accept v3 keys
+ if (getVersion() <= 3) {
+ log.add(LogLevel.ERROR, LogType.MSG_KC_V3_KEY, indent);
+ return null;
+ }
+
final Date now = new Date();
int redundantCerts = 0, badCerts = 0;
@@ -259,13 +272,12 @@ public class UncachedKeyRing {
for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getKeySignatures())) {
int type = zert.getSignatureType();
- // Disregard certifications on user ids, we will deal with those later
+ // These should most definitely not be here...
if (type == PGPSignature.NO_CERTIFICATION
|| type == PGPSignature.DEFAULT_CERTIFICATION
|| type == PGPSignature.CASUAL_CERTIFICATION
|| type == PGPSignature.POSITIVE_CERTIFICATION
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
- // These should not be here...
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE_UID, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
badCerts += 1;
@@ -328,7 +340,17 @@ public class UncachedKeyRing {
}
}
+ ArrayList<String> processedUserIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
+ // check for duplicate user ids
+ if (processedUserIds.contains(userId)) {
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_DUP,
+ indent, userId);
+ // strip out the first found user id with this name
+ modified = PGPPublicKey.removeCertification(modified, userId);
+ }
+ processedUserIds.add(userId);
+
PGPSignature selfCert = null;
revocation = null;
@@ -405,13 +427,13 @@ public class UncachedKeyRing {
if (selfCert == null) {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
redundantCerts += 1;
selfCert = zert;
} else {
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
redundantCerts += 1;
@@ -474,6 +496,10 @@ public class UncachedKeyRing {
// Replace modified key in the keyring
ring = replacePublicKey(ring, modified);
+ if (ring == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
indent -= 1;
}
@@ -580,8 +606,8 @@ public class UncachedKeyRing {
}
- // if we already have a cert, and this one is not newer: skip it
- if (selfCert != null && selfCert.getCreationTime().before(cert.getCreationTime())) {
+ // if we already have a cert, and this one is older: skip it
+ if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
redundantCerts += 1;
continue;
@@ -641,6 +667,10 @@ public class UncachedKeyRing {
}
// replace pubkey in keyring
ring = replacePublicKey(ring, modified);
+ if (ring == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
indent -= 1;
}
@@ -681,8 +711,9 @@ public class UncachedKeyRing {
long masterKeyId = other.getMasterKeyId();
- if (getMasterKeyId() != masterKeyId) {
- log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);
+ if (getMasterKeyId() != masterKeyId
+ || !Arrays.equals(getFingerprint(), other.getFingerprint())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_HETEROGENEOUS, indent);
return null;
}
@@ -729,6 +760,10 @@ public class UncachedKeyRing {
} else {
// otherwise, just insert the public key
result = replacePublicKey(result, key);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
continue;
}
@@ -757,6 +792,10 @@ public class UncachedKeyRing {
if (!key.isMasterKey()) {
if (modified != resultKey) {
result = replacePublicKey(result, modified);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
continue;
}
@@ -781,6 +820,10 @@ public class UncachedKeyRing {
// If anything changed, save the updated (sub)key
if (modified != resultKey) {
result = replacePublicKey(result, modified);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
}
@@ -795,7 +838,7 @@ public class UncachedKeyRing {
return new UncachedKeyRing(result);
} catch (IOException e) {
- log.add(LogLevel.ERROR, LogType.MSG_MG_FATAL_ENCODE, indent);
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_ENCODE, indent);
return null;
}
@@ -826,16 +869,19 @@ public class UncachedKeyRing {
*/
private static PGPKeyRing replacePublicKey(PGPKeyRing ring, PGPPublicKey key) {
if (ring instanceof PGPPublicKeyRing) {
- return PGPPublicKeyRing.insertPublicKey((PGPPublicKeyRing) ring, key);
- }
- PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
- PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
- // TODO generate secret key with S2K dummy, if none exists! for now, just die.
- if (sKey == null) {
- throw new RuntimeException("dummy secret key generation not yet implemented");
+ PGPPublicKeyRing pubRing = (PGPPublicKeyRing) ring;
+ return PGPPublicKeyRing.insertPublicKey(pubRing, key);
+ } else {
+ PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
+ PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
+ // TODO generate secret key with S2K dummy, if none exists!
+ if (sKey == null) {
+ Log.e(Constants.TAG, "dummy secret key generation not yet implemented");
+ return null;
+ }
+ sKey = PGPSecretKey.replacePublicKey(sKey, key);
+ return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
- sKey = PGPSecretKey.replacePublicKey(sKey, key);
- return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
/** This method removes a subkey in a keyring.
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
index 341ca6d04..c7a8bb1d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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,6 +18,10 @@
package org.sufficientlysecure.keychain.pgp;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
@@ -93,10 +98,23 @@ public class UncachedPublicKey {
return mPublicKey.getAlgorithm();
}
- public int getBitStrength() {
+ public Integer getBitStrength() {
+ if (isEC()) {
+ return null;
+ }
return mPublicKey.getBitStrength();
}
+ public String getCurveOid() {
+ if ( ! isEC()) {
+ return null;
+ }
+ if ( ! (mPublicKey.getPublicKeyPacket().getKey() instanceof ECPublicBCPGKey)) {
+ return null;
+ }
+ return ((ECPublicBCPGKey) mPublicKey.getPublicKeyPacket().getKey()).getCurveOID().getId();
+ }
+
/** Returns the primary user id, as indicated by the public key's self certificates.
*
* This is an expensive operation, since potentially a lot of certificates (and revocations)
@@ -185,6 +203,10 @@ public class UncachedPublicKey {
return getAlgorithm() == PGPPublicKey.DSA;
}
+ public boolean isEC() {
+ return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA;
+ }
+
@SuppressWarnings("unchecked")
// TODO make this safe
public int getKeyUsage() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
index 8dc28c2b3..4dfd93289 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
index ebd110dc5..f24259ba7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -95,9 +96,6 @@ public class WrappedSignature {
} catch (PGPException e) {
// no matter
Log.e(Constants.TAG, "exception reading embedded signatures", e);
- } catch (IOException e) {
- // no matter
- Log.e(Constants.TAG, "exception reading embedded signatures", e);
}
return sigs;
}
@@ -149,27 +147,17 @@ public class WrappedSignature {
}
}
- public void update(byte[] data, int offset, int length) throws PgpGeneralException {
- try {
- mSig.update(data, offset, length);
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
- }
+ public void update(byte[] data, int offset, int length) {
+ mSig.update(data, offset, length);
}
- public void update(byte data) throws PgpGeneralException {
- try {
- mSig.update(data);
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
- }
+ public void update(byte data) {
+ mSig.update(data);
}
public boolean verify() throws PgpGeneralException {
try {
return mSig.verify();
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
} catch(PGPException e) {
throw new PgpGeneralException(e);
}
@@ -178,8 +166,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key) throws PgpGeneralException {
try {
return mSig.verifyCertification(key);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -188,8 +174,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey masterKey, PGPPublicKey subKey) throws PgpGeneralException {
try {
return mSig.verifyCertification(masterKey, subKey);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -198,8 +182,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key, String uid) throws PgpGeneralException {
try {
return mSig.verifyCertification(uid, key);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Error!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
index 3700b4c34..aa0d86bb3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
index e076fd9cc..21f0dddf6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
index dd59f8603..4f6e878b4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -38,6 +39,7 @@ public class KeychainContract {
String FINGERPRINT = "fingerprint";
String KEY_SIZE = "key_size";
+ String KEY_CURVE_OID = "key_curve_oid";
String CAN_SIGN = "can_sign";
String CAN_ENCRYPT = "can_encrypt";
String CAN_CERTIFY = "can_certify";
@@ -111,6 +113,7 @@ public class KeychainContract {
public static final String HAS_ANY_SECRET = "has_any_secret";
public static final String HAS_ENCRYPT = "has_encrypt";
public static final String HAS_SIGN = "has_sign";
+ public static final String HAS_CERTIFY = "has_certify";
public static final String PUBKEY_DATA = "pubkey_data";
public static final String PRIVKEY_DATA = "privkey_data";
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 3a859f505..0bb43d47f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -51,7 +52,7 @@ import java.io.IOException;
*/
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "openkeychain.db";
- private static final int DATABASE_VERSION = 2;
+ private static final int DATABASE_VERSION = 3;
static Boolean apgHack = false;
public interface Tables {
@@ -85,6 +86,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ KeysColumns.KEY_ID + " INTEGER, "
+ KeysColumns.KEY_SIZE + " INTEGER, "
+ + KeysColumns.KEY_CURVE_OID + " TEXT, "
+ KeysColumns.ALGORITHM + " INTEGER, "
+ KeysColumns.FINGERPRINT + " BLOB, "
@@ -201,13 +203,20 @@ public class KeychainDatabase extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion == 1) {
- // add has_secret for all who are upgrading from a beta version
- try {
- db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");
- } catch (Exception e) {
- // never mind, the column probably already existed
- }
+ // add has_secret for all who are upgrading from a beta version
+ switch (oldVersion) {
+ case 1:
+ try {
+ db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");
+ } catch(Exception e){
+ // never mind, the column probably already existed
+ }
+ case 2:
+ try {
+ db.execSQL("ALTER TABLE keys ADD COLUMN " + KeysColumns.KEY_CURVE_OID + " TEXT");
+ } catch(Exception e){
+ // never mind, the column probably already existed
+ }
}
}
@@ -227,7 +236,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {
if (db.equals("apg.db")) {
hasApgDb = true;
} else if (db.equals("apg_old.db")) {
- Log.d(Constants.TAG, "Found apg_old.db");
+ Log.d(Constants.TAG, "Found apg_old.db, delete it!");
+ context.getDatabasePath("apg_old.db").delete();
}
}
}
@@ -310,9 +320,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {
}
}
- // Move to a different file (but don't delete, just to be safe)
- Log.d(Constants.TAG, "All done - moving apg.db to apg_old.db");
- context.getDatabasePath("apg.db").renameTo(context.getDatabasePath("apg_old.db"));
+ // delete old database
+ context.getDatabasePath("apg.db").delete();
}
private static void copy(File in, File out) throws IOException {
@@ -349,4 +358,9 @@ public class KeychainDatabase extends SQLiteOpenHelper {
copy(in, out);
}
+ // DANGEROUS, use in test code ONLY!
+ public void clearDatabase() {
+ getWritableDatabase().execSQL("delete from " + Tables.KEY_RINGS_PUBLIC);
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index c914cb5b7..f6df4a3eb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -245,6 +246,7 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID);
projectionMap.put(KeyRings.KEY_SIZE, Tables.KEYS + "." + Keys.KEY_SIZE);
+ projectionMap.put(KeyRings.KEY_CURVE_OID, Tables.KEYS + "." + Keys.KEY_CURVE_OID);
projectionMap.put(KeyRings.IS_REVOKED, Tables.KEYS + "." + Keys.IS_REVOKED);
projectionMap.put(KeyRings.CAN_CERTIFY, Tables.KEYS + "." + Keys.CAN_CERTIFY);
projectionMap.put(KeyRings.CAN_ENCRYPT, Tables.KEYS + "." + Keys.CAN_ENCRYPT);
@@ -271,6 +273,8 @@ public class KeychainProvider extends ContentProvider {
"kE." + Keys.KEY_ID + " AS " + KeyRings.HAS_ENCRYPT);
projectionMap.put(KeyRings.HAS_SIGN,
"kS." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN);
+ projectionMap.put(KeyRings.HAS_CERTIFY,
+ "kC." + Keys.KEY_ID + " AS " + KeyRings.HAS_CERTIFY);
projectionMap.put(KeyRings.IS_EXPIRED,
"(" + Tables.KEYS + "." + Keys.EXPIRY + " IS NOT NULL AND " + Tables.KEYS + "." + Keys.EXPIRY
+ " < " + new Date().getTime() / 1000 + ") AS " + KeyRings.IS_EXPIRED);
@@ -324,6 +328,15 @@ public class KeychainProvider extends ContentProvider {
+ " AND ( kS." + Keys.EXPIRY + " IS NULL OR kS." + Keys.EXPIRY
+ " >= " + new Date().getTime() / 1000 + " )"
+ ")" : "")
+ + (plist.contains(KeyRings.HAS_CERTIFY) ?
+ " LEFT JOIN " + Tables.KEYS + " AS kC ON ("
+ +"kC." + Keys.MASTER_KEY_ID
+ + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " AND kC." + Keys.IS_REVOKED + " = 0"
+ + " AND kC." + Keys.CAN_CERTIFY + " = 1"
+ + " AND ( kC." + Keys.EXPIRY + " IS NULL OR kC." + Keys.EXPIRY
+ + " >= " + new Date().getTime() / 1000 + " )"
+ + ")" : "")
);
qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
// in case there are multiple verifying certificates
@@ -400,6 +413,7 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
+ projectionMap.put(Keys.KEY_CURVE_OID, Keys.KEY_CURVE_OID);
projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
@@ -674,6 +688,11 @@ public class KeychainProvider extends ContentProvider {
final int match = mUriMatcher.match(uri);
switch (match) {
+ // dangerous
+ case KEY_RINGS_UNIFIED: {
+ count = db.delete(Tables.KEY_RINGS_PUBLIC, null, null);
+ break;
+ }
case KEY_RING_PUBLIC: {
@SuppressWarnings("ConstantConditions") // ensured by uriMatcher above
String selection = KeyRings.MASTER_KEY_ID + " = " + uri.getPathSegments().get(1);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index a13bb9c98..bb095c340 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -28,12 +29,16 @@ import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.NullProgressable;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
+import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
@@ -51,9 +56,12 @@ import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+import org.sufficientlysecure.keychain.util.FileImportCache;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressFixedScaler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -63,6 +71,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -86,6 +95,10 @@ public class ProviderHelper {
this(context, new OperationLog(), 0);
}
+ public ProviderHelper(Context context, OperationLog log) {
+ this(context, log, 0);
+ }
+
public ProviderHelper(Context context, OperationLog log, int indent) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -93,14 +106,6 @@ public class ProviderHelper {
mIndent = indent;
}
- public void resetLog() {
- if(mLog != null) {
- // Start a new log (leaving the old one intact)
- mLog = new OperationLog();
- mIndent = 0;
- }
- }
-
public OperationLog getLog() {
return mLog;
}
@@ -322,6 +327,7 @@ public class ProviderHelper {
values.put(Keys.KEY_ID, key.getKeyId());
values.put(Keys.KEY_SIZE, key.getBitStrength());
+ values.put(Keys.KEY_CURVE_OID, key.getCurveOid());
values.put(Keys.ALGORITHM, key.getAlgorithm());
values.put(Keys.FINGERPRINT, key.getFingerprint());
@@ -644,7 +650,7 @@ public class ProviderHelper {
if (publicRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
CanonicalizedPublicKeyRing canPublicRing;
@@ -658,20 +664,20 @@ public class ProviderHelper {
// If this is null, there is an error in the log so we can just return
if (publicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Early breakout if nothing changed
if (Arrays.hashCode(publicRing.getEncoded())
== Arrays.hashCode(oldPublicRing.getEncoded())) {
log(LogLevel.OK, LogType.MSG_IP_SUCCESS_IDENTICAL);
- return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null);
}
} catch (NotFoundException e) {
// Not an issue, just means we are dealing with a new keyring.
@@ -679,7 +685,7 @@ public class ProviderHelper {
// Canonicalize this keyring, to assert a number of assumptions made about it.
canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
}
@@ -692,12 +698,12 @@ public class ProviderHelper {
// Merge data from new public ring into secret one
secretRing = secretRing.merge(publicRing, mLog, mIndent);
if (secretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// This has always been a secret key ring, this is a safe cast
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
} catch (NotFoundException e) {
@@ -716,11 +722,11 @@ public class ProviderHelper {
}
}
- return new SaveKeyringResult(result, mLog);
+ return new SaveKeyringResult(result, mLog, canSecretRing);
} catch (IOException e) {
log(LogLevel.ERROR, LogType.MSG_IP_FAIL_IO_EXC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} finally {
mIndent -= 1;
}
@@ -736,7 +742,7 @@ public class ProviderHelper {
if ( ! secretRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
CanonicalizedSecretKeyRing canSecretRing;
@@ -750,14 +756,14 @@ public class ProviderHelper {
// If this is null, there is an error in the log so we can just return
if (secretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
// This is a safe cast, because we made sure this is a secret ring above
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
// Early breakout if nothing changed
@@ -765,7 +771,7 @@ public class ProviderHelper {
== Arrays.hashCode(oldSecretRing.getEncoded())) {
log(LogLevel.OK, LogType.MSG_IS_SUCCESS_IDENTICAL,
PgpKeyHelper.convertKeyIdToHex(masterKeyId) );
- return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null);
}
} catch (NotFoundException e) {
// Not an issue, just means we are dealing with a new keyring
@@ -774,7 +780,7 @@ public class ProviderHelper {
// This is a safe cast, because we made sure this is a secret ring above
canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
if (canSecretRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
}
@@ -787,7 +793,7 @@ public class ProviderHelper {
// Merge data from new secret ring into public one
publicRing = oldPublicRing.merge(secretRing, mLog, mIndent);
if (publicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
} catch (NotFoundException e) {
@@ -797,30 +803,289 @@ public class ProviderHelper {
CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
if (canPublicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
int result;
result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true);
if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
result = saveCanonicalizedSecretKeyRing(canSecretRing);
- return new SaveKeyringResult(result, mLog);
+ return new SaveKeyringResult(result, mLog, canSecretRing);
} catch (IOException e) {
log(LogLevel.ERROR, LogType.MSG_IS_FAIL_IO_EXC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} finally {
mIndent -= 1;
}
}
+ public ConsolidateResult consolidateDatabaseStep1(Progressable progress) {
+
+ // 1a. fetch all secret keyrings into a cache file
+ log(LogLevel.START, LogType.MSG_CON);
+ mIndent += 1;
+
+ progress.setProgress(R.string.progress_con_saving, 0, 100);
+
+ try {
+
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET);
+ mIndent += 1;
+
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
+ KeyRings.PRIVKEY_DATA, KeyRings.FINGERPRINT, KeyRings.HAS_ANY_SECRET
+ }, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_DB);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount());
+
+ FileImportCache<ParcelableKeyRing> cache =
+ new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl");
+ cache.writeCache(new Iterator<ParcelableKeyRing>() {
+ ParcelableKeyRing ring;
+
+ @Override
+ public boolean hasNext() {
+ if (ring != null) {
+ return true;
+ }
+ if (cursor.isAfterLast()) {
+ return false;
+ }
+ ring = new ParcelableKeyRing(cursor.getBlob(0),
+ PgpKeyHelper.convertFingerprintToHex(cursor.getBlob(1)));
+ cursor.moveToNext();
+ return true;
+ }
+
+ @Override
+ public ParcelableKeyRing next() {
+ try {
+ return ring;
+ } finally {
+ ring = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ });
+
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error saving secret", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_IO_SECRET);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ progress.setProgress(R.string.progress_con_saving, 3, 100);
+
+ // 1b. fetch all public keyrings into a cache file
+ try {
+
+ log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC);
+ mIndent += 1;
+
+ final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
+ KeyRings.PUBKEY_DATA, KeyRings.FINGERPRINT
+ }, null, null, null);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_DB);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ Preferences.getPreferences(mContext).setCachedConsolidateNumPublics(cursor.getCount());
+
+ FileImportCache<ParcelableKeyRing> cache =
+ new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_public.pcl");
+ cache.writeCache(new Iterator<ParcelableKeyRing>() {
+ ParcelableKeyRing ring;
+
+ @Override
+ public boolean hasNext() {
+ if (ring != null) {
+ return true;
+ }
+ if (cursor.isAfterLast()) {
+ return false;
+ }
+ ring = new ParcelableKeyRing(cursor.getBlob(0),
+ PgpKeyHelper.convertFingerprintToHex(cursor.getBlob(1)));
+ cursor.moveToNext();
+ return true;
+ }
+
+ @Override
+ public ParcelableKeyRing next() {
+ try {
+ return ring;
+ } finally {
+ ring = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ });
+
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error saving public", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_IO_PUBLIC);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+
+ log(LogLevel.INFO, LogType.MSG_CON_CRITICAL_IN);
+ Preferences.getPreferences(mContext).setCachedConsolidate(true);
+
+ return consolidateDatabaseStep2(progress, false);
+ }
+
+ public ConsolidateResult consolidateDatabaseStep2(Progressable progress) {
+ return consolidateDatabaseStep2(progress, true);
+ }
+
+ private static boolean mConsolidateCritical = false;
+
+ private ConsolidateResult consolidateDatabaseStep2(Progressable progress, boolean recovery) {
+
+ synchronized (ProviderHelper.class) {
+ if (mConsolidateCritical) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_CONCURRENT);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+ mConsolidateCritical = true;
+ }
+
+ try {
+ Preferences prefs = Preferences.getPreferences(mContext);
+
+ // Set flag that we have a cached consolidation here
+ int numSecrets = prefs.getCachedConsolidateNumSecrets();
+ int numPublics = prefs.getCachedConsolidateNumPublics();
+
+ if (recovery) {
+ if (numSecrets >= 0 && numPublics >= 0) {
+ log(LogLevel.START, LogType.MSG_CON_RECOVER, numSecrets, numPublics);
+ } else {
+ log(LogLevel.START, LogType.MSG_CON_RECOVER_UNKNOWN);
+ }
+ mIndent += 1;
+ }
+
+ if (!prefs.getCachedConsolidate()) {
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_BAD_STATE);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ }
+
+ // 2. wipe database (IT'S DANGEROUS)
+ log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR);
+ mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null);
+
+ FileImportCache<ParcelableKeyRing> cacheSecret =
+ new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl");
+ FileImportCache<ParcelableKeyRing> cachePublic =
+ new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_public.pcl");
+
+ // 3. Re-Import secret keyrings from cache
+ if (numSecrets > 0) try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, numSecrets);
+ mIndent += 1;
+
+ new PgpImportExport(mContext, this,
+ new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
+ .importKeyRings(cacheSecret.readCache(false), numSecrets);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error importing secret", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_SECRET);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+ else {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET_SKIP);
+ }
+
+ // 4. Re-Import public keyrings from cache
+ if (numPublics > 0) try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, numPublics);
+ mIndent += 1;
+
+ new PgpImportExport(mContext, this,
+ new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
+ .importKeyRings(cachePublic.readCache(false), numPublics);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "error importing public", e);
+ log(LogLevel.ERROR, LogType.MSG_CON_ERROR_PUBLIC);
+ return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog);
+ } finally {
+ mIndent -= 1;
+ }
+ else {
+ log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC_SKIP);
+ }
+
+ log(LogLevel.INFO, LogType.MSG_CON_CRITICAL_OUT);
+ Preferences.getPreferences(mContext).setCachedConsolidate(false);
+
+ // 5. Delete caches
+ try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_DELETE_SECRET);
+ mIndent += 1;
+ cacheSecret.delete();
+ } catch (IOException e) {
+ // doesn't /really/ matter
+ Log.e(Constants.TAG, "IOException during delete of secret cache", e);
+ log(LogLevel.WARN, LogType.MSG_CON_WARN_DELETE_SECRET);
+ } finally {
+ mIndent -= 1;
+ }
+
+ try {
+ log(LogLevel.DEBUG, LogType.MSG_CON_DELETE_PUBLIC);
+ mIndent += 1;
+ cachePublic.delete();
+ } catch (IOException e) {
+ // doesn't /really/ matter
+ Log.e(Constants.TAG, "IOException during deletion of public cache", e);
+ log(LogLevel.WARN, LogType.MSG_CON_WARN_DELETE_PUBLIC);
+ } finally {
+ mIndent -= 1;
+ }
+
+ progress.setProgress(100, 100);
+ log(LogLevel.OK, LogType.MSG_CON_SUCCESS);
+ mIndent -= 1;
+
+ return new ConsolidateResult(ConsolidateResult.RESULT_OK, mLog);
+
+ } finally {
+ mConsolidateCritical = false;
+ }
+
+ }
+
/**
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/
@@ -863,9 +1128,7 @@ public class ProviderHelper {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
String version = PgpHelper.getVersionForHeader(mContext);
- if (version != null) {
- keyRing.encodeArmored(bos, version);
- }
+ keyRing.encodeArmored(bos, version);
String armoredKey = bos.toString("UTF-8");
Log.d(Constants.TAG, "armoredKey:" + armoredKey);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
index 87c0cc0a6..a65d222da 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index 44d37b926..20dfac36d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -23,6 +23,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpMetadata;
@@ -38,6 +39,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -56,11 +58,16 @@ import java.util.Set;
public class OpenPgpService extends RemoteService {
- static final String[] KEYRING_PROJECTION =
- new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- };
+ static final String[] EMAIL_SEARCH_PROJECTION = new String[]{
+ KeyRings._ID,
+ KeyRings.MASTER_KEY_ID,
+ KeyRings.IS_EXPIRED,
+ KeyRings.IS_REVOKED,
+ };
+
+ // do not pre-select revoked or expired keys
+ static final String EMAIL_SEARCH_WHERE = KeychainContract.KeyRings.IS_REVOKED + " = 0 AND "
+ + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
/**
* Search database for key ids based on emails.
@@ -69,52 +76,61 @@ public class OpenPgpService extends RemoteService {
* @return
*/
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
- // find key ids to given emails in database
- ArrayList<Long> keyIds = new ArrayList<Long>();
-
+ boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
boolean missingUserIdsCheck = false;
boolean duplicateUserIdsCheck = false;
+
+ ArrayList<Long> keyIds = new ArrayList<Long>();
ArrayList<String> missingUserIds = new ArrayList<String>();
ArrayList<String> duplicateUserIds = new ArrayList<String>();
-
- for (String email : encryptionUserIds) {
- Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
- Cursor cursor = getContentResolver().query(uri, KEYRING_PROJECTION, null, null, null);
- try {
- if (cursor != null && cursor.moveToFirst()) {
- long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
- keyIds.add(id);
- } else {
- missingUserIdsCheck = true;
- missingUserIds.add(email);
- Log.d(Constants.TAG, "user id missing");
- }
- if (cursor != null && cursor.moveToNext()) {
- duplicateUserIdsCheck = true;
- duplicateUserIds.add(email);
- Log.d(Constants.TAG, "more than one user id with the same email");
- }
- } finally {
- if (cursor != null) {
- cursor.close();
+ if (!noUserIdsCheck) {
+ for (String email : encryptionUserIds) {
+ // try to find the key for this specific email
+ Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
+ Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
+ try {
+ // result should be one entry containing the key id
+ if (cursor != null && cursor.moveToFirst()) {
+ long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
+ keyIds.add(id);
+ } else {
+ missingUserIdsCheck = true;
+ missingUserIds.add(email);
+ Log.d(Constants.TAG, "user id missing");
+ }
+ // another entry for this email -> too keys with the same email inside user id
+ if (cursor != null && cursor.moveToNext()) {
+ duplicateUserIdsCheck = true;
+ duplicateUserIds.add(email);
+
+ // also pre-select
+ long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
+ keyIds.add(id);
+ Log.d(Constants.TAG, "more than one user id with the same email");
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
}
- // convert to long[]
+ // convert ArrayList<Long> to long[]
long[] keyIdsArray = new long[keyIds.size()];
for (int i = 0; i < keyIdsArray.length; i++) {
keyIdsArray[i] = keyIds.get(i);
}
- // allow the user to verify pub key selection
- if (missingUserIdsCheck || duplicateUserIdsCheck) {
- // build PendingIntent
+ if (noUserIdsCheck || missingUserIdsCheck || duplicateUserIdsCheck) {
+ // allow the user to verify pub key selection
+
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_NO_USER_IDS_CHECK, noUserIdsCheck);
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
- intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds);
+ intent.putExtra(RemoteServiceActivity.EXTRA_DUPLICATE_USER_IDS, duplicateUserIds);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
@@ -126,16 +142,18 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
- }
+ } else {
+ // everything was easy, we have exactly one key for every email
- if (keyIdsArray.length == 0) {
- return null;
- }
+ if (keyIdsArray.length == 0) {
+ Log.e(Constants.TAG, "keyIdsArray.length == 0, should never happen!");
+ }
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
+ Intent result = new Intent();
+ result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
+ }
}
private Intent getNfcIntent(Intent data, byte[] hashToSign, int hashAlgo) {
@@ -191,7 +209,7 @@ public class OpenPgpService extends RemoteService {
} catch (PassphraseCacheService.KeyNotFoundException e) {
// secret key that is set for this account is deleted?
// show account config again!
- return getCreateAccountIntent(data, data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME));
+ return getCreateAccountIntent(data, getAccountName(data));
}
}
if (passphrase == null) {
@@ -270,10 +288,9 @@ public class OpenPgpService extends RemoteService {
originalFilename = "";
}
- long[] keyIds;
- if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
- keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
- } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
+ // first try to get key ids from non-ambiguous key id extra
+ long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
+ if (keyIds == null) {
// get key ids based on given user ids
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
// give params through to activity...
@@ -285,20 +302,8 @@ public class OpenPgpService extends RemoteService {
// if not success -> result contains a PendingIntent for user interaction
return result;
}
- } else {
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_ERROR,
- new OpenPgpError(OpenPgpError.GENERIC_ERROR,
- "Missing parameter user_ids or key_ids!")
- );
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
- return result;
}
- // add own key for encryption
- keyIds = Arrays.copyOf(keyIds, keyIds.length + 1);
- keyIds[keyIds.length - 1] = accSettings.getKeyId();
-
// build InputData and write into OutputStream
// Get Input- and OutputStream from ParcelFileDescriptor
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
@@ -315,7 +320,8 @@ public class OpenPgpService extends RemoteService {
.setCompressionId(accSettings.getCompression())
.setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
.setEncryptionMasterKeyIds(keyIds)
- .setOriginalFilename(originalFilename);
+ .setOriginalFilename(originalFilename)
+ .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
if (sign) {
String passphrase;
@@ -334,9 +340,6 @@ public class OpenPgpService extends RemoteService {
builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
.setSignatureMasterKeyId(accSettings.getKeyId())
.setSignaturePassphrase(passphrase);
- } else {
- // encrypt only
- builder.setSignatureMasterKeyId(Constants.key.none);
}
try {
@@ -448,7 +451,7 @@ public class OpenPgpService extends RemoteService {
// If signature is unknown we return an _additional_ PendingIntent
// to retrieve the missing key
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId());
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
@@ -514,7 +517,7 @@ public class OpenPgpService extends RemoteService {
// If keys are not in db we return an additional PendingIntent
// to retrieve the missing key
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, masterKeyId);
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
@@ -596,6 +599,16 @@ public class OpenPgpService extends RemoteService {
return null;
}
+ private String getAccountName(Intent data) {
+ String accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME);
+ // if no account name is given use name "default"
+ if (TextUtils.isEmpty(accName)) {
+ accName = "default";
+ }
+ Log.d(Constants.TAG, "accName: " + accName);
+ return accName;
+ }
+
// TODO: multi-threading
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
@@ -606,12 +619,7 @@ public class OpenPgpService extends RemoteService {
return errorResult;
}
- String accName;
- if (data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME) != null) {
- accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME);
- } else {
- accName = "default";
- }
+ String accName = getAccountName(data);
final AccountSettings accSettings = getAccSettings(accName);
if (accSettings == null) {
return getCreateAccountIntent(data, accName);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java
index f70324e2c..e71b52ccd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
+import android.text.TextUtils;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpApi;
@@ -160,7 +161,7 @@ public abstract class RemoteService extends Service {
*/
protected AccountSettings getAccSettings(String accountName) {
String currentPkg = getCurrentCallingPackage();
- Log.d(Constants.TAG, "accountName: " + accountName);
+ Log.d(Constants.TAG, "getAccSettings accountName: "+ accountName);
Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(currentPkg, accountName);
@@ -171,7 +172,7 @@ public abstract class RemoteService extends Service {
protected Intent getCreateAccountIntent(Intent data, String accountName) {
String packageName = getCurrentCallingPackage();
- Log.d(Constants.TAG, "accountName: " + accountName);
+ Log.d(Constants.TAG, "getCreateAccountIntent accountName: " + accountName);
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_CREATE_ACCOUNT);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java
index 666252353..67ad0822d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java
@@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.util.Log;
public class AccountSettingsActivity extends ActionBarActivity {
@@ -106,4 +107,15 @@ public class AccountSettingsActivity extends ActionBarActivity {
finish();
}
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // if a result has been returned, display a notify
+ if (data != null && data.hasExtra(OperationResultParcel.EXTRA_RESULT)) {
+ OperationResultParcel result = data.getParcelableExtra(OperationResultParcel.EXTRA_RESULT);
+ result.createNotify(this).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
index 8468f5eca..2cab23e51 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
@@ -36,6 +36,8 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
+import org.sufficientlysecure.keychain.service.OperationResults;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
@@ -177,24 +179,19 @@ public class AccountSettingsFragment extends Fragment implements
switch (requestCode) {
case REQUEST_CODE_CREATE_KEY: {
if (resultCode == Activity.RESULT_OK) {
- // select newly created key
- try {
- long masterKeyId = new ProviderHelper(getActivity())
- .getCachedPublicKeyRing(data.getData())
- .extractOrGetMasterKeyId();
- mSelectKeyFragment.selectKey(masterKeyId);
- } catch (PgpGeneralException e) {
- Log.e(Constants.TAG, "key not found!", e);
+ if (data != null && data.hasExtra(OperationResultParcel.EXTRA_RESULT)) {
+ OperationResults.SaveKeyringResult result = data.getParcelableExtra(OperationResultParcel.EXTRA_RESULT);
+ mSelectKeyFragment.selectKey(result.mRingMasterKeyId);
+ } else {
+ Log.e(Constants.TAG, "missing result!");
}
}
break;
}
-
- default:
- super.onActivityResult(requestCode, resultCode, data);
-
- break;
}
+
+ // execute activity's onActivityResult to show log notify
+ super.onActivityResult(requestCode, resultCode, data);
}
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
index 48c76d561..4b27e115b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
@@ -18,11 +18,20 @@
package org.sufficientlysecure.keychain.remote.ui;
import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+import android.text.TextUtils;
+import android.text.style.BulletSpan;
+import android.text.style.StyleSpan;
import android.view.View;
import android.widget.TextView;
@@ -39,7 +48,6 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import java.security.Provider;
import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
@@ -68,7 +76,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
// select pub keys action
public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
- public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids";
+ public static final String EXTRA_DUPLICATE_USER_IDS = "dublicate_user_ids";
+ public static final String EXTRA_NO_USER_IDS_CHECK = "no_user_ids";
// error message
public static final String EXTRA_ERROR_MESSAGE = "error_message";
@@ -229,32 +238,41 @@ public class RemoteServiceActivity extends ActionBarActivity {
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
+ boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true);
ArrayList<String> missingUserIds = intent
.getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
ArrayList<String> dublicateUserIds = intent
- .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);
+ .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS);
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ final SpannableString textIntro = new SpannableString(
+ noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids)
+ : getString(R.string.api_select_pub_keys_text)
+ );
+ textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(textIntro);
- // 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);
- text += "<br/>";
- text += "<ul>";
+ ssb.append("\n\n");
+ ssb.append(getString(R.string.api_select_pub_keys_missing_text));
+ ssb.append("\n");
for (String userId : missingUserIds) {
- text += "<li>" + userId + "</li>";
+ SpannableString ss = new SpannableString(userId + "\n");
+ ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(ss);
}
- text += "</ul>";
- text += "<br/>";
}
if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
- text += getString(R.string.api_select_pub_keys_dublicates_text);
- text += "<br/>";
- text += "<ul>";
+ ssb.append("\n\n");
+ ssb.append(getString(R.string.api_select_pub_keys_dublicates_text));
+ ssb.append("\n");
for (String userId : dublicateUserIds) {
- text += "<li>" + userId + "</li>";
+ SpannableString ss = new SpannableString(userId + "\n");
+ ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ ssb.append(ss);
}
- text += "</ul>";
}
// Inflate a "Done"/"Cancel" custom action bar view
@@ -284,8 +302,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
setContentView(R.layout.api_remote_select_pub_keys);
// set text on view
- HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text);
- textView.setHtmlFromString(text, true);
+ TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text);
+ textView.setText(ssb, TextView.BufferType.SPANNABLE);
/* Load select pub keys fragment */
// Check that the activity is using the layout version with
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
index 43ed2dad0..fbe914b78 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
@@ -21,6 +21,8 @@ import android.accounts.Account;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
@@ -29,9 +31,11 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.provider.ContactsContract;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.KeychainApplication;
+import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.helper.EmailKeyHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -42,7 +46,7 @@ public class ContactSyncAdapterService extends Service {
private class ContactSyncAdapter extends AbstractThreadedSyncAdapter {
- private final AtomicBoolean importDone = new AtomicBoolean(false);
+// private final AtomicBoolean importDone = new AtomicBoolean(false);
public ContactSyncAdapter() {
super(ContactSyncAdapterService.this, true);
@@ -51,47 +55,59 @@ public class ContactSyncAdapterService extends Service {
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
final SyncResult syncResult) {
- importDone.set(false);
- KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
- EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
- new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- Bundle data = msg.getData();
- switch (msg.arg1) {
- case KeychainIntentServiceHandler.MESSAGE_OKAY:
- Log.d(Constants.TAG, "Syncing... Done.");
- synchronized (importDone) {
- importDone.set(true);
- importDone.notifyAll();
- }
- return true;
- case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS:
- if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) &&
- data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) {
- Log.d(Constants.TAG, "Syncing... Progress: " +
- data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" +
- data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX));
- return false;
- }
- default:
- Log.d(Constants.TAG, "Syncing... " + msg.toString());
- return false;
- }
- }
- })));
- synchronized (importDone) {
- try {
- if (!importDone.get()) importDone.wait();
- } catch (InterruptedException e) {
- Log.w(Constants.TAG, e);
- return;
- }
- }
+ Log.d(Constants.TAG, "Performing a sync!");
+ // TODO: Import is currently disabled for 2.8, until we implement proper origin management
+// importDone.set(false);
+// KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
+// EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
+// new Handler.Callback() {
+// @Override
+// public boolean handleMessage(Message msg) {
+// Bundle data = msg.getData();
+// switch (msg.arg1) {
+// case KeychainIntentServiceHandler.MESSAGE_OKAY:
+// Log.d(Constants.TAG, "Syncing... Done.");
+// synchronized (importDone) {
+// importDone.set(true);
+// importDone.notifyAll();
+// }
+// return true;
+// case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS:
+// if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) &&
+// data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) {
+// Log.d(Constants.TAG, "Syncing... Progress: " +
+// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" +
+// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX));
+// return false;
+// }
+// default:
+// Log.d(Constants.TAG, "Syncing... " + msg.toString());
+// return false;
+// }
+// }
+// })));
+// synchronized (importDone) {
+// try {
+// if (!importDone.get()) importDone.wait();
+// } catch (InterruptedException e) {
+// Log.w(Constants.TAG, e);
+// return;
+// }
+// }
ContactHelper.writeKeysToContacts(ContactSyncAdapterService.this);
}
}
+ public static void requestSync() {
+ Bundle extras = new Bundle();
+ // no need to wait for internet connection!
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ ContentResolver.requestSync(
+ new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE),
+ ContactsContract.AUTHORITY,
+ extras);
+ }
+
@Override
public IBinder onBind(Intent intent) {
return new ContactSyncAdapter().getSyncAdapterBinder();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index d6c470e11..021e6bc07 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -49,11 +50,14 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
+import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.FileImportCache;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -102,6 +106,10 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
+ public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE";
+
+ public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
+
/* keys for data bundle */
// encrypt, decrypt, import export
@@ -139,8 +147,13 @@ public class KeychainIntentService extends IntentService
// delete file securely
public static final String DELETE_FILE = "deleteFile";
+ // delete keyring(s)
+ public static final String DELETE_KEY_LIST = "delete_list";
+ public static final String DELETE_IS_SECRET = "delete_is_secret";
+
// import key
public static final String IMPORT_KEY_LIST = "import_key_list";
+ public static final String IMPORT_KEY_FILE = "import_key_file";
// export key
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
@@ -162,6 +175,10 @@ public class KeychainIntentService extends IntentService
public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
public static final String CERTIFY_KEY_UIDS = "sign_key_uids";
+ // consolidate
+ public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
+
+
/*
* possible data keys as result send over messenger
*/
@@ -176,8 +193,6 @@ public class KeychainIntentService extends IntentService
// export
public static final String RESULT_EXPORT = "exported";
- public static final String RESULT_IMPORT = "result";
-
Messenger mMessenger;
private boolean mIsCanceled;
@@ -246,27 +261,31 @@ public class KeychainIntentService extends IntentService
String originalFilename = getOriginalFilename(data);
/* Operation */
- PgpSignEncrypt.Builder builder =
- new PgpSignEncrypt.Builder(
- new ProviderHelper(this),
- inputData, outStream);
- builder.setProgressable(this);
-
- builder.setEnableAsciiArmorOutput(useAsciiArmor)
+ PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
+ new ProviderHelper(this),
+ inputData, outStream
+ );
+ builder.setProgressable(this)
+ .setEnableAsciiArmorOutput(useAsciiArmor)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setCompressionId(compressionId)
.setSymmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.setEncryptionMasterKeyIds(encryptionKeyIds)
.setSymmetricPassphrase(symmetricPassphrase)
- .setSignatureMasterKeyId(signatureKeyId)
- .setEncryptToSigner(true)
- .setSignatureHashAlgorithm(
- Preferences.getPreferences(this).getDefaultHashAlgorithm())
- .setSignaturePassphrase(
- PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
.setOriginalFilename(originalFilename);
+ try {
+ builder.setSignatureMasterKeyId(signatureKeyId)
+ .setSignaturePassphrase(
+ PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
+ .setSignatureHashAlgorithm(
+ Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .setAdditionalEncryptId(signatureKeyId);
+ } catch (PassphraseCacheService.KeyNotFoundException e) {
+ // encrypt-only
+ }
+
// this assumes that the bytes are cleartext (valid for current implementation!)
if (source == IO_BYTES) {
builder.setCleartextInput(true);
@@ -391,23 +410,41 @@ public class KeychainIntentService extends IntentService
}
/* Operation */
- ProviderHelper providerHelper = new ProviderHelper(this);
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100));
- EditKeyResult result;
+ EditKeyResult modifyResult;
if (saveParcel.mMasterKeyId != null) {
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
CanonicalizedSecretKeyRing secRing =
- providerHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
+ new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
- result = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
+ modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
} else {
- result = keyOperations.createSecretKeyRing(saveParcel);
+ modifyResult = keyOperations.createSecretKeyRing(saveParcel);
}
- UncachedKeyRing ring = result.getRing();
+ // If the edit operation didn't succeed, exit here
+ if (!modifyResult.success()) {
+ // always return SaveKeyringResult, so create one out of the EditKeyResult
+ SaveKeyringResult saveResult = new SaveKeyringResult(
+ SaveKeyringResult.RESULT_ERROR,
+ modifyResult.getLog(),
+ null);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
+ return;
+ }
- providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+ UncachedKeyRing ring = modifyResult.getRing();
+
+ // Save the keyring. The ProviderHelper is initialized with the previous log
+ SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog())
+ .saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+
+ // If the edit operation didn't succeed, exit here
+ if (!saveResult.success()) {
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
+ return;
+ }
// cache new passphrase
if (saveParcel.mNewPassphrase != null) {
@@ -417,8 +454,11 @@ public class KeychainIntentService extends IntentService
setProgress(R.string.progress_done, 100, 100);
+ // make sure new data is synced into contacts
+ ContactSyncAdapterService.requestSync();
+
/* Output */
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
} catch (Exception e) {
sendErrorToHandler(e);
}
@@ -454,17 +494,21 @@ public class KeychainIntentService extends IntentService
} else {
// get entries from cached file
FileImportCache<ParcelableKeyRing> cache =
- new FileImportCache<ParcelableKeyRing>(this);
+ new FileImportCache<ParcelableKeyRing>(this, "key_import.pcl");
entries = cache.readCacheIntoList();
}
- PgpImportExport pgpImportExport = new PgpImportExport(this, this);
+ ProviderHelper providerHelper = new ProviderHelper(this);
+ PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this);
ImportKeyResult result = pgpImportExport.importKeyRings(entries);
- Bundle resultData = new Bundle();
- resultData.putParcelable(RESULT_IMPORT, result);
+ if (result.mSecret > 0) {
+ providerHelper.consolidateDatabaseStep1(this);
+ }
+ // make sure new data is synced into contacts
+ ContactSyncAdapterService.requestSync();
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
} catch (Exception e) {
sendErrorToHandler(e);
}
@@ -549,8 +593,9 @@ public class KeychainIntentService extends IntentService
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
PgpImportExport pgpImportExport = new PgpImportExport(this, null);
- boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring);
- if (!uploaded) {
+ try {
+ pgpImportExport.uploadKeyRingToServer(server, keyring);
+ } catch (Keyserver.AddKeyException e) {
throw new PgpGeneralException("Unable to export key to selected server");
}
@@ -639,7 +684,56 @@ public class KeychainIntentService extends IntentService
} catch (Exception e) {
sendErrorToHandler(e);
}
+
+ } else if (ACTION_DELETE.equals(action)) {
+
+ try {
+
+ long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
+ boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
+
+ if (masterKeyIds.length == 0) {
+ throw new PgpGeneralException("List of keys to delete is empty");
+ }
+
+ if (isSecret && masterKeyIds.length > 1) {
+ throw new PgpGeneralException("Secret keys can only be deleted individually!");
+ }
+
+ boolean success = false;
+ for (long masterKeyId : masterKeyIds) {
+ int count = getContentResolver().delete(
+ KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null
+ );
+ success |= count > 0;
+ }
+
+ if (isSecret && success) {
+ ConsolidateResult result =
+ new ProviderHelper(this).consolidateDatabaseStep1(this);
+ }
+
+ if (success) {
+ // make sure new data is synced into contacts
+ ContactSyncAdapterService.requestSync();
+
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
+ }
+
+ } catch (Exception e) {
+ sendErrorToHandler(e);
+ }
+
+ } else if (ACTION_CONSOLIDATE.equals(action)) {
+ ConsolidateResult result;
+ if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
+ result = new ProviderHelper(this).consolidateDatabaseStep2(this);
+ } else {
+ result = new ProviderHelper(this).consolidateDatabaseStep1(this);
+ }
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
}
+
}
private void sendErrorToHandler(Exception e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index d7d98fd68..142bf65cc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -155,10 +156,8 @@ public class OperationResultParcel implements Parcelable {
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
if (getLog().containsWarnings()) {
- duration = 0;
color = Style.ORANGE;
} else {
- duration = SuperToast.Duration.LONG;
color = Style.GREEN;
}
@@ -167,7 +166,6 @@ public class OperationResultParcel implements Parcelable {
} else {
- duration = 0;
color = Style.RED;
str = "operation failed";
@@ -180,8 +178,8 @@ public class OperationResultParcel implements Parcelable {
button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD,
Style.getStyle(color, SuperToast.Animations.POPUP));
toast.setText(str);
- toast.setDuration(duration);
- toast.setIndeterminate(duration == 0);
+ toast.setDuration(SuperToast.Duration.EXTRA_LONG);
+ toast.setIndeterminate(false);
toast.setSwipeToDismiss(true);
// If we have a log and it's non-empty, show a View Log button
if (button) {
@@ -289,6 +287,7 @@ public class OperationResultParcel implements Parcelable {
MSG_IS_SUCCESS (R.string.msg_is_success),
// keyring canonicalization
+ MSG_KC_V3_KEY (R.string.msg_kc_v3_key),
MSG_KC_PUBLIC (R.string.msg_kc_public),
MSG_KC_SECRET (R.string.msg_kc_secret),
MSG_KC_FATAL_NO_UID (R.string.msg_kc_fatal_no_uid),
@@ -324,6 +323,7 @@ public class OperationResultParcel implements Parcelable {
MSG_KC_UID_BAD_TIME (R.string.msg_kc_uid_bad_time),
MSG_KC_UID_BAD_TYPE (R.string.msg_kc_uid_bad_type),
MSG_KC_UID_BAD (R.string.msg_kc_uid_bad),
+ MSG_KC_UID_CERT_DUP (R.string.msg_kc_uid_cert_dup),
MSG_KC_UID_DUP (R.string.msg_kc_uid_dup),
MSG_KC_UID_FOREIGN (R.string.msg_kc_uid_foreign),
MSG_KC_UID_NO_CERT (R.string.msg_kc_uid_no_cert),
@@ -333,10 +333,11 @@ public class OperationResultParcel implements Parcelable {
// keyring consolidation
+ MSG_MG_ERROR_SECRET_DUMMY(R.string.msg_mg_error_secret_dummy),
+ MSG_MG_ERROR_ENCODE(R.string.msg_mg_error_encode),
+ MSG_MG_ERROR_HETEROGENEOUS(R.string.msg_mg_error_heterogeneous),
MSG_MG_PUBLIC (R.string.msg_mg_public),
MSG_MG_SECRET (R.string.msg_mg_secret),
- MSG_MG_FATAL_ENCODE (R.string.msg_mg_fatal_encode),
- MSG_MG_HETEROGENEOUS (R.string.msg_mg_heterogeneous),
MSG_MG_NEW_SUBKEY (R.string.msg_mg_new_subkey),
MSG_MG_FOUND_NEW (R.string.msg_mg_found_new),
MSG_MG_UNCHANGED (R.string.msg_mg_unchanged),
@@ -346,10 +347,16 @@ public class OperationResultParcel implements Parcelable {
MSG_CR_ERROR_NO_MASTER (R.string.msg_cr_error_no_master),
MSG_CR_ERROR_NO_USER_ID (R.string.msg_cr_error_no_user_id),
MSG_CR_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
+ MSG_CR_ERROR_NULL_EXPIRY(R.string.msg_cr_error_null_expiry),
MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
+ MSG_CR_ERROR_NO_KEYSIZE (R.string.msg_cr_error_no_keysize),
+ MSG_CR_ERROR_NO_CURVE (R.string.msg_cr_error_no_curve),
MSG_CR_ERROR_UNKNOWN_ALGO (R.string.msg_cr_error_unknown_algo),
MSG_CR_ERROR_INTERNAL_PGP (R.string.msg_cr_error_internal_pgp),
- MSG_CR_ERROR_MASTER_ELGAMAL (R.string.msg_cr_error_master_elgamal),
+ MSG_CR_ERROR_FLAGS_DSA (R.string.msg_cr_error_flags_dsa),
+ MSG_CR_ERROR_FLAGS_ELGAMAL (R.string.msg_cr_error_flags_elgamal),
+ MSG_CR_ERROR_FLAGS_ECDSA (R.string.msg_cr_error_flags_ecdsa),
+ MSG_CR_ERROR_FLAGS_ECDH (R.string.msg_cr_error_flags_ecdh),
// secret key modify
MSG_MF (R.string.msg_mr),
@@ -357,18 +364,27 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint),
MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
+ MSG_MF_ERROR_MASTER_NONE(R.string.msg_mf_error_master_none),
+ MSG_MF_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
- MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
+ MSG_MF_ERROR_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
+ MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
+ MSG_MF_ERROR_PASSPHRASE_MASTER(R.string.msg_mf_error_passphrase_master),
+ MSG_MF_ERROR_PAST_EXPIRY(R.string.msg_mf_error_past_expiry),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
+ MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
+ MSG_MF_ERROR_SUBKEY_MISSING(R.string.msg_mf_error_subkey_missing),
+ MSG_MF_MASTER (R.string.msg_mf_master),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
+ MSG_MF_PASSPHRASE_KEY (R.string.msg_mf_passphrase_key),
+ MSG_MF_PASSPHRASE_EMPTY_RETRY (R.string.msg_mf_passphrase_empty_retry),
+ MSG_MF_PASSPHRASE_FAIL (R.string.msg_mf_passphrase_fail),
MSG_MF_PRIMARY_REPLACE_OLD (R.string.msg_mf_primary_replace_old),
MSG_MF_PRIMARY_NEW (R.string.msg_mf_primary_new),
MSG_MF_SUBKEY_CHANGE (R.string.msg_mf_subkey_change),
- MSG_MF_SUBKEY_MISSING (R.string.msg_mf_subkey_missing),
MSG_MF_SUBKEY_NEW_ID (R.string.msg_mf_subkey_new_id),
MSG_MF_SUBKEY_NEW (R.string.msg_mf_subkey_new),
- MSG_MF_SUBKEY_PAST_EXPIRY (R.string.msg_mf_subkey_past_expiry),
MSG_MF_SUBKEY_REVOKE (R.string.msg_mf_subkey_revoke),
MSG_MF_SUCCESS (R.string.msg_mf_success),
MSG_MF_UID_ADD (R.string.msg_mf_uid_add),
@@ -377,6 +393,32 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_UID_ERROR_EMPTY (R.string.msg_mf_uid_error_empty),
MSG_MF_UNLOCK_ERROR (R.string.msg_mf_unlock_error),
MSG_MF_UNLOCK (R.string.msg_mf_unlock),
+
+ // consolidate
+ MSG_CON_CRITICAL_IN (R.string.msg_con_critical_in),
+ MSG_CON_CRITICAL_OUT (R.string.msg_con_critical_out),
+ MSG_CON_DB_CLEAR (R.string.msg_con_db_clear),
+ MSG_CON_DELETE_PUBLIC (R.string.msg_con_delete_public),
+ MSG_CON_DELETE_SECRET (R.string.msg_con_delete_secret),
+ MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state),
+ MSG_CON_ERROR_CONCURRENT(R.string.msg_con_error_concurrent),
+ MSG_CON_ERROR_DB (R.string.msg_con_error_db),
+ MSG_CON_ERROR_IO_PUBLIC (R.string.msg_con_error_io_public),
+ MSG_CON_ERROR_IO_SECRET (R.string.msg_con_error_io_secret),
+ MSG_CON_ERROR_PUBLIC (R.string.msg_con_error_public),
+ MSG_CON_ERROR_SECRET (R.string.msg_con_error_secret),
+ MSG_CON_RECOVER (R.plurals.msg_con_recover),
+ MSG_CON_RECOVER_UNKNOWN (R.string.msg_con_recover_unknown),
+ MSG_CON_REIMPORT_PUBLIC (R.plurals.msg_con_reimport_public),
+ MSG_CON_REIMPORT_PUBLIC_SKIP (R.string.msg_con_reimport_public_skip),
+ MSG_CON_REIMPORT_SECRET (R.plurals.msg_con_reimport_secret),
+ MSG_CON_REIMPORT_SECRET_SKIP (R.string.msg_con_reimport_secret_skip),
+ MSG_CON (R.string.msg_con),
+ MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
+ MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
+ MSG_CON_SUCCESS (R.string.msg_con_success),
+ MSG_CON_WARN_DELETE_PUBLIC (R.string.msg_con_warn_delete_public),
+ MSG_CON_WARN_DELETE_SECRET (R.string.msg_con_warn_delete_secret),
;
private final int mMsgId;
@@ -406,7 +448,9 @@ public class OperationResultParcel implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mResult);
- dest.writeTypedList(mLog.toList());
+ if (mLog != null) {
+ dest.writeTypedList(mLog.toList());
+ }
}
public static final Creator<OperationResultParcel> CREATOR = new Creator<OperationResultParcel>() {
@@ -432,6 +476,15 @@ public class OperationResultParcel implements Parcelable {
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));
}
+ public boolean containsType(LogType type) {
+ for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) {
+ if (entry.mType == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean containsWarnings() {
for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) {
if (entry.mLevel == LogLevel.WARN || entry.mLevel == LogLevel.ERROR) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index 543b83edb..f3d0b9e9b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -28,7 +29,10 @@ import com.github.johnpersano.supertoasts.SuperToast;
import com.github.johnpersano.supertoasts.util.OnClickWrapper;
import com.github.johnpersano.supertoasts.util.Style;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
@@ -37,7 +41,7 @@ public abstract class OperationResults {
public static class ImportKeyResult extends OperationResultParcel {
- public final int mNewKeys, mUpdatedKeys, mBadKeys;
+ public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
// At least one new key
public static final int RESULT_OK_NEWKEYS = 2;
@@ -49,18 +53,21 @@ public abstract class OperationResults {
public static final int RESULT_WITH_WARNINGS = 16;
// No keys to import...
- public static final int RESULT_FAIL_NOTHING = 32 +1;
+ public static final int RESULT_FAIL_NOTHING = 32 + 1;
public boolean isOkBoth() {
return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED))
== (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED);
}
+
public boolean isOkNew() {
return (mResult & RESULT_OK_NEWKEYS) == RESULT_OK_NEWKEYS;
}
+
public boolean isOkUpdated() {
return (mResult & RESULT_OK_UPDATED) == RESULT_OK_UPDATED;
}
+
public boolean isFailNothing() {
return (mResult & RESULT_FAIL_NOTHING) == RESULT_FAIL_NOTHING;
}
@@ -70,14 +77,16 @@ public abstract class OperationResults {
mNewKeys = source.readInt();
mUpdatedKeys = source.readInt();
mBadKeys = source.readInt();
+ mSecret = source.readInt();
}
public ImportKeyResult(int result, OperationLog log,
- int newKeys, int updatedKeys, int badKeys) {
+ int newKeys, int updatedKeys, int badKeys, int secret) {
super(result, log);
mNewKeys = newKeys;
mUpdatedKeys = updatedKeys;
mBadKeys = badKeys;
+ mSecret = secret;
}
@Override
@@ -86,6 +95,7 @@ public abstract class OperationResults {
dest.writeInt(mNewKeys);
dest.writeInt(mUpdatedKeys);
dest.writeInt(mBadKeys);
+ dest.writeInt(mSecret);
}
public static Creator<ImportKeyResult> CREATOR = new Creator<ImportKeyResult>() {
@@ -124,7 +134,7 @@ public abstract class OperationResults {
if (this.isOkBoth()) {
str = activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_1, mNewKeys, mNewKeys);
- str += " "+ activity.getResources().getQuantityString(
+ str += " " + activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_2, mUpdatedKeys, mUpdatedKeys, withWarnings);
} else if (isOkUpdated()) {
str = activity.getResources().getQuantityString(
@@ -185,13 +195,13 @@ public abstract class OperationResults {
public static class EditKeyResult extends OperationResultParcel {
private transient UncachedKeyRing mRing;
- public final Long mRingMasterKeyId;
+ public final long mRingMasterKeyId;
public EditKeyResult(int result, OperationLog log,
- UncachedKeyRing ring) {
+ UncachedKeyRing ring) {
super(result, log);
mRing = ring;
- mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
public UncachedKeyRing getRing() {
@@ -224,8 +234,12 @@ public abstract class OperationResults {
public static class SaveKeyringResult extends OperationResultParcel {
- public SaveKeyringResult(int result, OperationLog log) {
+ public final long mRingMasterKeyId;
+
+ public SaveKeyringResult(int result, OperationLog log,
+ CanonicalizedKeyRing ring) {
super(result, log);
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
// Some old key was updated
@@ -240,6 +254,34 @@ public abstract class OperationResults {
return (mResult & UPDATED) == UPDATED;
}
+ public SaveKeyringResult(Parcel source) {
+ super(source);
+ mRingMasterKeyId = source.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeLong(mRingMasterKeyId);
+ }
+
+ public static Creator<SaveKeyringResult> CREATOR = new Creator<SaveKeyringResult>() {
+ public SaveKeyringResult createFromParcel(final Parcel source) {
+ return new SaveKeyringResult(source);
+ }
+
+ public SaveKeyringResult[] newArray(final int size) {
+ return new SaveKeyringResult[size];
+ }
+ };
+ }
+
+ public static class ConsolidateResult extends OperationResultParcel {
+
+ public ConsolidateResult(int result, OperationLog log) {
+ super(result, log);
+ }
+
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 8cd9876eb..1b357bd65 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -78,7 +78,7 @@ public class PassphraseCacheService extends Service {
private static final int NOTIFICATION_ID = 1;
private static final int MSG_PASSPHRASE_CACHE_GET_OKAY = 1;
- private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND = 2;
+ private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND = 2;
private BroadcastReceiver mIntentReceiver;
@@ -170,7 +170,7 @@ public class PassphraseCacheService extends Service {
switch (returnMessage.what) {
case MSG_PASSPHRASE_CACHE_GET_OKAY:
return returnMessage.getData().getString(EXTRA_PASSPHRASE);
- case MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND:
+ case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
throw new KeyNotFoundException();
default:
throw new KeyNotFoundException("should not happen!");
@@ -322,7 +322,7 @@ public class PassphraseCacheService extends Service {
msg.setData(bundle);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
- msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND;
+ msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
}
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
index 490a8e738..996ce6a5a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -79,14 +80,16 @@ public class SaveKeyringParcel implements Parcelable {
// performance gain for using Parcelable here would probably be negligible,
// use Serializable instead.
public static class SubkeyAdd implements Serializable {
- public int mAlgorithm;
- public int mKeysize;
+ public Algorithm mAlgorithm;
+ public Integer mKeySize;
+ public Curve mCurve;
public int mFlags;
public Long mExpiry;
- public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
+ public SubkeyAdd(Algorithm algorithm, Integer keySize, Curve curve, int flags, Long expiry) {
mAlgorithm = algorithm;
- mKeysize = keysize;
+ mKeySize = keySize;
+ mCurve = curve;
mFlags = flags;
mExpiry = expiry;
}
@@ -94,7 +97,8 @@ public class SaveKeyringParcel implements Parcelable {
@Override
public String toString() {
String out = "mAlgorithm: " + mAlgorithm + ", ";
- out += "mKeysize: " + mKeysize + ", ";
+ out += "mKeySize: " + mKeySize + ", ";
+ out += "mCurve: " + mCurve + ", ";
out += "mFlags: " + mFlags;
out += "mExpiry: " + mExpiry;
@@ -213,4 +217,20 @@ public class SaveKeyringParcel implements Parcelable {
return out;
}
+
+ // All supported algorithms
+ public enum Algorithm {
+ RSA, DSA, ELGAMAL, ECDSA, ECDH
+ }
+
+ // All curves defined in the standard
+ // http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269
+ public enum Curve {
+ NIST_P256, NIST_P384, NIST_P521,
+
+ // these are supported by gpg, but they are not in rfc6637 and not supported by BouncyCastle yet
+ // (adding support would be trivial though -> JcaPGPKeyConverter.java:190)
+ // BRAINPOOL_P256, BRAINPOOL_P384, BRAINPOOL_P512
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index c1986825c..8b99d474d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
* Copyright (C) 2011 Senecaso
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,6 +41,7 @@ import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
@@ -53,9 +55,12 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
+import org.sufficientlysecure.keychain.service.OperationResults;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
+import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
+import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
@@ -64,18 +69,18 @@ import java.util.ArrayList;
/**
* Signs the specified public key with the specified secret master key
*/
-public class CertifyKeyActivity extends ActionBarActivity implements
- SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks<Cursor> {
+public class CertifyKeyActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private View mCertifyButton;
private ImageView mActionCertifyImage;
private CheckBox mUploadKeyCheckbox;
private Spinner mSelectKeyserverSpinner;
+ private ScrollView mScrollView;
- private SelectSecretKeyLayoutFragment mSelectKeyFragment;
+ private CertifyKeySpinner mCertifyKeySpinner;
private Uri mDataUri;
- private long mPubKeyId = 0;
- private long mMasterKeyId = 0;
+ private long mPubKeyId = Constants.key.none;
+ private long mMasterKeyId = Constants.key.none;
private ListView mUserIds;
private UserIdsAdapter mUserIdsAdapter;
@@ -89,20 +94,24 @@ public class CertifyKeyActivity extends ActionBarActivity implements
setContentView(R.layout.certify_key_activity);
- mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager()
- .findFragmentById(R.id.sign_key_select_key_fragment);
+ mCertifyKeySpinner = (CertifyKeySpinner) findViewById(R.id.certify_key_spinner);
mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver);
mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox);
mCertifyButton = findViewById(R.id.certify_key_certify_button);
mActionCertifyImage = (ImageView) findViewById(R.id.certify_key_action_certify_image);
mUserIds = (ListView) findViewById(R.id.view_key_user_ids);
+ mScrollView = (ScrollView) findViewById(R.id.certify_scroll_view);
// make certify image gray, like action icons
mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
PorterDuff.Mode.SRC_IN);
- mSelectKeyFragment.setCallback(this);
- mSelectKeyFragment.setFilterCertify(true);
+ mCertifyKeySpinner.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
+ @Override
+ public void onKeyChanged(long masterKeyId) {
+ mMasterKeyId = masterKeyId;
+ }
+ });
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
@@ -135,9 +144,9 @@ public class CertifyKeyActivity extends ActionBarActivity implements
public void onClick(View v) {
if (mPubKeyId != 0) {
if (mMasterKeyId == 0) {
- mSelectKeyFragment.setError(getString(R.string.select_key_to_certify));
Notify.showNotify(CertifyKeyActivity.this, getString(R.string.select_key_to_certify),
Notify.Style.ERROR);
+ scrollUp();
} else {
initiateCertifying();
}
@@ -162,6 +171,14 @@ public class CertifyKeyActivity extends ActionBarActivity implements
getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
}
+ private void scrollUp() {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ mScrollView.fullScroll(ScrollView.FOCUS_UP);
+ }
+ });
+ }
+
static final String USER_IDS_SELECTION = UserIds.IS_REVOKED + " = 0";
static final String[] KEYRING_PROJECTION =
@@ -199,6 +216,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
if (data.moveToFirst()) {
// TODO: put findViewById in onCreate!
mPubKeyId = data.getLong(INDEX_MASTER_KEY_ID);
+ mCertifyKeySpinner.setHiddenMasterKeyId(mPubKeyId);
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(mPubKeyId);
((TextView) findViewById(R.id.key_id)).setText(keyIdStr);
@@ -213,6 +231,9 @@ public class CertifyKeyActivity extends ActionBarActivity implements
break;
case LOADER_ID_USER_IDS:
mUserIdsAdapter.swapCursor(data);
+ // when some user ids are pre-checked, the focus is requested and the scroll view goes
+ // down. This fixes it.
+ scrollUp();
break;
}
}
@@ -292,8 +313,14 @@ public class CertifyKeyActivity extends ActionBarActivity implements
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Notify.showNotify(CertifyKeyActivity.this, R.string.key_certify_success,
- Notify.Style.INFO);
+// Notify.showNotify(CertifyKeyActivity.this, R.string.key_certify_success,
+// Notify.Style.INFO);
+
+ OperationResultParcel result = new OperationResultParcel(OperationResultParcel.RESULT_OK, null);
+ Intent intent = new Intent();
+ intent.putExtra(OperationResultParcel.EXTRA_RESULT, result);
+ CertifyKeyActivity.this.setResult(RESULT_OK, intent);
+ CertifyKeyActivity.this.finish();
// check if we need to send the key to the server or not
if (mUploadKeyCheckbox.isChecked()) {
@@ -345,13 +372,14 @@ public class CertifyKeyActivity extends ActionBarActivity implements
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Intent intent = new Intent();
- intent.putExtra(OperationResultParcel.EXTRA_RESULT, message.getData());
- Notify.showNotify(CertifyKeyActivity.this, R.string.key_send_success,
- Notify.Style.INFO);
+ //Notify.showNotify(CertifyKeyActivity.this, R.string.key_send_success,
+ //Notify.Style.INFO);
- setResult(RESULT_OK);
- finish();
+ OperationResultParcel result = new OperationResultParcel(OperationResultParcel.RESULT_OK, null);
+ Intent intent = new Intent();
+ intent.putExtra(OperationResultParcel.EXTRA_RESULT, result);
+ CertifyKeyActivity.this.setResult(RESULT_OK, intent);
+ CertifyKeyActivity.this.finish();
}
}
};
@@ -367,14 +395,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements
startService(intent);
}
- /**
- * callback from select key fragment
- */
- @Override
- public void onKeySelected(long secretKeyId) {
- mMasterKeyId = secretKeyId;
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
new file mode 100644
index 000000000..edc05e28d
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
@@ -0,0 +1,99 @@
+/*
+ * 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.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.FragmentActivity;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+
+/**
+ * We can not directly create a dialog on the application context.
+ * This activity encapsulates a DialogFragment to emulate a dialog.
+ */
+public class ConsolidateDialogActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // this activity itself has no content view (see manifest)
+
+ consolidateRecovery();
+
+ }
+
+ private void consolidateRecovery() {
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ /* don't care about the results (for now?)
+
+ // get returned data bundle
+ Bundle returnData = message.getData();
+ if (returnData == null) {
+ return;
+ }
+ final ConsolidateResult result =
+ returnData.getParcelable(KeychainIntentService.RESULT_CONSOLIDATE);
+ if (result == null) {
+ return;
+ }
+ result.createNotify(ConsolidateDialogActivity.this).show();
+ */
+
+ ConsolidateDialogActivity.this.finish();
+ }
+ }
+ };
+
+ // Send all information needed to service to import key in other thread
+ Intent intent = new Intent(this, KeychainIntentService.class);
+ intent.setAction(KeychainIntentService.ACTION_CONSOLIDATE);
+
+ // fill values for this action
+ Bundle data = new Bundle();
+ data.putBoolean(KeychainIntentService.CONSOLIDATE_RECOVERY, true);
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ // show progress dialog
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(intent);
+
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index 773be816a..69f4af04b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -33,6 +33,7 @@ import android.widget.TextView;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.KeyRing;
@@ -42,6 +43,8 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
public class CreateKeyFinalFragment extends Fragment {
@@ -125,10 +128,9 @@ public class CreateKeyFinalFragment extends Fragment {
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
- // Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
- getString(R.string.progress_importing),
+ getString(R.string.progress_building_key),
ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
@@ -140,26 +142,21 @@ public class CreateKeyFinalFragment extends Fragment {
if (returnData == null) {
return;
}
- final OperationResults.EditKeyResult result =
+ final OperationResults.SaveKeyringResult result =
returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
if (result == null) {
+ Log.e(Constants.TAG, "result == null");
return;
}
- if (result.getResult() == OperationResultParcel.RESULT_OK) {
- if (mUploadCheckbox.isChecked()) {
- // result will be displayed after upload
- uploadKey(result);
- } else {
- // TODO: return result
- result.createNotify(getActivity());
-
- getActivity().setResult(Activity.RESULT_OK);
- getActivity().finish();
- }
+ if (mUploadCheckbox.isChecked()) {
+ // result will be displayed after upload
+ uploadKey(result);
} else {
- // display result on error without finishing activity
- result.createNotify(getActivity());
+ Intent data = new Intent();
+ data.putExtra(OperationResultParcel.EXTRA_RESULT, result);
+ getActivity().setResult(Activity.RESULT_OK, data);
+ getActivity().finish();
}
}
}
@@ -169,9 +166,12 @@ public class CreateKeyFinalFragment extends Fragment {
Bundle data = new Bundle();
SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.CERTIFY_OTHER, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.SIGN_DATA, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ Algorithm.RSA, 4096, null, KeyFlags.CERTIFY_OTHER, 0L));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ Algorithm.RSA, 4096, null, KeyFlags.SIGN_DATA, 0L));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ Algorithm.RSA, 4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
String userId = KeyRing.createUserId(mName, mEmail, null);
parcel.mAddUserIds.add(userId);
parcel.mChangePrimaryUserId = userId;
@@ -191,7 +191,7 @@ public class CreateKeyFinalFragment extends Fragment {
getActivity().startService(intent);
}
- private void uploadKey(final OperationResults.EditKeyResult editKeyResult) {
+ private void uploadKey(final OperationResults.SaveKeyringResult saveKeyResult) {
// Send all information needed to service to upload key in other thread
final Intent intent = new Intent(getActivity(), KeychainIntentService.class);
@@ -199,7 +199,7 @@ public class CreateKeyFinalFragment extends Fragment {
// set data uri as path to keyring
Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
- editKeyResult.mRingMasterKeyId);
+ saveKeyResult.mRingMasterKeyId);
intent.setData(blobUri);
// fill values for this action
@@ -211,7 +211,6 @@ public class CreateKeyFinalFragment extends Fragment {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
@@ -219,20 +218,16 @@ public class CreateKeyFinalFragment extends Fragment {
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- // TODO: not supported by upload?
-// if (result.getResult() == OperationResultParcel.RESULT_OK) {
- // TODO: return result
- editKeyResult.createNotify(getActivity());
-
- Notify.showNotify(getActivity(), R.string.key_send_success,
- Notify.Style.INFO);
-
- getActivity().setResult(Activity.RESULT_OK);
+ // TODO: upload operation needs a result!
+ // TODO: then combine these results
+ //if (result.getResult() == OperationResultParcel.RESULT_OK) {
+ //Notify.showNotify(getActivity(), R.string.key_send_success,
+ //Notify.Style.INFO);
+
+ Intent data = new Intent();
+ data.putExtra(OperationResultParcel.EXTRA_RESULT, saveKeyResult);
+ getActivity().setResult(Activity.RESULT_OK, data);
getActivity().finish();
-// } else {
-// // display result on error without finishing activity
-// editKeyResult.createNotify(getActivity());
-// }
}
}
};
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 03074bb6a..28692f638 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -48,8 +48,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.OperationResults;
-import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
@@ -340,7 +339,8 @@ public class EditKeyFragment extends LoaderFragment implements
} else {
mSaveKeyringParcel.mRevokeUserIds.add(userId);
// not possible to revoke and change to primary user id
- if (mSaveKeyringParcel.mChangePrimaryUserId.equals(userId)) {
+ if (mSaveKeyringParcel.mChangePrimaryUserId != null
+ && mSaveKeyringParcel.mChangePrimaryUserId.equals(userId)) {
mSaveKeyringParcel.mChangePrimaryUserId = null;
}
}
@@ -407,10 +407,10 @@ public class EditKeyFragment extends LoaderFragment implements
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY_DATE:
- Long expiry = (Long) message.getData().
- getSerializable(EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY_DATE);
- mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry = expiry;
+ case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY:
+ mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry =
+ (Long) message.getData().getSerializable(
+ EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY);
break;
}
getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
@@ -504,7 +504,6 @@ public class EditKeyFragment extends LoaderFragment implements
private void save(String passphrase) {
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString());
- // Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
getString(R.string.progress_saving),
@@ -520,8 +519,8 @@ public class EditKeyFragment extends LoaderFragment implements
if (returnData == null) {
return;
}
- final OperationResults.EditKeyResult result =
- returnData.getParcelable(EditKeyResult.EXTRA_RESULT);
+ final OperationResultParcel result =
+ returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
if (result == null) {
return;
}
@@ -534,7 +533,7 @@ public class EditKeyFragment extends LoaderFragment implements
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
- intent.putExtra(EditKeyResult.EXTRA_RESULT, result);
+ intent.putExtra(OperationResultParcel.EXTRA_RESULT, result);
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
getActivity().finish();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index 7e08f6b7c..4cd694d48 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -73,16 +73,13 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryption_key_ids";
// view
- ViewPager mViewPagerMode;
- //PagerTabStrip mPagerTabStripMode;
- PagerTabStripAdapter mTabsAdapterMode;
- ViewPager mViewPagerContent;
- PagerTabStrip mPagerTabStripContent;
- PagerTabStripAdapter mTabsAdapterContent;
+ private int mCurrentMode = PAGER_MODE_ASYMMETRIC;
+ private ViewPager mViewPagerContent;
+ private PagerTabStrip mPagerTabStripContent;
+ private PagerTabStripAdapter mTabsAdapterContent;
// tabs
- int mSwitchToMode = PAGER_MODE_ASYMMETRIC;
- int mSwitchToContent = PAGER_CONTENT_MESSAGE;
+ private int mSwitchToContent = PAGER_CONTENT_MESSAGE;
private static final int PAGER_MODE_ASYMMETRIC = 0;
private static final int PAGER_MODE_SYMMETRIC = 1;
@@ -102,7 +99,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
private String mMessage = "";
public boolean isModeSymmetric() {
- return PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem();
+ return PAGER_MODE_SYMMETRIC == mCurrentMode;
}
public boolean isContentMessage() {
@@ -312,59 +309,60 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
String title = isContentMessage() ? getString(R.string.title_share_message)
: getString(R.string.title_share_file);
- // fallback on Android 2.3, otherwise we would get weird results
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- return Intent.createChooser(prototype, title);
- }
-
- // prevent recursion aka Inception :P
- String[] blacklist = new String[]{Constants.PACKAGE_NAME + ".ui.EncryptActivity"};
-
- List<LabeledIntent> targetedShareIntents = new ArrayList<LabeledIntent>();
-
- List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(prototype, 0);
- List<ResolveInfo> resInfoListFiltered = new ArrayList<ResolveInfo>();
- if (!resInfoList.isEmpty()) {
- for (ResolveInfo resolveInfo : resInfoList) {
- // do not add blacklisted ones
- if (resolveInfo.activityInfo == null || Arrays.asList(blacklist).contains(resolveInfo.activityInfo.name))
- continue;
-
- resInfoListFiltered.add(resolveInfo);
- }
-
- if (!resInfoListFiltered.isEmpty()) {
- // sorting for nice readability
- Collections.sort(resInfoListFiltered, new Comparator<ResolveInfo>() {
- @Override
- public int compare(ResolveInfo first, ResolveInfo second) {
- String firstName = first.loadLabel(getPackageManager()).toString();
- String secondName = second.loadLabel(getPackageManager()).toString();
- return firstName.compareToIgnoreCase(secondName);
- }
- });
-
- // create the custom intent list
- for (ResolveInfo resolveInfo : resInfoListFiltered) {
- Intent targetedShareIntent = (Intent) prototype.clone();
- targetedShareIntent.setPackage(resolveInfo.activityInfo.packageName);
- targetedShareIntent.setClassName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
-
- LabeledIntent lIntent = new LabeledIntent(targetedShareIntent,
- resolveInfo.activityInfo.packageName,
- resolveInfo.loadLabel(getPackageManager()),
- resolveInfo.activityInfo.icon);
- targetedShareIntents.add(lIntent);
- }
-
- // Create chooser with only one Intent in it
- Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), title);
- // append all other Intents
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
- return chooserIntent;
- }
-
- }
+ // Disabled, produced an empty list on Huawei U8860 with Android Version 4.0.3
+// // fallback on Android 2.3, otherwise we would get weird results
+// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+// return Intent.createChooser(prototype, title);
+// }
+//
+// // prevent recursion aka Inception :P
+// String[] blacklist = new String[]{Constants.PACKAGE_NAME + ".ui.EncryptActivity"};
+//
+// List<LabeledIntent> targetedShareIntents = new ArrayList<LabeledIntent>();
+//
+// List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(prototype, 0);
+// List<ResolveInfo> resInfoListFiltered = new ArrayList<ResolveInfo>();
+// if (!resInfoList.isEmpty()) {
+// for (ResolveInfo resolveInfo : resInfoList) {
+// // do not add blacklisted ones
+// if (resolveInfo.activityInfo == null || Arrays.asList(blacklist).contains(resolveInfo.activityInfo.name))
+// continue;
+//
+// resInfoListFiltered.add(resolveInfo);
+// }
+//
+// if (!resInfoListFiltered.isEmpty()) {
+// // sorting for nice readability
+// Collections.sort(resInfoListFiltered, new Comparator<ResolveInfo>() {
+// @Override
+// public int compare(ResolveInfo first, ResolveInfo second) {
+// String firstName = first.loadLabel(getPackageManager()).toString();
+// String secondName = second.loadLabel(getPackageManager()).toString();
+// return firstName.compareToIgnoreCase(secondName);
+// }
+// });
+//
+// // create the custom intent list
+// for (ResolveInfo resolveInfo : resInfoListFiltered) {
+// Intent targetedShareIntent = (Intent) prototype.clone();
+// targetedShareIntent.setPackage(resolveInfo.activityInfo.packageName);
+// targetedShareIntent.setClassName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
+//
+// LabeledIntent lIntent = new LabeledIntent(targetedShareIntent,
+// resolveInfo.activityInfo.packageName,
+// resolveInfo.loadLabel(getPackageManager()),
+// resolveInfo.activityInfo.icon);
+// targetedShareIntents.add(lIntent);
+// }
+//
+// // Create chooser with only one Intent in it
+// Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), title);
+// // append all other Intents
+// chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
+// return chooserIntent;
+// }
+//
+// }
// fallback to Android's default chooser
return Intent.createChooser(prototype, title);
@@ -385,7 +383,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris);
}
- sendIntent.setType("application/pgp-encrypted");
+ sendIntent.setType("application/octet-stream");
}
if (!isModeSymmetric() && mEncryptionUserIds != null) {
Set<String> users = new HashSet<String>();
@@ -474,13 +472,9 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
}
private void initView() {
- mViewPagerMode = (ViewPager) findViewById(R.id.encrypt_pager_mode);
- //mPagerTabStripMode = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_mode);
mViewPagerContent = (ViewPager) findViewById(R.id.encrypt_pager_content);
mPagerTabStripContent = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_content);
- mTabsAdapterMode = new PagerTabStripAdapter(this);
- mViewPagerMode.setAdapter(mTabsAdapterMode);
mTabsAdapterContent = new PagerTabStripAdapter(this);
mViewPagerContent.setAdapter(mTabsAdapterContent);
}
@@ -502,10 +496,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
// Handle intent actions
handleActions(getIntent());
-
- mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class, null, getString(R.string.label_asymmetric));
- mTabsAdapterMode.addTab(EncryptSymmetricFragment.class, null, getString(R.string.label_symmetric));
- mViewPagerMode.setCurrentItem(mSwitchToMode);
+ updateModeFragment();
mTabsAdapterContent.addTab(EncryptMessageFragment.class, null, getString(R.string.label_message));
mTabsAdapterContent.addTab(EncryptFileFragment.class, null, getString(R.string.label_files));
@@ -521,6 +512,16 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
return super.onCreateOptionsMenu(menu);
}
+ private void updateModeFragment() {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.encrypt_pager_mode,
+ mCurrentMode == PAGER_MODE_SYMMETRIC
+ ? new EncryptSymmetricFragment()
+ : new EncryptAsymmetricFragment())
+ .commitAllowingStateLoss();
+ getSupportFragmentManager().executePendingTransactions();
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.isCheckable()) {
@@ -528,9 +529,8 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
}
switch (item.getItemId()) {
case R.id.check_use_symmetric:
- mSwitchToMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
-
- mViewPagerMode.setCurrentItem(mSwitchToMode);
+ mCurrentMode = item.isChecked() ? PAGER_MODE_SYMMETRIC : PAGER_MODE_ASYMMETRIC;
+ updateModeFragment();
notifyUpdate();
break;
case R.id.check_use_armor:
@@ -604,7 +604,7 @@ public class EncryptActivity extends DrawerActivity implements EncryptActivityIn
mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
// preselect keys given by intent
- mSwitchToMode = PAGER_MODE_ASYMMETRIC;
+ mCurrentMode = PAGER_MODE_ASYMMETRIC;
/**
* Main Actions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index a402b6f68..a508472d6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -18,35 +18,22 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
-import android.content.Context;
-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.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Spinner;
-import android.widget.SpinnerAdapter;
-import android.widget.TextView;
import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
+import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
@@ -54,22 +41,20 @@ import java.util.Iterator;
import java.util.List;
public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
- public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id";
- public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids";
-
ProviderHelper mProviderHelper;
// view
- private Spinner mSign;
+ private KeySpinner mSign;
private EncryptKeyCompletionView mEncryptKeyView;
- private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter();
// model
private EncryptActivityInterface mEncryptInterface;
@Override
public void onNotifyUpdate() {
-
+ if (mSign != null) {
+ mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
+ }
}
@Override
@@ -101,17 +86,11 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
- mSign = (Spinner) view.findViewById(R.id.sign);
- mSign.setAdapter(mSignAdapter);
- mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- setSignatureKeyId(parent.getAdapter().getItemId(position));
- }
-
+ mSign = (KeySpinner) view.findViewById(R.id.sign);
+ mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
@Override
- public void onNothingSelected(AdapterView<?> parent) {
- setSignatureKeyId(Constants.key.none);
+ public void onKeyChanged(long masterKeyId) {
+ setSignatureKeyId(masterKeyId);
}
});
mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
@@ -128,42 +107,6 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
// preselect keys given
preselectKeys();
- getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<Cursor>() {
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- // This is called when a new Loader needs to be created. This
- // sample only has one Loader, so we don't care about the ID.
- Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
-
- // These are the rows that we will retrieve.
- String[] projection = new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- KeyRings.KEY_ID,
- KeyRings.USER_ID,
- KeyRings.IS_EXPIRED,
- KeyRings.HAS_SIGN,
- KeyRings.HAS_ANY_SECRET
- };
-
- String where = KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeyRings.HAS_SIGN + " NOT NULL AND "
- + KeyRings.IS_REVOKED + " = 0 AND " + KeyRings.IS_EXPIRED + " = 0";
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, projection, where, null, null);
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- mSignAdapter.swapCursor(data);
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- mSignAdapter.swapCursor(null);
- }
- });
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
@Override
public void onTokenAdded(Object token) {
@@ -194,6 +137,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
KeyRings.buildUnifiedKeyRingUri(signatureKey));
if(keyring.hasAnySecret()) {
setSignatureKeyId(keyring.getMasterKeyId());
+ mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
}
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
@@ -211,6 +155,8 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
Log.e(Constants.TAG, "key not found!", e);
}
}
+ // This is to work-around a rendering bug in TokenCompleteTextView
+ mEncryptKeyView.requestFocus();
updateEncryptionKeys();
}
}
@@ -233,95 +179,4 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
setEncryptionKeyIds(keyIdsArr);
setEncryptionUserIds(userIds.toArray(new String[userIds.size()]));
}
-
- private class SelectSignKeyCursorAdapter extends BaseAdapter implements SpinnerAdapter {
- private CursorAdapter inner;
- private int mIndexUserId;
- private int mIndexKeyId;
- private int mIndexMasterKeyId;
-
- public SelectSignKeyCursorAdapter() {
- inner = new CursorAdapter(null, null, 0) {
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return getActivity().getLayoutInflater().inflate(R.layout.encrypt_asymmetric_signkey, null);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
- ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")"));
- ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]);
- ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
- }
-
- @Override
- public long getItemId(int position) {
- mCursor.moveToPosition(position);
- return mCursor.getLong(mIndexMasterKeyId);
- }
- };
- }
-
- public Cursor swapCursor(Cursor newCursor) {
- if (newCursor == null) return inner.swapCursor(null);
-
- mIndexKeyId = newCursor.getColumnIndex(KeyRings.KEY_ID);
- mIndexUserId = newCursor.getColumnIndex(KeyRings.USER_ID);
- mIndexMasterKeyId = newCursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
- if (newCursor.moveToFirst()) {
- do {
- if (newCursor.getLong(mIndexMasterKeyId) == mEncryptInterface.getSignatureKey()) {
- mSign.setSelection(newCursor.getPosition() + 1);
- }
- } while (newCursor.moveToNext());
- }
- return inner.swapCursor(newCursor);
- }
-
- @Override
- public int getCount() {
- return inner.getCount() + 1;
- }
-
- @Override
- public Object getItem(int position) {
- if (position == 0) return null;
- return inner.getItem(position - 1);
- }
-
- @Override
- public long getItemId(int position) {
- if (position == 0) return Constants.key.none;
- return inner.getItemId(position - 1);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = getDropDownView(position, convertView, parent);
- v.findViewById(android.R.id.text1).setVisibility(View.GONE);
- return v;
- }
-
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- View v;
- if (position == 0) {
- if (convertView == null) {
- v = inner.newView(null, null, parent);
- } else {
- v = convertView;
- }
- ((TextView) v.findViewById(android.R.id.title)).setText("None");
- v.findViewById(android.R.id.text1).setVisibility(View.GONE);
- v.findViewById(android.R.id.text2).setVisibility(View.GONE);
- } else {
- v = inner.getView(position - 1, convertView, parent);
- v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE);
- v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
- }
- return v;
- }
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
index 5f3f170a1..7b608a0a2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
@@ -51,7 +51,7 @@ public class FirstTimeActivity extends ActionBarActivity {
mSkipSetup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- finishSetup();
+ finishSetup(null);
}
});
@@ -80,18 +80,22 @@ public class FirstTimeActivity extends ActionBarActivity {
if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) {
if (resultCode == RESULT_OK) {
- finishSetup();
+ finishSetup(data);
}
} else {
Log.e(Constants.TAG, "No valid request code!");
}
}
- private void finishSetup() {
+ private void finishSetup(Intent srcData) {
Preferences prefs = Preferences.getPreferences(this);
prefs.setFirstTime(false);
- Intent intent = new Intent(FirstTimeActivity.this, KeyListActivity.class);
- startActivity(intent);
+ Intent intent = new Intent(this, KeyListActivity.class);
+ // give intent through to display notify
+ if (srcData != null) {
+ intent.putExtras(srcData);
+ }
+ startActivityForResult(intent, 0);
finish();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 255290de3..96fa11363 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
@@ -64,7 +65,7 @@ public class ImportKeysActivity extends ActionBarActivity {
+ "IMPORT_KEY_FROM_KEYSERVER";
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT =
Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN_RESULT";
- public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX
+ public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN";
public static final String ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_FILE_AND_RETURN";
@@ -87,7 +88,7 @@ public class ImportKeysActivity extends ActionBarActivity {
public static final String EXTRA_KEY_ID = "key_id";
public static final String EXTRA_FINGERPRINT = "fingerprint";
- // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN when used from OpenPgpService
+ // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE when used from OpenPgpService
public static final String EXTRA_PENDING_INTENT_DATA = "data";
private Intent mPendingIntentData;
@@ -170,7 +171,7 @@ public class ImportKeysActivity extends ActionBarActivity {
startListFragment(savedInstanceState, importData, null, null);
}
} else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action)
- || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(action)
+ || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(action)
|| ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(action)) {
// only used for OpenPgpService
@@ -287,7 +288,9 @@ public class ImportKeysActivity extends ActionBarActivity {
@Override
public void onPageSelected(int position) {
// cancel loader and clear list
- mListFragment.destroyLoader();
+ if (mListFragment != null) {
+ mListFragment.destroyLoader();
+ }
}
@Override
@@ -456,28 +459,25 @@ public class ImportKeysActivity extends ActionBarActivity {
return;
}
final ImportKeyResult result =
- returnData.getParcelable(KeychainIntentService.RESULT_IMPORT);
+ returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
if (result == null) {
+ Log.e(Constants.TAG, "result == null");
return;
}
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())) {
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
+ || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
Intent intent = new Intent();
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
ImportKeysActivity.this.setResult(RESULT_OK, intent);
ImportKeysActivity.this.finish();
return;
}
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(getIntent().getAction())) {
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
ImportKeysActivity.this.finish();
return;
}
- if (ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
- ImportKeysActivity.this.setResult(RESULT_OK);
- ImportKeysActivity.this.finish();
- return;
- }
result.createNotify(ImportKeysActivity.this).show();
}
@@ -503,7 +503,8 @@ public class ImportKeysActivity extends ActionBarActivity {
// to prevent Java Binder problems on heavy imports
// read FileImportCache for more info.
try {
- FileImportCache<ParcelableKeyRing> cache = new FileImportCache<ParcelableKeyRing>(this);
+ FileImportCache<ParcelableKeyRing> cache =
+ new FileImportCache<ParcelableKeyRing>(this, "key_import.pcl");
cache.writeCache(selectedEntries);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
index d339bc132..88caebc32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
@@ -29,15 +29,19 @@ import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.util.Log;
+import java.util.List;
+
public class ImportKeysServerFragment extends Fragment {
public static final String ARG_QUERY = "query";
public static final String ARG_KEYSERVER = "keyserver";
@@ -46,7 +50,7 @@ public class ImportKeysServerFragment extends Fragment {
private ImportKeysActivity mImportActivity;
private View mSearchButton;
- private EditText mQueryEditText;
+ private AutoCompleteTextView mQueryEditText;
private View mConfigButton;
private View mConfigLayout;
private Spinner mServerSpinner;
@@ -75,7 +79,7 @@ public class ImportKeysServerFragment extends Fragment {
View view = inflater.inflate(R.layout.import_keys_server_fragment, container, false);
mSearchButton = view.findViewById(R.id.import_server_search);
- mQueryEditText = (EditText) view.findViewById(R.id.import_server_query);
+ mQueryEditText = (AutoCompleteTextView) view.findViewById(R.id.import_server_query);
mConfigButton = view.findViewById(R.id.import_server_config_button);
mConfigLayout = view.findViewById(R.id.import_server_config);
mServerSpinner = (Spinner) view.findViewById(R.id.import_server_spinner);
@@ -93,6 +97,16 @@ public class ImportKeysServerFragment extends Fragment {
mSearchButton.setEnabled(false);
}
+ List<String> namesAndEmails = ContactHelper.getContactNames(getActivity());
+ namesAndEmails.addAll(ContactHelper.getContactMails(getActivity()));
+ mQueryEditText.setThreshold(3);
+ mQueryEditText.setAdapter(
+ new ArrayAdapter<String>
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
+ namesAndEmails
+ )
+ );
+
mSearchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 7a6e78a7d..e2ad241e2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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 +18,11 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
import android.view.Menu;
import android.view.MenuItem;
@@ -28,6 +32,10 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
+import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
@@ -63,6 +71,7 @@ public class KeyListActivity extends DrawerActivity {
getMenuInflater().inflate(R.menu.key_list, menu);
if (Constants.DEBUG) {
+ menu.findItem(R.id.menu_key_list_debug_cons).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_read).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_write).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true);
@@ -92,6 +101,10 @@ public class KeyListActivity extends DrawerActivity {
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
return true;
+ case R.id.menu_key_list_debug_cons:
+ consolidate();
+ return true;
+
case R.id.menu_key_list_debug_read:
try {
KeychainDatabase.debugBackup(this, true);
@@ -133,7 +146,67 @@ public class KeyListActivity extends DrawerActivity {
private void createKey() {
Intent intent = new Intent(this, CreateKeyActivity.class);
- startActivity(intent);
+ startActivityForResult(intent, 0);
+ }
+
+ private void consolidate() {
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ // get returned data bundle
+ Bundle returnData = message.getData();
+ if (returnData == null) {
+ return;
+ }
+ final ConsolidateResult result =
+ returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
+ if (result == null) {
+ return;
+ }
+
+ result.createNotify(KeyListActivity.this).show();
+ }
+ }
+ };
+
+ // Send all information needed to service to import key in other thread
+ Intent intent = new Intent(this, KeychainIntentService.class);
+
+ intent.setAction(KeychainIntentService.ACTION_CONSOLIDATE);
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ // show progress dialog
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(intent);
+
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // if a result has been returned, display a notify
+ if (data != null && data.hasExtra(OperationResultParcel.EXTRA_RESULT)) {
+ OperationResultParcel result = data.getParcelableExtra(OperationResultParcel.EXTRA_RESULT);
+ result.createNotify(this).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 3c97b1128..b4676f9b7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -79,14 +80,15 @@ public class KeyListFragment extends LoaderFragment
private KeyListAdapter mAdapter;
private StickyListHeadersListView mStickyList;
+ // saves the mode object for multiselect, needed for reset at some point
+ private ActionMode mActionMode = null;
+
private String mQuery;
private SearchView mSearchView;
// empty list layout
private Button mButtonEmptyCreate;
private Button mButtonEmptyImport;
- public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012;
-
/**
* Load custom layout with StickyListView from library
*/
@@ -105,7 +107,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), CreateKeyActivity.class);
- startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
+ startActivityForResult(intent, 0);
}
});
mButtonEmptyImport = (Button) view.findViewById(R.id.key_list_empty_button_import);
@@ -115,7 +117,7 @@ public class KeyListFragment extends LoaderFragment
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
- startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
+ startActivityForResult(intent, 0);
}
});
@@ -148,6 +150,7 @@ public class KeyListFragment extends LoaderFragment
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
android.view.MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.key_list_multi, menu);
+ mActionMode = mode;
return true;
}
@@ -193,6 +196,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onDestroyActionMode(ActionMode mode) {
+ mActionMode = null;
mAdapter.clearSelection();
}
@@ -288,6 +292,13 @@ public class KeyListFragment extends LoaderFragment
// this view is made visible if no data is available
mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
+ // end action mode, if any
+ if (mActionMode != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mActionMode.finish();
+ }
+ }
+
// The list should now be shown.
if (isResumed()) {
setContentShown(true);
@@ -330,12 +341,12 @@ public class KeyListFragment extends LoaderFragment
* Show dialog to delete key
*
* @param masterKeyIds
- * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
+ * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {
// Can only work on singular secret keys
- if(hasSecret && masterKeyIds.length > 1) {
+ if (hasSecret && masterKeyIds.length > 1) {
Notify.showNotify(getActivity(), R.string.secret_cannot_multiple,
Notify.Style.ERROR);
return;
@@ -365,6 +376,7 @@ public class KeyListFragment extends LoaderFragment
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
// Get the searchview
MenuItem searchItem = menu.findItem(R.id.menu_key_list_search);
+
mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
// Execute this when searching
@@ -383,7 +395,6 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
mQuery = null;
- mSearchView.setQuery("", true);
getLoaderManager().restartLoader(0, null, KeyListFragment.this);
return true;
}
@@ -399,11 +410,18 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onQueryTextChange(String s) {
+ Log.d(Constants.TAG, "onQueryTextChange s:" + s);
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
- mQuery = !TextUtils.isEmpty(s) ? s : null;
- getLoaderManager().restartLoader(0, null, this);
+ // If the nav drawer is opened, onQueryTextChange("") is executed.
+ // This hack prevents restarting the loader.
+ // TODO: better way to fix this?
+ String tmp = (mQuery == null) ? "" : mQuery;
+ if (!s.equals(tmp)) {
+ mQuery = s;
+ getLoaderManager().restartLoader(0, null, this);
+ }
return true;
}
@@ -479,7 +497,7 @@ public class KeyListFragment extends LoaderFragment
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
- && new Date(cursor.getLong(INDEX_EXPIRY)*1000).before(new Date());
+ && new Date(cursor.getLong(INDEX_EXPIRY) * 1000).before(new Date());
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
// Note: order is important!
@@ -521,6 +539,7 @@ public class KeyListFragment extends LoaderFragment
return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
}
+
public long getMasterKeyId(int id) {
if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id);
@@ -625,7 +644,7 @@ public class KeyListFragment extends LoaderFragment
public boolean isAnySecretSelected() {
for (int pos : mSelection.keySet()) {
- if(mAdapter.isSecretAvailable(pos))
+ if (mAdapter.isSecretAvailable(pos))
return true;
}
return false;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java
index b8386b144..248b8976a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
index 0e948bf7f..e524c3870 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
index de3236d35..64c1e16be 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
@@ -317,10 +317,10 @@ public class PreferencesActivity extends PreferenceActivity {
private static void initializeHashAlgorithm
(final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) {
- valueIds = new int[]{HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
+ valueIds = new int[]{HashAlgorithmTags.RIPEMD160,
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512,};
- entries = new String[]{"MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
+ entries = new String[]{"RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
"SHA-512",};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
index 341e11d1d..92f38a44c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -166,7 +167,7 @@ public class ViewCertActivity extends ActionBarActivity
mStatus.setTextColor(getResources().getColor(R.color.black));
}
- String algorithmStr = PgpKeyHelper.getAlgorithmInfo(this, sig.getKeyAlgorithm(), 0);
+ String algorithmStr = PgpKeyHelper.getAlgorithmInfo(this, sig.getKeyAlgorithm(), null, null);
mAlgorithm.setText(algorithmStr);
mRowReason.setVisibility(View.GONE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 28f7b8bf5..2c0881ea4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -54,6 +54,8 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
@@ -303,8 +305,10 @@ public class ViewKeyActivity extends ActionBarActivity implements
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
- setResult(RESULT_CANCELED);
- finish();
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
}
};
@@ -313,6 +317,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // if a result has been returned, display a notify
if (data != null && data.hasExtra(OperationResultParcel.EXTRA_RESULT)) {
OperationResultParcel result = data.getParcelableExtra(OperationResultParcel.EXTRA_RESULT);
result.createNotify(this).show();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
index 5a55b0dad..786537b25 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 08243f06b..c37cb014e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
index 1f809cc51..1fed58721 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
@@ -155,8 +155,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// don't show full fingerprint on key import
holder.fingerprint.setVisibility(View.GONE);
- if (entry.getBitStrength() != 0 && entry.getAlgorithm() != null) {
- holder.algorithm.setText("" + entry.getBitStrength() + "/" + entry.getAlgorithm());
+ if (entry.getAlgorithm() != null) {
+ holder.algorithm.setText(entry.getAlgorithm());
holder.algorithm.setVisibility(View.VISIBLE);
} else {
holder.algorithm.setVisibility(View.INVISIBLE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index d457e75bd..489cbcefb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -35,7 +35,9 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import java.util.Calendar;
import java.util.Date;
+import java.util.TimeZone;
public class SubkeysAdapter extends CursorAdapter {
private LayoutInflater mInflater;
@@ -50,6 +52,7 @@ public class SubkeysAdapter extends CursorAdapter {
Keys.RANK,
Keys.ALGORITHM,
Keys.KEY_SIZE,
+ Keys.KEY_CURVE_OID,
Keys.HAS_SECRET,
Keys.CAN_CERTIFY,
Keys.CAN_ENCRYPT,
@@ -64,14 +67,15 @@ public class SubkeysAdapter extends CursorAdapter {
private static final int INDEX_RANK = 2;
private static final int INDEX_ALGORITHM = 3;
private static final int INDEX_KEY_SIZE = 4;
- private static final int INDEX_HAS_SECRET = 5;
- private static final int INDEX_CAN_CERTIFY = 6;
- private static final int INDEX_CAN_ENCRYPT = 7;
- private static final int INDEX_CAN_SIGN = 8;
- private static final int INDEX_IS_REVOKED = 9;
- private static final int INDEX_CREATION = 10;
- private static final int INDEX_EXPIRY = 11;
- private static final int INDEX_FINGERPRINT = 12;
+ private static final int INDEX_KEY_CURVE_OID = 5;
+ private static final int INDEX_HAS_SECRET = 6;
+ private static final int INDEX_CAN_CERTIFY = 7;
+ private static final int INDEX_CAN_ENCRYPT = 8;
+ private static final int INDEX_CAN_SIGN = 9;
+ private static final int INDEX_IS_REVOKED = 10;
+ private static final int INDEX_CREATION = 11;
+ private static final int INDEX_EXPIRY = 12;
+ private static final int INDEX_FINGERPRINT = 13;
public SubkeysAdapter(Context context, Cursor c, int flags,
SaveKeyringParcel saveKeyringParcel) {
@@ -139,7 +143,8 @@ public class SubkeysAdapter extends CursorAdapter {
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
context,
cursor.getInt(INDEX_ALGORITHM),
- cursor.getInt(INDEX_KEY_SIZE)
+ cursor.getInt(INDEX_KEY_SIZE),
+ cursor.getString(INDEX_KEY_CURVE_OID)
);
vKeyId.setText(keyIdStr);
@@ -183,7 +188,7 @@ public class SubkeysAdapter extends CursorAdapter {
SaveKeyringParcel.SubkeyChange subkeyChange = mSaveKeyringParcel.getSubkeyChange(keyId);
if (subkeyChange != null) {
- if (subkeyChange.mExpiry == null) {
+ if (subkeyChange.mExpiry == null || subkeyChange.mExpiry == 0L) {
expiryDate = null;
} else {
expiryDate = new Date(subkeyChange.mExpiry * 1000);
@@ -198,9 +203,13 @@ public class SubkeysAdapter extends CursorAdapter {
boolean isExpired;
if (expiryDate != null) {
isExpired = expiryDate.before(new Date());
+ Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTime(expiryDate);
+ // convert from UTC to time zone of device
+ expiryCal.setTimeZone(TimeZone.getDefault());
vKeyExpiry.setText(context.getString(R.string.label_expiry) + ": "
- + DateFormat.getDateFormat(context).format(expiryDate));
+ + DateFormat.getDateFormat(context).format(expiryCal.getTime()));
} else {
isExpired = false;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
index be2e17c63..d50318fb4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
@@ -33,21 +33,19 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import java.util.Calendar;
import java.util.Date;
import java.util.List;
+import java.util.TimeZone;
public class SubkeysAddedAdapter extends ArrayAdapter<SaveKeyringParcel.SubkeyAdd> {
private LayoutInflater mInflater;
private Activity mActivity;
- // hold a private reference to the underlying data List
- private List<SaveKeyringParcel.SubkeyAdd> mData;
-
public SubkeysAddedAdapter(Activity activity, List<SaveKeyringParcel.SubkeyAdd> data) {
super(activity, -1, data);
mActivity = activity;
mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mData = data;
}
static class ViewHolder {
@@ -101,16 +99,21 @@ public class SubkeysAddedAdapter extends ArrayAdapter<SaveKeyringParcel.SubkeyAd
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
mActivity,
holder.mModel.mAlgorithm,
- holder.mModel.mKeysize
+ holder.mModel.mKeySize,
+ holder.mModel.mCurve
);
holder.vKeyId.setText(R.string.edit_key_new_subkey);
holder.vKeyDetails.setText(algorithmStr);
- if (holder.mModel.mExpiry != null) {
+ if (holder.mModel.mExpiry != 0L) {
Date expiryDate = new Date(holder.mModel.mExpiry * 1000);
+ Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTime(expiryDate);
+ // convert from UTC to time zone of device
+ expiryCal.setTimeZone(TimeZone.getDefault());
holder.vKeyExpiry.setText(getContext().getString(R.string.label_expiry) + ": "
- + DateFormat.getDateFormat(getContext()).format(expiryDate));
+ + DateFormat.getDateFormat(getContext()).format(expiryCal.getTime()));
} else {
holder.vKeyExpiry.setText(getContext().getString(R.string.label_expiry) + ": "
+ getContext().getString(R.string.none));
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index cb31978e9..b4119a5eb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -20,19 +20,18 @@ package org.sufficientlysecure.keychain.ui.dialog;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.text.Editable;
import android.text.TextWatcher;
-import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
@@ -40,17 +39,18 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TableRow;
import android.widget.TextView;
+import android.widget.Toast;
-import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.util.Choice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.Date;
import java.util.TimeZone;
public class AddSubkeyDialogFragment extends DialogFragment {
@@ -67,7 +67,10 @@ public class AddSubkeyDialogFragment extends DialogFragment {
private TableRow mExpiryRow;
private DatePicker mExpiryDatePicker;
private Spinner mAlgorithmSpinner;
+ private View mKeySizeRow;
private Spinner mKeySizeSpinner;
+ private View mCurveRow;
+ private Spinner mCurveSpinner;
private TextView mCustomKeyTextView;
private EditText mCustomKeyEditText;
private TextView mCustomKeyInfoTextView;
@@ -76,6 +79,8 @@ public class AddSubkeyDialogFragment extends DialogFragment {
private CheckBox mFlagEncrypt;
private CheckBox mFlagAuthenticate;
+ private boolean mWillBeMasterKey;
+
public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) {
mAlgorithmSelectedListener = listener;
}
@@ -96,7 +101,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
final FragmentActivity context = getActivity();
final LayoutInflater mInflater;
- final boolean willBeMasterKey = getArguments().getBoolean(ARG_WILL_BE_MASTER_KEY);
+ mWillBeMasterKey = getArguments().getBoolean(ARG_WILL_BE_MASTER_KEY);
mInflater = context.getLayoutInflater();
CustomAlertDialogBuilder dialog = new CustomAlertDialogBuilder(context);
@@ -110,6 +115,9 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mExpiryDatePicker = (DatePicker) view.findViewById(R.id.add_subkey_expiry_date_picker);
mAlgorithmSpinner = (Spinner) view.findViewById(R.id.add_subkey_algorithm);
mKeySizeSpinner = (Spinner) view.findViewById(R.id.add_subkey_size);
+ mCurveSpinner = (Spinner) view.findViewById(R.id.add_subkey_curve);
+ mKeySizeRow = view.findViewById(R.id.add_subkey_row_size);
+ mCurveRow = view.findViewById(R.id.add_subkey_row_curve);
mCustomKeyTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_label);
mCustomKeyEditText = (EditText) view.findViewById(R.id.add_subkey_custom_key_size_input);
mCustomKeyInfoTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_info);
@@ -130,27 +138,36 @@ public class AddSubkeyDialogFragment extends DialogFragment {
});
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- mExpiryDatePicker.setMinDate(new Date().getTime() + DateUtils.DAY_IN_MILLIS);
+ // date picker works based on default time zone
+ Calendar minDateCal = Calendar.getInstance(TimeZone.getDefault());
+ minDateCal.add(Calendar.DAY_OF_YEAR, 1); // at least one day after creation (today)
+ mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
}
- ArrayList<Choice> choices = new ArrayList<Choice>();
- choices.add(new Choice(PublicKeyAlgorithmTags.DSA, getResources().getString(
- R.string.dsa)));
- if (!willBeMasterKey) {
- choices.add(new Choice(PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, getResources().getString(
- R.string.elgamal)));
- }
- choices.add(new Choice(PublicKeyAlgorithmTags.RSA_GENERAL, getResources().getString(
- R.string.rsa)));
- ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context,
- android.R.layout.simple_spinner_item, choices);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mAlgorithmSpinner.setAdapter(adapter);
- // make RSA the default
- for (int i = 0; i < choices.size(); ++i) {
- if (choices.get(i).getId() == PublicKeyAlgorithmTags.RSA_GENERAL) {
- mAlgorithmSpinner.setSelection(i);
- break;
+ {
+ ArrayList<Choice<Algorithm>> choices = new ArrayList<Choice<Algorithm>>();
+ choices.add(new Choice<Algorithm>(Algorithm.DSA, getResources().getString(
+ R.string.dsa)));
+ if (!mWillBeMasterKey) {
+ choices.add(new Choice<Algorithm>(Algorithm.ELGAMAL, getResources().getString(
+ R.string.elgamal)));
+ }
+ choices.add(new Choice<Algorithm>(Algorithm.RSA, getResources().getString(
+ R.string.rsa)));
+ choices.add(new Choice<Algorithm>(Algorithm.ECDSA, getResources().getString(
+ R.string.ecdsa)));
+ choices.add(new Choice<Algorithm>(Algorithm.ECDH, getResources().getString(
+ R.string.ecdh)));
+ ArrayAdapter<Choice<Algorithm>> adapter = new ArrayAdapter<Choice<Algorithm>>(context,
+ android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mAlgorithmSpinner.setAdapter(adapter);
+ // make RSA the default
+ for (int i = 0; i < choices.size(); ++i) {
+ if (choices.get(i).getId() == Algorithm.RSA) {
+ mAlgorithmSpinner.setSelection(i);
+ break;
+ }
}
}
@@ -161,58 +178,42 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mKeySizeSpinner.setAdapter(keySizeAdapter);
mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length
-
- dialog.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface di, int id) {
- di.dismiss();
- Choice newKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
- int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), getSelectedKeyLength());
-
- int flags = 0;
- if (mFlagCertify.isChecked()) {
- flags |= KeyFlags.CERTIFY_OTHER;
- }
- if (mFlagSign.isChecked()) {
- flags |= KeyFlags.SIGN_DATA;
- }
- if (mFlagEncrypt.isChecked()) {
- flags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
- }
- if (mFlagAuthenticate.isChecked()) {
- flags |= KeyFlags.AUTHENTICATION;
- }
-
- Long expiry;
- if (mNoExpiryCheckBox.isChecked()) {
- expiry = null;
- } else {
- Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- //noinspection ResourceType
- selectedCal.set(mExpiryDatePicker.getYear(),
- mExpiryDatePicker.getMonth(), mExpiryDatePicker.getDayOfMonth());
- expiry = selectedCal.getTime().getTime() / 1000;
- }
-
- SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
- newKeyAlgorithmChoice.getId(),
- newKeySize,
- flags,
- expiry
- );
- mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
- }
+ {
+ ArrayList<Choice<Curve>> choices = new ArrayList<Choice<Curve>>();
+
+ choices.add(new Choice<Curve>(Curve.NIST_P256, getResources().getString(
+ R.string.key_curve_nist_p256)));
+ choices.add(new Choice<Curve>(Curve.NIST_P384, getResources().getString(
+ R.string.key_curve_nist_p384)));
+ choices.add(new Choice<Curve>(Curve.NIST_P521, getResources().getString(
+ R.string.key_curve_nist_p521)));
+
+ /* @see SaveKeyringParcel
+ choices.add(new Choice<Curve>(Curve.BRAINPOOL_P256, getResources().getString(
+ R.string.key_curve_bp_p256)));
+ choices.add(new Choice<Curve>(Curve.BRAINPOOL_P384, getResources().getString(
+ R.string.key_curve_bp_p384)));
+ choices.add(new Choice<Curve>(Curve.BRAINPOOL_P512, getResources().getString(
+ R.string.key_curve_bp_p512)));
+ */
+
+ ArrayAdapter<Choice<Curve>> adapter = new ArrayAdapter<Choice<Curve>>(context,
+ android.R.layout.simple_spinner_item, choices);
+ mCurveSpinner.setAdapter(adapter);
+ // make NIST P-256 the default
+ for (int i = 0; i < choices.size(); ++i) {
+ if (choices.get(i).getId() == Curve.NIST_P256) {
+ mCurveSpinner.setSelection(i);
+ break;
}
- );
+ }
+ }
dialog.setCancelable(true);
- dialog.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface di, int id) {
- di.dismiss();
- }
- }
- );
+
+ // onClickListener are set in onStart() to override default dismiss behaviour
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.setNegativeButton(android.R.string.cancel, null);
final AlertDialog alertDialog = dialog.show();
@@ -246,7 +247,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- setKeyLengthSpinnerValuesForAlgorithm(((Choice) parent.getSelectedItem()).getId());
+ updateUiForAlgorithm(((Choice<Algorithm>) parent.getSelectedItem()).getId());
setCustomKeyVisibility();
setOkButtonAvailability(alertDialog);
@@ -260,6 +261,79 @@ public class AddSubkeyDialogFragment extends DialogFragment {
return alertDialog;
}
+ @Override
+ public void onStart() {
+ super.onStart(); //super.onStart() is where dialog.show() is actually called on the underlying dialog, so we have to do it after this point
+ AlertDialog d = (AlertDialog) getDialog();
+ if (d != null) {
+ Button positiveButton = d.getButton(Dialog.BUTTON_POSITIVE);
+ Button negativeButton = d.getButton(Dialog.BUTTON_NEGATIVE);
+ positiveButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mFlagCertify.isChecked() && !mFlagSign.isChecked()
+ && !mFlagEncrypt.isChecked() && !mFlagAuthenticate.isChecked()) {
+ Toast.makeText(getActivity(), R.string.edit_key_select_flag, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ Algorithm algorithm = ((Choice<Algorithm>) mAlgorithmSpinner.getSelectedItem()).getId();
+ Curve curve = null;
+ Integer keySize = null;
+ // For EC keys, add a curve
+ if (algorithm == Algorithm.ECDH || algorithm == Algorithm.ECDSA) {
+ curve = ((Choice<Curve>) mCurveSpinner.getSelectedItem()).getId();
+ // Otherwise, get a keysize
+ } else {
+ keySize = getProperKeyLength(algorithm, getSelectedKeyLength());
+ }
+
+ int flags = 0;
+ if (mFlagCertify.isChecked()) {
+ flags |= KeyFlags.CERTIFY_OTHER;
+ }
+ if (mFlagSign.isChecked()) {
+ flags |= KeyFlags.SIGN_DATA;
+ }
+ if (mFlagEncrypt.isChecked()) {
+ flags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
+ }
+ if (mFlagAuthenticate.isChecked()) {
+ flags |= KeyFlags.AUTHENTICATION;
+ }
+
+ long expiry;
+ if (mNoExpiryCheckBox.isChecked()) {
+ expiry = 0L;
+ } else {
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
+ //noinspection ResourceType
+ selectedCal.set(mExpiryDatePicker.getYear(),
+ mExpiryDatePicker.getMonth(), mExpiryDatePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ expiry = selectedCal.getTime().getTime() / 1000;
+ }
+
+ SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
+ algorithm, keySize, curve, flags, expiry
+ );
+ mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
+
+ // finally, dismiss the dialogue
+ dismiss();
+ }
+ });
+ negativeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ }
+ });
+ }
+ }
+
private int getSelectedKeyLength() {
final String selectedItemString = (String) mKeySizeSpinner.getSelectedItem();
final String customLengthString = getResources().getString(R.string.key_size_custom);
@@ -290,16 +364,16 @@ public class AddSubkeyDialogFragment extends DialogFragment {
* @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is
* inappropriate.
*/
- private int getProperKeyLength(int algorithmId, int currentKeyLength) {
+ private int getProperKeyLength(Algorithm algorithm, int currentKeyLength) {
final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192};
int properKeyLength = -1;
- switch (algorithmId) {
- case PublicKeyAlgorithmTags.RSA_GENERAL:
+ switch (algorithm) {
+ case RSA:
if (currentKeyLength > 1024 && currentKeyLength <= 16384) {
properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8);
}
break;
- case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+ case ELGAMAL:
int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length];
for (int i = 0; i < elGamalSupportedLengths.length; i++) {
elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength);
@@ -314,7 +388,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
}
properKeyLength = elGamalSupportedLengths[minimalIndex];
break;
- case PublicKeyAlgorithmTags.DSA:
+ case DSA:
if (currentKeyLength >= 512 && currentKeyLength <= 1024) {
properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64);
}
@@ -324,10 +398,10 @@ public class AddSubkeyDialogFragment extends DialogFragment {
}
private void setOkButtonAvailability(AlertDialog alertDialog) {
- final Choice selectedAlgorithm = (Choice) mAlgorithmSpinner.getSelectedItem();
- final int selectedKeySize = getSelectedKeyLength(); //Integer.parseInt((String) mKeySizeSpinner.getSelectedItem());
- final int properKeyLength = getProperKeyLength(selectedAlgorithm.getId(), selectedKeySize);
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(properKeyLength > 0);
+ Algorithm algorithm = ((Choice<Algorithm>) mAlgorithmSpinner.getSelectedItem()).getId();
+ boolean enabled = algorithm == Algorithm.ECDSA || algorithm == Algorithm.ECDH
+ || getProperKeyLength(algorithm, getSelectedKeyLength()) > 0;
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
}
private void setCustomKeyVisibility() {
@@ -343,38 +417,104 @@ public class AddSubkeyDialogFragment extends DialogFragment {
// hide keyboard after setting visibility to gone
if (visibility == View.GONE) {
InputMethodManager imm = (InputMethodManager)
- getActivity().getSystemService(getActivity().INPUT_METHOD_SERVICE);
+ getActivity().getSystemService(FragmentActivity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mCustomKeyEditText.getWindowToken(), 0);
}
}
- private void setKeyLengthSpinnerValuesForAlgorithm(int algorithmId) {
+ private void updateUiForAlgorithm(Algorithm algorithm) {
final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) mKeySizeSpinner.getAdapter();
- final Object selectedItem = mKeySizeSpinner.getSelectedItem();
keySizeAdapter.clear();
- switch (algorithmId) {
- case PublicKeyAlgorithmTags.RSA_GENERAL:
+ switch (algorithm) {
+ case RSA:
replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
+ mKeySizeSpinner.setSelection(1);
+ mKeySizeRow.setVisibility(View.VISIBLE);
+ mCurveRow.setVisibility(View.GONE);
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_rsa));
+ // allowed flags:
+ mFlagSign.setEnabled(true);
+ mFlagEncrypt.setEnabled(true);
+ mFlagAuthenticate.setEnabled(true);
+
+ if (mWillBeMasterKey) {
+ mFlagCertify.setEnabled(true);
+
+ mFlagCertify.setChecked(true);
+ mFlagSign.setChecked(false);
+ mFlagEncrypt.setChecked(false);
+ } else {
+ mFlagCertify.setEnabled(false);
+
+ mFlagCertify.setChecked(false);
+ mFlagSign.setChecked(true);
+ mFlagEncrypt.setChecked(true);
+ }
+ mFlagAuthenticate.setChecked(false);
break;
- case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+ case ELGAMAL:
replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
+ mKeySizeSpinner.setSelection(3);
+ mKeySizeRow.setVisibility(View.VISIBLE);
+ mCurveRow.setVisibility(View.GONE);
mCustomKeyInfoTextView.setText(""); // ElGamal does not support custom key length
+ // allowed flags:
+ mFlagCertify.setChecked(false);
+ mFlagCertify.setEnabled(false);
+ mFlagSign.setChecked(false);
+ mFlagSign.setEnabled(false);
+ mFlagEncrypt.setChecked(true);
+ mFlagEncrypt.setEnabled(true);
+ mFlagAuthenticate.setChecked(false);
+ mFlagAuthenticate.setEnabled(false);
break;
- case PublicKeyAlgorithmTags.DSA:
+ case DSA:
replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
+ mKeySizeSpinner.setSelection(2);
+ mKeySizeRow.setVisibility(View.VISIBLE);
+ mCurveRow.setVisibility(View.GONE);
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_dsa));
+ // allowed flags:
+ mFlagCertify.setChecked(false);
+ mFlagCertify.setEnabled(false);
+ mFlagSign.setChecked(true);
+ mFlagSign.setEnabled(true);
+ mFlagEncrypt.setChecked(false);
+ mFlagEncrypt.setEnabled(false);
+ mFlagAuthenticate.setChecked(false);
+ mFlagAuthenticate.setEnabled(false);
+ break;
+ case ECDSA:
+ mKeySizeRow.setVisibility(View.GONE);
+ mCurveRow.setVisibility(View.VISIBLE);
+ mCustomKeyInfoTextView.setText("");
+ // allowed flags:
+ mFlagCertify.setEnabled(mWillBeMasterKey);
+ mFlagCertify.setChecked(mWillBeMasterKey);
+ mFlagSign.setEnabled(true);
+ mFlagSign.setChecked(!mWillBeMasterKey);
+ mFlagEncrypt.setEnabled(false);
+ mFlagEncrypt.setChecked(false);
+ mFlagAuthenticate.setEnabled(true);
+ mFlagAuthenticate.setChecked(false);
+ break;
+ case ECDH:
+ mKeySizeRow.setVisibility(View.GONE);
+ mCurveRow.setVisibility(View.VISIBLE);
+ mCustomKeyInfoTextView.setText("");
+ // allowed flags:
+ mFlagCertify.setChecked(false);
+ mFlagCertify.setEnabled(false);
+ mFlagSign.setChecked(false);
+ mFlagSign.setEnabled(false);
+ mFlagEncrypt.setChecked(true);
+ mFlagEncrypt.setEnabled(true);
+ mFlagAuthenticate.setChecked(false);
+ mFlagAuthenticate.setEnabled(false);
break;
}
keySizeAdapter.notifyDataSetChanged();
- // when switching algorithm, try to select same key length as before
- for (int i = 0; i < keySizeAdapter.getCount(); i++) {
- if (selectedItem.equals(keySizeAdapter.getItem(i))) {
- mKeySizeSpinner.setSelection(i);
- break;
- }
- }
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index 4927a4d24..d0c9cea5b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -18,7 +18,9 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Dialog;
+import android.app.ProgressDialog;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
@@ -31,9 +33,10 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.util.Log;
import java.util.HashMap;
@@ -48,8 +51,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
private TextView mMainMessage;
private View mInflateView;
- private Messenger mMessenger;
-
/**
* Creates new instance of this delete file dialog fragment
*/
@@ -68,7 +69,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
+ final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER);
final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
@@ -83,6 +84,8 @@ public class DeleteKeyDialogFragment extends DialogFragment {
builder.setTitle(R.string.warning);
+ final boolean hasSecret;
+
// If only a single key has been selected
if (masterKeyIds.length == 1) {
long masterKeyId = masterKeyIds[0];
@@ -98,7 +101,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
}
);
String userId = (String) data.get(KeyRings.USER_ID);
- boolean hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;
+ hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;
// Set message depending on which key it is.
mMainMessage.setText(getString(
@@ -107,12 +110,12 @@ public class DeleteKeyDialogFragment extends DialogFragment {
userId
));
} catch (ProviderHelper.NotFoundException e) {
- sendMessageToHandler(MESSAGE_ERROR, null);
dismiss();
return null;
}
} else {
mMainMessage.setText(R.string.key_deletion_confirmation_multi);
+ hasSecret = false;
}
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
@@ -120,18 +123,45 @@ public class DeleteKeyDialogFragment extends DialogFragment {
@Override
public void onClick(DialogInterface dialog, int which) {
- boolean success = false;
- for (long masterKeyId : masterKeyIds) {
- int count = activity.getContentResolver().delete(
- KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null
- );
- success = count > 0;
- }
- if (success) {
- sendMessageToHandler(MESSAGE_OKAY, null);
- } else {
- sendMessageToHandler(MESSAGE_ERROR, null);
- }
+ // Send all information needed to service to import key in other thread
+ Intent intent = new Intent(getActivity(), KeychainIntentService.class);
+
+ intent.setAction(KeychainIntentService.ACTION_DELETE);
+
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ getActivity(),
+ getString(R.string.progress_deleting),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+ try {
+ Message msg = Message.obtain();
+ msg.copyFrom(message);
+ messenger.send(msg);
+ } catch (RemoteException e) {
+ Log.e(Constants.TAG, "messenger error", e);
+ }
+ }
+ };
+
+ // fill values for this action
+ Bundle data = new Bundle();
+ data.putLongArray(KeychainIntentService.DELETE_KEY_LIST, masterKeyIds);
+ data.putBoolean(KeychainIntentService.DELETE_IS_SECRET, hasSecret);
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ // show progress dialog
+ saveHandler.showProgressDialog(getActivity());
+
+ // start service with intent
+ getActivity().startService(intent);
+
dismiss();
}
});
@@ -146,23 +176,4 @@ public class DeleteKeyDialogFragment extends DialogFragment {
return builder.show();
}
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what Message integer you want to send
- */
- private void sendMessageToHandler(Integer what, Bundle data) {
- Message msg = Message.obtain();
- msg.what = what;
- if (data != null) {
- msg.setData(data);
- }
- 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);
- }
- }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index aa63f9944..f46e253c0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -25,9 +25,10 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
-import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.DatePicker;
import org.sufficientlysecure.keychain.Constants;
@@ -40,17 +41,14 @@ import java.util.TimeZone;
public class EditSubkeyExpiryDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_CREATION_DATE = "creation_date";
- private static final String ARG_EXPIRY_DATE = "expiry_date";
+ private static final String ARG_CREATION = "creation";
+ private static final String ARG_EXPIRY = "expiry";
- public static final int MESSAGE_NEW_EXPIRY_DATE = 1;
+ public static final int MESSAGE_NEW_EXPIRY = 1;
public static final int MESSAGE_CANCEL = 2;
- public static final String MESSAGE_DATA_EXPIRY_DATE = "expiry_date";
+ public static final String MESSAGE_DATA_EXPIRY = "expiry";
private Messenger mMessenger;
- private Calendar mExpiryCal;
-
- private DatePicker mDatePicker;
/**
* Creates new instance of this dialog fragment
@@ -60,8 +58,8 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
EditSubkeyExpiryDialogFragment frag = new EditSubkeyExpiryDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
- args.putSerializable(ARG_CREATION_DATE, creationDate);
- args.putSerializable(ARG_EXPIRY_DATE, expiryDate);
+ args.putSerializable(ARG_CREATION, creationDate);
+ args.putSerializable(ARG_EXPIRY, expiryDate);
frag.setArguments(args);
@@ -75,15 +73,17 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
- Date creationDate = new Date(getArguments().getLong(ARG_CREATION_DATE) * 1000);
- Date expiryDate = new Date(getArguments().getLong(ARG_EXPIRY_DATE) * 1000);
+ long creation = getArguments().getLong(ARG_CREATION);
+ long expiry = getArguments().getLong(ARG_EXPIRY);
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationCal.setTime(creationDate);
- mExpiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- mExpiryCal.setTime(expiryDate);
+ creationCal.setTime(new Date(creation * 1000));
+ final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTime(new Date(expiry * 1000));
- Log.d(Constants.TAG, "onCreateDialog");
+ // date picker works with default time zone, we need to convert from UTC to default timezone
+ creationCal.setTimeZone(TimeZone.getDefault());
+ expiryCal.setTimeZone(TimeZone.getDefault());
// Explicitly not using DatePickerDialog here!
// DatePickerDialog is difficult to customize and has many problems (see old git versions)
@@ -95,19 +95,64 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
View view = inflater.inflate(R.layout.edit_subkey_expiry_dialog, null);
alert.setView(view);
- mDatePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
+ final CheckBox noExpiry = (CheckBox) view.findViewById(R.id.edit_subkey_expiry_no_expiry);
+ final DatePicker datePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
+
+ noExpiry.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ datePicker.setVisibility(View.GONE);
+ } else {
+ datePicker.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+
+ // init date picker with default selected date
+ if (expiry == 0L) {
+ noExpiry.setChecked(true);
+ datePicker.setVisibility(View.GONE);
+
+ Calendar todayCal = Calendar.getInstance(TimeZone.getDefault());
+ if (creationCal.after(todayCal)) {
+ // Note: This is just for the rare cases where creation is _after_ today
+
+ // set it to creation date +1 day (don't set it to creationCal, it would break crash
+ // datePicker.setMinDate() execution with IllegalArgumentException
+ Calendar creationCalPlusOne = (Calendar) creationCal.clone();
+ creationCalPlusOne.add(Calendar.DAY_OF_YEAR, 1);
+ datePicker.init(
+ creationCalPlusOne.get(Calendar.YEAR),
+ creationCalPlusOne.get(Calendar.MONTH),
+ creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
+ null
+ );
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- // will crash with IllegalArgumentException if we set a min date
- // that is not before expiry
- if (creationCal.before(mExpiryCal)) {
- mDatePicker.setMinDate(creationCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
} else {
- // when creation date isn't available
- mDatePicker.setMinDate(mExpiryCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
+ // normally, just init with today
+ datePicker.init(
+ todayCal.get(Calendar.YEAR),
+ todayCal.get(Calendar.MONTH),
+ todayCal.get(Calendar.DAY_OF_MONTH),
+ null
+ );
}
+ } else {
+ noExpiry.setChecked(false);
+ datePicker.setVisibility(View.VISIBLE);
+
+ // set date picker to current expiry
+ datePicker.init(
+ expiryCal.get(Calendar.YEAR),
+ expiryCal.get(Calendar.MONTH),
+ expiryCal.get(Calendar.DAY_OF_MONTH),
+ null
+ );
+ }
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+ datePicker.setMinDate(creationCal.getTime().getTime());
}
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -115,34 +160,28 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int id) {
dismiss();
- Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- //noinspection ResourceType
- selectedCal.set(mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
+ long expiry;
+ if (noExpiry.isChecked()) {
+ expiry = 0L;
+ } else {
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getDefault());
+ //noinspection ResourceType
+ selectedCal.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
+ // date picker uses default time zone, we need to convert to UTC
+ selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
- if (mExpiryCal != null) {
long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (mExpiryCal.getTimeInMillis() / 86400000);
- if (numDays > 0) {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ - (expiryCal.getTimeInMillis() / 86400000);
+ if (numDays <= 0) {
+ Log.e(Constants.TAG, "Should not happen! Expiry num of days <= 0!");
+ throw new RuntimeException();
}
- } else {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ expiry = selectedCal.getTime().getTime() / 1000;
}
- }
- });
-
- alert.setNeutralButton(R.string.btn_no_date, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, null);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ data.putSerializable(MESSAGE_DATA_EXPIRY, expiry);
+ sendMessageToHandler(MESSAGE_NEW_EXPIRY, data);
}
});
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
index 093a04aff..0324dd3b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
@@ -25,6 +25,7 @@ import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnKeyListener;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
+import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import org.sufficientlysecure.keychain.R;
@@ -113,7 +114,12 @@ public class ProgressDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
- ProgressDialog dialog = new ProgressDialog(activity);
+ // if the progress dialog is displayed from the application class, design is missing
+ // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
+ ContextThemeWrapper context = new ContextThemeWrapper(activity,
+ R.style.Theme_AppCompat_Light);
+
+ ProgressDialog dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
new file mode 100644
index 000000000..e3c9804bb
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -0,0 +1,77 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.AttributeSet;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+
+public class CertifyKeySpinner extends KeySpinner {
+ private long mHiddenMasterKeyId = Constants.key.none;
+
+ public CertifyKeySpinner(Context context) {
+ super(context);
+ }
+
+ public CertifyKeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CertifyKeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setHiddenMasterKeyId(long hiddenMasterKeyId) {
+ this.mHiddenMasterKeyId = hiddenMasterKeyId;
+ reload();
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader() {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+ Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
+
+ // These are the rows that we will retrieve.
+ String[] projection = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.KEY_ID,
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.IS_EXPIRED,
+ KeychainContract.KeyRings.HAS_CERTIFY,
+ KeychainContract.KeyRings.HAS_ANY_SECRET
+ };
+
+ String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND "
+ + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND "
+ + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND "
+ + KeychainContract.KeyRings.IS_EXPIRED + " = 0 AND " + KeychainDatabase.Tables.KEYS + "."
+ + KeychainContract.KeyRings.MASTER_KEY_ID + " != " + mHiddenMasterKeyId;
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
index 20b9570bb..ceb3f665f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
@@ -111,7 +111,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getContext() instanceof FragmentActivity) {
- ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// These are the rows that we will retrieve.
@@ -143,6 +143,8 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
swapCursor(null);
}
});
+ } else {
+ Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass());
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java
index 31e01a7fb..b456b61ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java
@@ -24,7 +24,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
-import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -38,9 +38,7 @@ import org.sufficientlysecure.keychain.R;
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:foldedLabel="@string/TEXT_TO_DISPLAY_WHEN_FOLDED"
- custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED"
- custom:foldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_FOLDED"
- custom:unFoldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_UNFOLDED">
+ custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED">
<include layout="@layout/ELEMENTS_TO_BE_FOLDED"/>
@@ -49,7 +47,7 @@ import org.sufficientlysecure.keychain.R;
*/
public class FoldableLinearLayout extends LinearLayout {
- private ImageButton mFoldableIcon;
+ private ImageView mFoldableIcon;
private boolean mFolded;
private boolean mHasMigrated = false;
private Integer mShortAnimationDuration = null;
@@ -139,7 +137,7 @@ public class FoldableLinearLayout extends LinearLayout {
}
private void initialiseInnerViews() {
- mFoldableIcon = (ImageButton) mFoldableLayout.findViewById(R.id.foldableIcon);
+ mFoldableIcon = (ImageView) mFoldableLayout.findViewById(R.id.foldableIcon);
mFoldableIcon.setImageResource(R.drawable.ic_action_expand);
mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText);
mFoldableTextView.setText(mFoldedLabel);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
new file mode 100644
index 000000000..3a31fc9f4
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -0,0 +1,232 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.CursorAdapter;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.util.Log;
+
+public abstract class KeySpinner extends Spinner {
+ public interface OnKeyChangedListener {
+ public void onKeyChanged(long masterKeyId);
+ }
+
+ private long mSelectedKeyId;
+ private SelectKeyAdapter mAdapter = new SelectKeyAdapter();
+ private OnKeyChangedListener mListener;
+
+ public KeySpinner(Context context) {
+ super(context);
+ initView();
+ }
+
+ public KeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView();
+ }
+
+ public KeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initView();
+ }
+
+ private void initView() {
+ setAdapter(mAdapter);
+ super.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (mListener != null) {
+ mListener.onKeyChanged(id);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ if (mListener != null) {
+ mListener.onKeyChanged(Constants.key.none);
+ }
+ }
+ });
+ }
+
+ public abstract Loader<Cursor> onCreateLoader();
+
+ @Override
+ public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setOnKeyChangedListener(OnKeyChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ reload();
+ }
+
+ public void reload() {
+ if (getContext() instanceof FragmentActivity) {
+ ((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(hashCode(), null, new LoaderManager.LoaderCallbacks<Cursor>() {
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return KeySpinner.this.onCreateLoader();
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mAdapter.swapCursor(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ mAdapter.swapCursor(null);
+ }
+ });
+ } else {
+ Log.e(Constants.TAG, "KeySpinner must be attached to FragmentActivity, this is " + getContext().getClass());
+ }
+ }
+
+ public long getSelectedKeyId() {
+ return mSelectedKeyId;
+ }
+
+ public void setSelectedKeyId(long selectedKeyId) {
+ this.mSelectedKeyId = selectedKeyId;
+ }
+
+ private class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter {
+ private CursorAdapter inner;
+ private int mIndexUserId;
+ private int mIndexKeyId;
+ private int mIndexMasterKeyId;
+
+ public SelectKeyAdapter() {
+ inner = new CursorAdapter(null, null, 0) {
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return View.inflate(getContext(), R.layout.keyspinner_key, null);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
+ ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")"));
+ ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]);
+ ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)));
+ }
+
+ @Override
+ public long getItemId(int position) {
+ try {
+ return ((Cursor) getItem(position)).getLong(mIndexMasterKeyId);
+ } catch (Exception e) {
+ // This can happen on concurrent modification :(
+ return Constants.key.none;
+ }
+ }
+ };
+ }
+
+ public Cursor swapCursor(Cursor newCursor) {
+ if (newCursor == null) return inner.swapCursor(null);
+
+ mIndexKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.KEY_ID);
+ mIndexUserId = newCursor.getColumnIndex(KeychainContract.KeyRings.USER_ID);
+ mIndexMasterKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID);
+ if (newCursor.moveToFirst()) {
+ do {
+ if (newCursor.getLong(mIndexMasterKeyId) == mSelectedKeyId) {
+ setSelection(newCursor.getPosition() + 1);
+ }
+ } while (newCursor.moveToNext());
+ }
+ return inner.swapCursor(newCursor);
+ }
+
+ @Override
+ public int getCount() {
+ return inner.getCount() + 1;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ if (position == 0) return null;
+ return inner.getItem(position - 1);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position == 0) return Constants.key.none;
+ return inner.getItemId(position - 1);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ try {
+ View v = getDropDownView(position, convertView, parent);
+ v.findViewById(android.R.id.text1).setVisibility(View.GONE);
+ return v;
+ } catch (NullPointerException e) {
+ // This is for the preview...
+ return View.inflate(getContext(), android.R.layout.simple_list_item_1, null);
+ }
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ View v;
+ if (position == 0) {
+ if (convertView == null) {
+ v = inner.newView(null, null, parent);
+ } else {
+ v = convertView;
+ }
+ ((TextView) v.findViewById(android.R.id.title)).setText("None");
+ v.findViewById(android.R.id.text1).setVisibility(View.GONE);
+ v.findViewById(android.R.id.text2).setVisibility(View.GONE);
+ } else {
+ v = inner.getView(position - 1, convertView, parent);
+ v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE);
+ v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE);
+ }
+ return v;
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
deleted file mode 100644
index a48d2a026..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NoSwipeWrapContentViewPager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-public class NoSwipeWrapContentViewPager extends android.support.v4.view.ViewPager {
- public NoSwipeWrapContentViewPager(Context context) {
- super(context);
- }
-
- public NoSwipeWrapContentViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- int height;
- View child = getChildAt(getCurrentItem());
- if (child != null) {
- child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- height = child.getMeasuredHeight();
- } else {
- height = 0;
- }
-
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent arg0) {
- // Never allow swiping to switch between pages
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Never allow swiping to switch between pages
- return false;
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
new file mode 100644
index 000000000..a1ed2c065
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
@@ -0,0 +1,65 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.AttributeSet;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+
+public class SignKeySpinner extends KeySpinner {
+ public SignKeySpinner(Context context) {
+ super(context);
+ }
+
+ public SignKeySpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SignKeySpinner(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader() {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+ Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
+
+ // These are the rows that we will retrieve.
+ String[] projection = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.KEY_ID,
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.IS_EXPIRED,
+ KeychainContract.KeyRings.HAS_SIGN,
+ KeychainContract.KeyRings.HAS_ANY_SECRET
+ };
+
+ String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeychainContract.KeyRings.HAS_SIGN + " NOT NULL AND "
+ + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
index 9acc7a73b..99db634ac 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
@@ -50,7 +50,6 @@ public class AlgorithmNames {
mEncryptionNames.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
mEncryptionNames.put(PGPEncryptedData.IDEA, "IDEA");
- mHashNames.put(HashAlgorithmTags.MD5, "MD5");
mHashNames.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
mHashNames.put(HashAlgorithmTags.SHA1, "SHA-1");
mHashNames.put(HashAlgorithmTags.SHA224, "SHA-224");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
index 70c7d80fe..48f10d4b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
@@ -17,21 +17,16 @@
package org.sufficientlysecure.keychain.util;
-public class Choice {
+public class Choice <E> {
private String mName;
- private int mId;
+ private E mId;
- public Choice() {
- mId = -1;
- mName = "";
- }
-
- public Choice(int id, String name) {
+ public Choice(E id, String name) {
mId = id;
mName = name;
}
- public int getId() {
+ public E getId() {
return mId;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
index 5a4bf5311..09275fc95 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java
@@ -46,10 +46,11 @@ public class FileImportCache<E extends Parcelable> {
private Context mContext;
- private static final String FILENAME = "key_import.pcl";
+ private final String mFilename;
- public FileImportCache(Context context) {
- this.mContext = context;
+ public FileImportCache(Context context, String filename) {
+ mContext = context;
+ mFilename = filename;
}
public void writeCache(ArrayList<E> selectedEntries) throws IOException {
@@ -64,7 +65,7 @@ public class FileImportCache<E extends Parcelable> {
throw new IOException("cache dir is null!");
}
- File tempFile = new File(mContext.getCacheDir(), FILENAME);
+ File tempFile = new File(mContext.getCacheDir(), mFilename);
DataOutputStream oos = new DataOutputStream(new FileOutputStream(tempFile));
@@ -91,6 +92,10 @@ public class FileImportCache<E extends Parcelable> {
}
public Iterator<E> readCache() throws IOException {
+ return readCache(true);
+ }
+
+ public Iterator<E> readCache(final boolean deleteAfterRead) throws IOException {
File cacheDir = mContext.getCacheDir();
if (cacheDir == null) {
@@ -98,7 +103,7 @@ public class FileImportCache<E extends Parcelable> {
throw new IOException("cache dir is null!");
}
- final File tempFile = new File(cacheDir, FILENAME);
+ final File tempFile = new File(cacheDir, mFilename);
final DataInputStream ois = new DataInputStream(new FileInputStream(tempFile));
return new Iterator<E>() {
@@ -165,7 +170,10 @@ public class FileImportCache<E extends Parcelable> {
if (!closed) {
try {
ois.close();
- tempFile.delete();
+ if (deleteAfterRead) {
+ //noinspection ResultOfMethodCallIgnored
+ tempFile.delete();
+ }
} catch (IOException e) {
// nvm
}
@@ -176,4 +184,17 @@ public class FileImportCache<E extends Parcelable> {
};
}
+
+ public boolean delete() throws IOException {
+
+ File cacheDir = mContext.getCacheDir();
+ if (cacheDir == null) {
+ // https://groups.google.com/forum/#!topic/android-developers/-694j87eXVU
+ throw new IOException("cache dir is null!");
+ }
+
+ final File tempFile = new File(cacheDir, mFilename);
+ return tempFile.delete();
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java
new file mode 100644
index 000000000..4bb4ca5de
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java
@@ -0,0 +1,29 @@
+package org.sufficientlysecure.keychain.util;
+
+import org.sufficientlysecure.keychain.pgp.Progressable;
+
+/** This is a simple variant of ProgressScaler which shows a fixed progress message, ignoring
+ * the provided ones.
+ */
+public class ProgressFixedScaler extends ProgressScaler {
+
+ final int mResId;
+
+ public ProgressFixedScaler(Progressable wrapped, int from, int to, int max, int resId) {
+ super(wrapped, from, to, max);
+ mResId = resId;
+ }
+
+ public void setProgress(int resourceId, int progress, int max) {
+ if (mWrapped != null) {
+ mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax);
+ }
+ }
+
+ public void setProgress(String message, int progress, int max) {
+ if (mWrapped != null) {
+ mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax);
+ }
+ }
+
+}
diff --git a/OpenKeychain/src/main/res/layout-large/api_apps_list_activity.xml b/OpenKeychain/src/main/res/layout-large/api_apps_list_activity.xml
index 88686bbbc..af06614b9 100644
--- a/OpenKeychain/src/main/res/layout-large/api_apps_list_activity.xml
+++ b/OpenKeychain/src/main/res/layout-large/api_apps_list_activity.xml
@@ -1,20 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
- <android.support.v4.widget.FixedDrawerLayout
- android:id="@+id/drawer_layout"
-
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <android.support.v4.widget.FixedDrawerLayout
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <include layout="@layout/drawer_list"/>
+ <include layout="@layout/drawer_list" />
</android.support.v4.widget.FixedDrawerLayout>
- <include layout="@layout/api_apps_list_content"/>
+ <include layout="@layout/api_apps_list_content" />
</FrameLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml b/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml
index 9e9f37391..06487a982 100644
--- a/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml
+++ b/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml
@@ -1,19 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.widget.FixedDrawerLayout
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v4.widget.FixedDrawerLayout
- xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
- android:id="@+id/drawer_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <include layout="@layout/drawer_list"/>
+ <include layout="@layout/drawer_list" />
</android.support.v4.widget.FixedDrawerLayout>
- <include layout="@layout/decrypt_content"/>
+ <include layout="@layout/decrypt_content" />
</FrameLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout-large/encrypt_activity.xml b/OpenKeychain/src/main/res/layout-large/encrypt_activity.xml
index 355580fad..84b2891e3 100644
--- a/OpenKeychain/src/main/res/layout-large/encrypt_activity.xml
+++ b/OpenKeychain/src/main/res/layout-large/encrypt_activity.xml
@@ -1,19 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
<android.support.v4.widget.FixedDrawerLayout
- xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
- xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include layout="@layout/drawer_list"/>
+ <include layout="@layout/drawer_list" />
</android.support.v4.widget.FixedDrawerLayout>
- <include layout="@layout/encrypt_content"/>
+ <include layout="@layout/encrypt_content" />
</FrameLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout-large/key_list_activity.xml b/OpenKeychain/src/main/res/layout-large/key_list_activity.xml
index 6abbea13f..039081cd7 100644
--- a/OpenKeychain/src/main/res/layout-large/key_list_activity.xml
+++ b/OpenKeychain/src/main/res/layout-large/key_list_activity.xml
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
<android.support.v4.widget.FixedDrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include layout="@layout/drawer_list"/>
+ <include layout="@layout/drawer_list" />
</android.support.v4.widget.FixedDrawerLayout>
- <include layout="@layout/key_list_content"/>
+ <include layout="@layout/key_list_content" />
</FrameLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/add_subkey_dialog.xml b/OpenKeychain/src/main/res/layout/add_subkey_dialog.xml
index e1ccfee1f..7af73be09 100644
--- a/OpenKeychain/src/main/res/layout/add_subkey_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/add_subkey_dialog.xml
@@ -34,7 +34,7 @@
android:padding="4dp" />
</TableRow>
- <TableRow>
+ <TableRow android:id="@+id/add_subkey_row_size">
<TextView
android:layout_width="wrap_content"
@@ -50,6 +50,24 @@
android:padding="4dp" />
</TableRow>
+ <TableRow
+ android:id="@+id/add_subkey_row_curve"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_ecc_curve"/>
+
+ <Spinner
+ android:id="@+id/add_subkey_curve"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:padding="4dp"/>
+ </TableRow>
+
<TextView
android:id="@+id/add_subkey_custom_key_size_label"
android:layout_width="wrap_content"
diff --git a/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml b/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml
index aaeae78e0..d8e1d9ad8 100644
--- a/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml
@@ -59,9 +59,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:foldedLabel="@string/api_settings_show_advanced"
- custom:unFoldedLabel="@string/api_settings_hide_advanced"
- custom:foldedIcon="fa-chevron-right"
- custom:unFoldedIcon="fa-chevron-down">
+ custom:unFoldedLabel="@string/api_settings_hide_advanced">
<TextView
android:layout_width="match_parent"
diff --git a/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml b/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
index ceea1d8a6..6ef31913a 100644
--- a/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
@@ -40,9 +40,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:foldedLabel="@string/api_settings_show_info"
- custom:unFoldedLabel="@string/api_settings_hide_info"
- custom:foldedIcon="fa-chevron-right"
- custom:unFoldedIcon="fa-chevron-down">
+ custom:unFoldedLabel="@string/api_settings_hide_info">
<TextView
android:layout_width="match_parent"
@@ -67,7 +65,7 @@
android:id="@+id/api_app_settings_package_signature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="Base64 encoded signature"
+ android:text="Base64 encoded hash of signature"
android:textAppearance="?android:attr/textAppearanceSmall" />
</org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml b/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
index a10592607..bf4d0a70d 100644
--- a/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
+++ b/OpenKeychain/src/main/res/layout/api_remote_select_pub_keys.xml
@@ -4,13 +4,13 @@
android:layout_height="fill_parent"
android:orientation="vertical" >
- <org.sufficientlysecure.htmltextview.HtmlTextView
+ <TextView
android:id="@+id/api_select_pub_keys_text"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="8dp"
- android:paddingBottom="0dip"
- android:text="Set in-code!"
+ android:paddingTop="8dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall" />
<FrameLayout
diff --git a/OpenKeychain/src/main/res/layout/certify_key_activity.xml b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
index 34d4dbd57..9796a6ddc 100644
--- a/OpenKeychain/src/main/res/layout/certify_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -8,6 +7,7 @@
<include layout="@layout/notify_area" />
<ScrollView
+ android:id="@+id/certify_scroll_view"
android:layout_width="wrap_content"
android:layout_height="match_parent">
@@ -26,14 +26,10 @@
android:layout_marginTop="14dp"
android:text="@string/section_certification_key" />
- <fragment
- android:id="@+id/sign_key_select_key_fragment"
- android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ <org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner
+ android:id="@+id/certify_key_spinner"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- tools:layout="@layout/select_secret_key_layout_fragment" />
+ android:layout_height="wrap_content" />
<TextView
style="@style/SectionHeader"
@@ -119,8 +115,7 @@
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/view_key_user_ids"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:descendantFocusability="blocksDescendants" />
+ android:layout_height="wrap_content" />
<TextView
style="@style/SectionHeader"
@@ -184,7 +179,6 @@
</LinearLayout>
-
</LinearLayout>
</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml b/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
index 062f07863..8a713115e 100644
--- a/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/edit_subkey_expiry_dialog.xml
@@ -4,6 +4,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <CheckBox
+ android:id="@+id/edit_subkey_expiry_no_expiry"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:checked="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_no_date" />
+
<DatePicker
android:id="@+id/edit_subkey_expiry_date_picker"
android:layout_gravity="center_horizontal"
diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
index 4d82477bc..2189a1f34 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
@@ -24,7 +24,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/label_asymmetric_from" />
- <Spinner
+ <org.sufficientlysecure.keychain.ui.widget.SignKeySpinner
android:id="@+id/sign"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/OpenKeychain/src/main/res/layout/encrypt_content.xml b/OpenKeychain/src/main/res/layout/encrypt_content.xml
index e5edc6657..d029e7b83 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_content.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_content.xml
@@ -9,13 +9,11 @@
<include layout="@layout/notify_area"/>
- <org.sufficientlysecure.keychain.ui.widget.NoSwipeWrapContentViewPager
+ <FrameLayout
android:id="@+id/encrypt_pager_mode"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- </org.sufficientlysecure.keychain.ui.widget.NoSwipeWrapContentViewPager>
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
<android.support.v4.view.ViewPager
android:id="@+id/encrypt_pager_content"
diff --git a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
index 3d2fb688b..13cf7c225 100644
--- a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
+++ b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
@@ -11,14 +11,13 @@
android:orientation="horizontal"
android:clickable="true">
- <ImageButton
+ <ImageView
android:id="@+id/foldableIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="10dp"
- android:src="@drawable/ic_action_expand"
- android:background="@drawable/button_no_style"/>
+ android:src="@drawable/ic_action_expand"/>
<TextView
android:id="@+id/foldableText"
diff --git a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
index 062289688..c70236e07 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml
@@ -11,7 +11,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top|left"
- android:hint="@string/hint_keybase_search"
+ android:hint="@string/hint_keybase_search_hint"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions"
android:singleLine="true"
diff --git a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
index 47c354c53..62e7d740c 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml
@@ -10,13 +10,13 @@
android:layout_height="?android:attr/listPreferredItemHeight"
android:orientation="horizontal">
- <EditText
+ <AutoCompleteTextView
android:id="@+id/import_server_query"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top|left"
- android:hint="@string/hint_public_keys"
+ android:hint="@string/hint_keyserver_search_hint"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions"
android:singleLine="true"
diff --git a/OpenKeychain/src/main/res/layout/key_list_activity.xml b/OpenKeychain/src/main/res/layout/key_list_activity.xml
index 297fc526e..03ef85381 100644
--- a/OpenKeychain/src/main/res/layout/key_list_activity.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_activity.xml
@@ -4,16 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <include layout="@layout/notify_area" />
-
- <include layout="@layout/key_list_content" />
-
- </LinearLayout>
+ <include layout="@layout/key_list_content" />
<include layout="@layout/drawer_list" />
diff --git a/OpenKeychain/src/main/res/layout/key_list_content.xml b/OpenKeychain/src/main/res/layout/key_list_content.xml
index e58e42961..66b009c78 100644
--- a/OpenKeychain/src/main/res/layout/key_list_content.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_content.xml
@@ -1,14 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/notify_area" />
+
+ <FrameLayout
android:id="@+id/content_frame"
android:layout_marginLeft="@dimen/drawer_content_padding"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <fragment
+ <fragment
android:id="@+id/key_list_fragment"
android:name="org.sufficientlysecure.keychain.ui.KeyListFragment"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-</FrameLayout> \ No newline at end of file
+ android:layout_height="match_parent" />
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_signkey.xml b/OpenKeychain/src/main/res/layout/keyspinner_key.xml
index 703f9133b..703f9133b 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_signkey.xml
+++ b/OpenKeychain/src/main/res/layout/keyspinner_key.xml
diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml
index b15a73c0e..451eb30ee 100644
--- a/OpenKeychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml
@@ -4,7 +4,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <include layout="@layout/notify_area"/>
+ <include layout="@layout/notify_area" />
<LinearLayout
android:id="@+id/view_key_status_layout"
@@ -16,17 +16,17 @@
android:orientation="horizontal">
<ImageView
+ android:id="@+id/view_key_status_image"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/view_key_status_image" />
+ android:layout_height="wrap_content" />
<TextView
+ android:id="@+id/view_key_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/view_key_status_text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dp"/>
+ android:layout_marginLeft="8dp" />
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
index 00b3f85c5..1cf826b30 100644
--- a/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_certs_fragment.xml
@@ -1,24 +1,47 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <se.emilsjolander.stickylistheaders.StickyListHeadersListView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/list"
- android:fastScrollEnabled="true"
- android:paddingBottom="16dp"
- android:paddingLeft="16dp"
- android:paddingRight="32dp"
- android:scrollbarStyle="outsideOverlay" />
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/empty_certs"
- android:id="@+id/empty"
- android:visibility="gone"
- android:layout_gravity="center" />
+ android:background="@color/holo_gray_bright"
+ android:padding="8dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/certs_text"
+ android:gravity="center_horizontal" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider"
+ android:id="@+id/view_key_status_divider" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <se.emilsjolander.stickylistheaders.StickyListHeadersListView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/list"
+ android:fastScrollEnabled="true"
+ android:paddingBottom="16dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="32dp"
+ android:scrollbarStyle="outsideOverlay" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/empty_certs"
+ android:id="@+id/empty"
+ android:visibility="gone"
+ android:layout_gravity="center" />
+
+ </FrameLayout>
+
+</LinearLayout>
-</FrameLayout>
diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml
index 056dd5986..6e571243d 100644
--- a/OpenKeychain/src/main/res/menu/key_list.xml
+++ b/OpenKeychain/src/main/res/menu/key_list.xml
@@ -32,6 +32,12 @@
android:title="@string/menu_import_existing_key" />
<item
+ android:id="@+id/menu_key_list_debug_cons"
+ app:showAsAction="never"
+ android:title="Debug / Consolidate"
+ android:visible="false" />
+
+ <item
android:id="@+id/menu_key_list_debug_read"
app:showAsAction="never"
android:title="Debug / DB restore"
diff --git a/OpenKeychain/src/main/res/raw-cs/help_about.html b/OpenKeychain/src/main/res/raw-cs/help_about.html
index f536fecbd..6394ce319 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_about.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_about.html
@@ -3,11 +3,11 @@
<body>
<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>
+<p>Licence: GPLv3+</p>
-<h2>Developers</h2>
+<h2>Vývojáři</h2>
<ul>
-<li>Dominik Schürmann (Maintainer)</li>
+<li>Dominik Schürmann (Hlavní vývojář)</li>
<li>Art O Cathain</li>
<li>Ash Hughes</li>
<li>Brian C. Barnes</li>
@@ -27,7 +27,7 @@
<li>Tim Bray</li>
<li>Vincent Breitmoser</li>
</ul>
-<h2>Libraries</h2>
+<h2>Knihovny</h2>
<ul>
<li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
diff --git a/OpenKeychain/src/main/res/raw-cs/help_changelog.html b/OpenKeychain/src/main/res/raw-cs/help_changelog.html
index e27ac7475..41ec2cad6 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html b/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
index 88492731c..d691df871 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_nfc_beam.html
@@ -1,12 +1,12 @@
<html>
<head></head>
<body>
-<h2>How to receive keys</h2>
+<h2>Jak přijmout klíče</h2>
<ol>
-<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>
+<li>Navigujte na kontakt vašeho partnera a otevřete ten který chcete sdílet.</li>
+<li>Podržte dvě zařízení zády k sobě (musí se téměř dotýkat) a ucítíte vibraci.</li>
+<li>Po tom co ucítíte vibraci, uvidíte že se obsah na displeji zařízení vašeho partnera změní na objekt typu karta s animací na pozadí připomínající rychlost warpu ze Star Treku.</li>
+<li>Tapněte na kartu a obsach se nahraje do zařízení.</li>
</ol>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-cs/help_start.html b/OpenKeychain/src/main/res/raw-cs/help_start.html
index 51a76c01e..eaffc2389 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_start.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_start.html
@@ -1,22 +1,22 @@
<html>
<head></head>
<body>
-<h2>Getting started</h2>
-<p>First you need a personal secret key. Create one via the option menus in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<h2>Začínáme</h2>
+<p>Nejprve potřebujete osobní tajný klíč. Vytvořte si ho pomocí volby v menu v sekci "Klíče" nebo importujte existující tajné klíče. Následně můžete stáhnout klíče vašich známých nebo si je vyměnit pomocí QR kódu případně 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>
+<p>Doporučujeme instalaci <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> pro zlepšení práce se soubory a <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> pro skenování generovaných QR kódů. Kliknutí na odkazy otevře Google Play Store nebo F-Droid odkud můžete začít installovat.</p>
-<h2>Applications</h2>
-<p>Several applications support OpenKeychain to encrypt/sign your private communication:<br><img src="apps_k9"><br>K-9 Mail: OpenKeychain support available in current <a href="https://github.com/k9mail/k-9/releases/tag/4.904">alpha build</a>!<br><a href="market://details?id=eu.siacs.conversations"><img src="apps_conversations"><br>Conversations</a>: Jabber/XMPP client<br><a href="market://details?id=org.lf_net.pgpunlocker"><img src="apps_pgpauth"><br>PGPAuth</a>: App to send a PGP-signed request to a server to open or close something, e.g. a door</p>
+<h2>Aplikace</h2>
+<p>Několik aplikací umožňuje šifrovat/podepsat privátní komunikaci pomocí OpenKeychain:<br><img src="apps_k9"><br>K-9 Mail: podpora OpenKeychain v aktualní verzi <a href="https://github.com/k9mail/k-9/releases/tag/4.904">alpha build</a>!<br><a href="market://details?id=eu.siacs.conversations"><img src="apps_conversations"><br>Konverzace</a>: Jabber/XMPP client<br><a href="market://details?id=org.lf_net.pgpunlocker"><img src="apps_pgpauth"><br>PGPAuth</a>: Appka sloužící k odesílání požadavků podepsaných PGP na servery pro otevření nebo zavření něčeho, třeba dveří</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>Našel jsem bug v OpenChain!</h2>
+<p>Reportujte chyby pomocí <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue trackeru 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>Přispět</h2>
+<p>Pokud chcete pomoci vyvýjet OpenKeychain tak, že přispějete svými kodérskými schopnostmi <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">přečtěte si naší malou příručku na Githubu</a>.</p>
-<h2>Translations</h2>
-<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+<h2>Překlady</h2>
+<p>Pomozte s překladem OpenKeychain! Každý může participovat na <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain na Transifexu</a></p>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-cs/help_wot.html b/OpenKeychain/src/main/res/raw-cs/help_wot.html
index 29790139b..30288f2bb 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_wot.html
+++ b/OpenKeychain/src/main/res/raw-cs/help_wot.html
@@ -1,7 +1,7 @@
<html>
<head></head>
<body>
-<h2>Web of Trust</h2>
+<h2>Síť důvěry</h2>
<p>The Web of Trust describes the part of PGP which deals with creation and bookkeeping of certifications. It provides mechanisms to help the user keep track of who a public key belongs to, and share this information with others; To ensure the privacy of encrypted communication, it is essential to know that the public key you encrypt to belongs to the person you think it does.</p>
<h2>Support in OpenKeychain</h2>
diff --git a/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html b/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
index 083e055c7..09128be62 100644
--- a/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
+++ b/OpenKeychain/src/main/res/raw-cs/nfc_beam_share.html
@@ -2,10 +2,10 @@
<head></head>
<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>Tap the card and the content will then load on the other person’s device.</li>
+<li>Ujistěte se, že NFC je zapnuto v Nastavení &gt; Další &gt; NFC a ujistěte se, že Android Beam ve stejné sekci je také zapnutý.</li>
+<li>Podržte dvě zařízení zády k sobě (musí se téměř dotýkat) a ucítíte vibraci.</li>
+<li>Po tom co ucítíte vibraci, uvidíte že se obsah na displeji zařízení vašeho partnera změní na objekt typu karta s animací na pozadí připomínající rychlost warpu ze Star Treku.</li>
+<li>Tapněte na kartu a obsach se nahraje do zařízení.</li>
</ol>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-de/help_about.html b/OpenKeychain/src/main/res/raw-de/help_about.html
index f5622d54a..934caa832 100644
--- a/OpenKeychain/src/main/res/raw-de/help_about.html
+++ b/OpenKeychain/src/main/res/raw-de/help_about.html
@@ -5,7 +5,7 @@
<p><a href="http://www.openkeychain.org">OpenKeychain</a> ist eine OpenPGP-Implementierung für Android.</p>
<p>Lizenz: GPLv3+</p>
-<h2>Developers</h2>
+<h2>Engwickler</h2>
<ul>
<li>Dominik Schürmann (Maintainer)</li>
<li>Art O Cathain</li>
diff --git a/OpenKeychain/src/main/res/raw-de/help_changelog.html b/OpenKeychain/src/main/res/raw-de/help_changelog.html
index 674d9c93f..0a8f95e83 100644
--- a/OpenKeychain/src/main/res/raw-de/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-de/help_changelog.html
@@ -3,17 +3,18 @@
<body>
<h2>2.8</h2>
<ul>
-<li>So many bugs have been fixed in this release that we focus on the main new features</li>
-<li>Key edit: awesome new design, key revocation</li>
-<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
-<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
-<li>File encryption: awesome new design, support for encrypting multiple files</li>
-<li>New icons to show status of key (by Brennan Novak)</li>
-<li>Important bug fix: Importing of large key collections from a file is now possible</li>
-<li>Notification showing cached passphrases</li>
-</ul>
-<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
+<li>Es wurden in diesem Release so viele Bugs ausgebessert, sodass wir uns besser auf die neuen Funktionen konzentrieren</li>
+<li>Schlüsselbearbeitung: tolles neues Design und Schlüsselrückruf</li>
+<li>Schlüsselimport: tolles neues Design, gesicherte Verbindungen zum Schlüsselserver über HKPS, Schlüsselserver [?] über DNS SRV Einträge </li>
+<li>Neuer Bildschirm bei der ersten Öffnung</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>Dateiverschlüsselung: tolles neues Design, Unterstützung für mehrere Dateien</li>
+<li>Neue Icons zum Anzeigen des Schlüsselstatus' (von Brennan Novak)</li>
+<li>Wichtige Ausbesserung eines Bugs: Importieren größerer Schlüsselsammlungen aus einer Datei ist nun möglich </li>
+<li>Benachrichtigung, die die Passphrasen im Cache anzeigt </li>
+<li>Keys are connected to Android's contacts</li>
+</ul>
+<p>Dieser Release wäre ohne die Arbeit von Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray und Thialfihar nicht möglich </p>
<h2>2.7</h2>
<ul>
@@ -21,7 +22,7 @@
<li>Neues Schlüsselansicht Design (Dominik, Vincent)</li>
<li>Neue flache Android Buttons (Dominik, Vincent)</li>
<li>API Fehler behoben (Dominik)</li>
-<li>keybase.io importiert (Tim Bray)</li>
+<li>Import aus keybase.io (Tim Bray)</li>
</ul>
<h2>2.6.1</h2>
<ul>
@@ -29,17 +30,17 @@
</ul>
<h2>2.6</h2>
<ul>
-<li>Key certifications (thanks to Vincent Breitmoser)</li>
-<li>Support for GnuPG partial secret keys (thanks to Vincent Breitmoser)</li>
-<li>New design for signature verification</li>
-<li>Custom key length (thanks to Greg Witczak)</li>
-<li>Fix share-functionality from other apps</li>
+<li>Schlüsselzertifizierungen (danke an Vincent Breitmoser) </li>
+<li>Unterstützung für GnuPG-Teilschlüssel (danke an Vincent Breitmoser) </li>
+<li>Neues Design für Signaturverifikation</li>
+<li>Benutzerdefinierte Schlüssellänge (Dank an Greg Witczak)</li>
+<li>Fehler behoben bei der Teilen-Funktion von anderen Apps</li>
</ul>
<h2>2.5</h2>
<ul>
-<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
-<li>New modern design for encrypt/decrypt screens</li>
+<li>Fehler bei der Entschlüsselung symmetrischer PGP Nachrichten/Dateien behoben </li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
+<li>Neues modernes Design für Verschlüsselungs-/Entschlüsselungs-Bildschirme</li>
<li>OpenPGP API Version 3 (mehrfache api accounts, interne fehlerbehebungen, schlüssel suche)</li>
</ul>
<h2>2.4</h2>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-de/help_start.html b/OpenKeychain/src/main/res/raw-de/help_start.html
index dfff2bc03..0764c9ebb 100644
--- a/OpenKeychain/src/main/res/raw-de/help_start.html
+++ b/OpenKeychain/src/main/res/raw-de/help_start.html
@@ -1,7 +1,7 @@
<html>
<head></head>
<body>
-<h2>Los gehts</h2>
+<h2>Los geht's</h2>
<p>Zuerst benötigen Sie einen privaten Schlüssel. Erstellen Sie einen Schlüssel über den Eintrag "Schlüssel" im Menu oder importieren Sie bestehende private Schlüssel. Anschließend können Sie die Schlüssel ihrer Freunde runterladen oder Sie über QR-Codes oder NFC austauschen.</p>
<p>Es wird empfohlen, dass Sie den <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> für ein verbessertes Dateihandling installieren, sowie den <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> installieren um erstellte QR-Codes zu scannen. Die Links führen entweder zu Google Play oder zu F-Droid zur Installation.</p>
@@ -13,10 +13,10 @@
<p>Bitte berichten Sie Bugs mithilfe des <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Issue Trackers der OpenKeychain</a>.</p>
<h2>Unterstützen</h2>
-<p>Wenn Sie uns bei der Entwickelung von OpenKeychain durch das Beisteuern von Code helfen wollt, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">schaut euch unsere kurze Anleitung auf Github an</a>.</p>
+<p>Wenn Sie uns bei der Entwickelung von OpenKeychain durch das Beisteuern von Code helfen wollen, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">schauen Sie unsere kurze Anleitung auf Github an</a>.</p>
<h2>Übersetzungen</h2>
-<p>Hilf mit OpenKeychain zu übersetzten! Jeder kann auf <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain auf Transifex</a> mitmachen.</p>
+<p>Hilf mit, OpenKeychain zu übersetzten! Jeder kann auf <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain auf Transifex</a> mitmachen.</p>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-es/help_changelog.html b/OpenKeychain/src/main/res/raw-es/help_changelog.html
index a6b2d269d..cf778141a 100644
--- a/OpenKeychain/src/main/res/raw-es/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-es/help_changelog.html
@@ -7,11 +7,12 @@
<li>Edición de clave: Tremendo nuevo diseño, revocación de clave</li>
<li>Importación de clave: Impresionante nuevo diseño, conexiones seguras al servidor de claves vía hkps, el servidor de claves resuelve mediante registros DNS SRV</li>
<li>Nueva pantalla de primer inicio</li>
-<li>Nueva pantalla de creación de clave: Autocompletado del nombre y correo electrónico basado en sus cuentas Android personales</li>
+<li>Nueva pantalla de creación: autocompletado de nombre y correo electrónico basado en sus cuentas de Android personales</li>
<li>Cifrado de fichero: Pasmante nuevo diseño, soporte para cifrar múltiples ficheros.</li>
<li>Nuevos iconos para mostrar el estado de la clave (por Brennan Novak)</li>
<li>Importante reparacion de fallo: Ahora es posible la importación de grandes colecciones de claves desde un fichero</li>
<li>Notificación que muestra las frases contraseña almacenadas en caché</li>
+<li>Las claves están conectadas con los contactos de Android</li>
</ul>
<p>Esta versión no sería posible sin el trabajo de Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -33,13 +34,13 @@
<li>Soporte para claves secretas parciales de GnuPG (gracias a Vincent Breitmoser)</li>
<li>Nuevo diseño para verificación de firma</li>
<li>Tamaño de clave personalizado (gracias a Greg Witczak)</li>
-<li>Fix share-functionality from other apps</li>
+<li>Repara la funcionalidad de compartido desde otras aplicaciones</li>
</ul>
<h2>2.5</h2>
<ul>
-<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
-<li>New modern design for encrypt/decrypt screens</li>
+<li>Repara el descifrado de mensajes/ficheros pgp simétricos</li>
+<li>Pantalla de edición de clave refactorizada (gracias a Ash Hughes)</li>
+<li>Nuevo diseño moderno para pantallas de cifrado/descifrado</li>
<li>OpenPGP API versión 3 (múltiples cuentas API, reparaciones internas, comprobación de claves)</li>
</ul>
<h2>2.4</h2>
@@ -47,45 +48,45 @@
Además de varios parches pequeños, un notable número de correcciones fueron hechas por las siguientes personas (en orden alfabético):
Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
<ul>
-<li>New unified key list</li>
-<li>Colorized key fingerprint</li>
-<li>Support for keyserver ports</li>
-<li>Deactivate possibility to generate weak keys</li>
-<li>Much more internal work on the API</li>
-<li>Certify user ids</li>
-<li>Keyserver query based on machine-readable output</li>
-<li>Lock navigation drawer on tablets</li>
-<li>Suggestions for emails on creation of keys</li>
-<li>Search in public key lists</li>
-<li>And much more improvements and fixes…</li>
+<li>Nueva lista unificada de claves</li>
+<li>Huella de validación de clave coloreada</li>
+<li>Soporte para puertos de servidores de claves</li>
+<li>Desactiva la posibilidad de generar claves débiles.</li>
+<li>Mucho más trabajo interno en la API</li>
+<li>Certifica las identidades de usuario</li>
+<li>Petición al servidor de claves basada en salida legible-por-máquina</li>
+<li>Cerrar panel lateral de navegación en tabletas</li>
+<li>Sugerencias para correos electrónicos al crear claves</li>
+<li>Buscar en listas de claves públicas</li>
+<li>Añadir muchas más mejoras y reparaciones...</li>
</ul>
<h2>2.3.1</h2>
<ul>
-<li>Hotfix for crash when upgrading from old versions</li>
+<li>Reparación para fallo al actualizar desde versiones antiguas.</li>
</ul>
<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>Elimina la exportación innecesaria de claves públicas al exportar claves secretas (privadas) (gracias a Ash Hughes)</li>
+<li>Repara el establecimiento de fechas de expiración de claves (gracias a Ash Hughes)</li>
+<li>Más reparaciones internas al editar claves (gracias a Ash Hughes)</li>
+<li>Realización de peticiones a los servidores de claves desde la pantalla de importación</li>
+<li>Repara la disposición y el estilo del cuadro de diálogo en Android 2.2-3.0</li>
+<li>Repara fallos en claves con identidades de usuario vacías</li>
+<li>Repara fallos y listas vacías al volver desde la pantalla de firmado</li>
<li>Bouncy Castle (librería criptográfica) actualizada de 1.47 a 1.50 y compilada desde la fuente</li>
-<li>Fix upload of key from signing screen</li>
+<li>Repara la subida de clave desde la pantalla de firmado</li>
</ul>
<h2>2.2</h2>
<ul>
-<li>New design with navigation drawer</li>
-<li>New public key list design</li>
-<li>New public key view</li>
-<li>Bug fixes for importing of keys</li>
-<li>Key cross-certification (thanks to Ash Hughes)</li>
-<li>Handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
-<li>First version with new languages (thanks to the contributors on Transifex)</li>
-<li>Sharing of keys via QR Codes fixed and improved</li>
-<li>Package signature verification for API</li>
+<li>Nuevo diseño con panel lateral de navegación</li>
+<li>Nuevo diseño de lista de claves públicas</li>
+<li>Nueva vista de clave pública</li>
+<li>Reparación de fallos para la importación de claves</li>
+<li>Certificación-cruzada de clave (gracias a Ash Hughes)</li>
+<li>Tratamiento adecuado de contraseñas UTF-8 (gracias a Ash Hughes)</li>
+<li>Primera versión nuevos idiomas (gracias a los contribuidores en Transifex)</li>
+<li>Compartición de claves mediante códigos QR reparada y mejorada</li>
+<li>Verificación de firma de paquetes para la API</li>
</ul>
<h2>2.1.1</h2>
<ul>
@@ -93,65 +94,65 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
</ul>
<h2>2.1</h2>
<ul>
-<li>Lots of bug fixes</li>
-<li>New API for developers</li>
+<li>Muchas reparaciones de fallos</li>
+<li>Nueva API para desarrolladores</li>
<li>corrección del bug PRNG por Google</li>
</ul>
<h2>2.0</h2>
<ul>
-<li>Complete redesign</li>
-<li>Share public keys via qr codes, nfc beam</li>
-<li>Sign keys</li>
-<li>Upload keys to server</li>
-<li>Fixes import issues</li>
-<li>New AIDL API</li>
+<li>Rediseño completo</li>
+<li>Compartido de claves públicas mediante códigos qr, nfc beam</li>
+<li>Firmar claves</li>
+<li>Subir claves al servidor</li>
+<li>Repara problemas de importación</li>
+<li>Nueva API AIDL</li>
</ul>
<h2>1.0.8</h2>
<ul>
-<li>Basic keyserver support</li>
+<li>Soporte básico de servidor de claves</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>
-<li>Bugfixes</li>
-<li>Optimizations</li>
+<li>Más opciones para caché de frase contraseña: 1, 2, 4, 8 horas</li>
+<li>Traducciones: noruego (gracias, Sander Danielsen), chino (gracias, Zhang Fredrick)</li>
+<li>Reparaciones de fallos</li>
+<li>Optimizaciones</li>
</ul>
<h2>1.0.7</h2>
<ul>
-<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>Reparado un problema con la verificación de firma de textos con una nueva línea al principio</li>
+<li>Más opciones para el periodo de vida en caché de la frase contraseña (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
-<li>Account adding crash on Froyo fixed</li>
-<li>Secure file deletion</li>
-<li>Option to delete key file after import</li>
-<li>Stream encryption/decryption (gallery, etc.)</li>
-<li>New options (language, force v3 signatures)</li>
-<li>Interface changes</li>
-<li>Bugfixes</li>
+<li>Reparado el fallo de la adición de cuenta en Froyo</li>
+<li>Borrado seguro de fichero</li>
+<li>Opción para borrar fichero de clave después de importar</li>
+<li>Cifrado/descifrado del stream (galería, etc.)</li>
+<li>Nuevas opciones (idioma, forzar firmas v3)</li>
+<li>Cambios en la interfaz</li>
+<li>Reparaciones de fallos</li>
</ul>
<h2>1.0.5</h2>
<ul>
<li>traducciones a alemán e italiano</li>
-<li>Much smaller package, due to reduced BC sources</li>
-<li>New preferences GUI</li>
-<li>Layout adjustment for localization</li>
-<li>Signature bugfix</li>
+<li>Paquete mucho más pequeño, debido a fuentes de codec de bitrate (BC) reducido</li>
+<li>Nueva interfaz gráfica (GUI) de prefencias</li>
+<li>Ajuste de la disposición para localización</li>
+<li>Reparación de firma</li>
</ul>
<h2>1.0.4</h2>
<ul>
-<li>Fixed another crash caused by some SDK bug with query builder</li>
+<li>Reparado otro fallo causado por algún fallo del kit de desarrollo de software (SDK) con el constructor de peticiones</li>
</ul>
<h2>1.0.3</h2>
<ul>
-<li>Fixed crashes during encryption/signing and possibly key export</li>
+<li>Reparados fallos durante el cifrado/firmado y posiblemente el exportado de clave</li>
</ul>
<h2>1.0.2</h2>
<ul>
-<li>Filterable key lists</li>
-<li>Smarter pre-selection of encryption keys</li>
-<li>New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
-<li>Fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+<li>Listas de claves filtrables</li>
+<li>Pre-selección de claves de cifrado más inteligente</li>
+<li>Nuevo objeto Intent que maneja VIEW y SEND (ver y enviar), permite que los ficheros sean cifrados/descifrados fuera de los administradores de ficheros.</li>
+<li>Reparaciones y características adicionales (preselección de clave) para K-9 Mail, nueva versión beta disponible</li>
</ul>
<h2>1.0.1</h2>
<ul>
@@ -160,11 +161,11 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<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>Support of more file managers (including ASTRO)</li>
+<li>Soporte de más administradores de ficheros (incluyendo ASTRO)</li>
<li>traducción al esloveno</li>
-<li>New database, much faster, less memory usage</li>
-<li>Defined Intents and content provider for other apps</li>
-<li>Bugfixes</li>
+<li>Nueva base de datos, mucho más rápida, menos uso de memoria</li>
+<li>Definidos objetos Intent y proveedores de contenido para otras aplicaciones</li>
+<li>Reparaciones de fallos</li>
</ul>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-et/help_changelog.html b/OpenKeychain/src/main/res/raw-et/help_changelog.html
index e27ac7475..41ec2cad6 100644
--- a/OpenKeychain/src/main/res/raw-et/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-et/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-fr/help_changelog.html b/OpenKeychain/src/main/res/raw-fr/help_changelog.html
index 43618398d..9d58256a7 100644
--- a/OpenKeychain/src/main/res/raw-fr/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-fr/help_changelog.html
@@ -12,6 +12,7 @@
<li>Nouvelles icônes d'état des clefs (par Brennan Novak)</li>
<li>Correctif important de bogue : l'importation de grandes collections de clefs à partir d'un fichier est maintenant possible</li>
<li>Notification montrant les phrases de passe en cache</li>
+<li>Les clefs sont connectées aux contacts d'Android</li>
</ul>
<p>Cette version ne serait pas possible sans le travail de Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Correctif - déchiffrement de messages/fichiers pgp symétriques</li>
-<li>Nouvel mouture de l'écran de modification des clefs (merci à Ash Hughes)</li>
+<li>Écran de modification des clefs remanié (merci à Ash Hughes)</li>
<li>Nouvelle conception moderne pour les écrans de chiffrement/déchiffrement</li>
<li>API OpenPGP version 3 (comptes multiples d'api, correctifs internes, recherche de clefs)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Prise en charge de base du serveur de clefs</li>
<li>App2sd</li>
-<li>Plus de choix pour le cache des phrases de passe : 1, 2, 4, 8 heures</li>
+<li>Plus de choix pour le cache de la phrase de passe : 1, 2, 4, 8 heures</li>
<li>Traductions : norvégien (merci Sander Danielsen), chinois (merci Zhang Fredrick)</li>
<li>Correctifs de bogues</li>
<li>Optimisations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Problème corrigé avec la vérification de la signature des textes se terminant par un retour à la ligne</li>
-<li>Plus de choix pour la durée de vie de la phrase de passe : (20, 40, 60 min)</li>
+<li>Plus de choix pour la durée de vie de la phrase de passe (20, 40, 60 min)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-it/help_about.html b/OpenKeychain/src/main/res/raw-it/help_about.html
index e26c8e246..7b586cbd3 100644
--- a/OpenKeychain/src/main/res/raw-it/help_about.html
+++ b/OpenKeychain/src/main/res/raw-it/help_about.html
@@ -5,9 +5,9 @@
<p><a href="http://www.openkeychain.org">OpenKeychain</a> un implementazione OpenPGP per Android.</p>
<p>Licenza: GPLv3+</p>
-<h2>Developers</h2>
+<h2>Sviluppatori</h2>
<ul>
-<li>Dominik Schürmann (Maintainer)</li>
+<li>Dominik Schürmann (Manutentore)</li>
<li>Art O Cathain</li>
<li>Ash Hughes</li>
<li>Brian C. Barnes</li>
@@ -34,13 +34,13 @@
<li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licenza Apache v2)</li>
<li>
-<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
+<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Licenza Apache v2)</li>
<li>
-<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
+<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Licenza Apache v2)</li>
<li>
-<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
+<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Licenza Apache v2)</li>
<li>
-<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
+<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Licenza Apache v2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licenza Apache v2)</li>
<li>
diff --git a/OpenKeychain/src/main/res/raw-it/help_changelog.html b/OpenKeychain/src/main/res/raw-it/help_changelog.html
index 6b39c43c0..c4cae4d47 100644
--- a/OpenKeychain/src/main/res/raw-it/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-it/help_changelog.html
@@ -3,17 +3,18 @@
<body>
<h2>2.8</h2>
<ul>
-<li>So many bugs have been fixed in this release that we focus on the main new features</li>
-<li>Key edit: awesome new design, key revocation</li>
-<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
-<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
-<li>File encryption: awesome new design, support for encrypting multiple files</li>
-<li>New icons to show status of key (by Brennan Novak)</li>
-<li>Important bug fix: Importing of large key collections from a file is now possible</li>
-<li>Notification showing cached passphrases</li>
-</ul>
-<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
+<li>Così tanti bug sono stati corretti in questa versione che ci concentriamo sulle principali novità</li>
+<li>Modifica chiave: nuovo eccezionale design, revoca chiave</li>
+<li>Importa chiave: nuovo eccezionale design, connessioni sicure via keyserver HKPS, risoluzione keyserver tramite record SRV DNS</li>
+<li>Nuova schermata di introduzione</li>
+<li>Nuova schermata di creazione chiave: autocompletamento di nomi e email basato sui tuoi account personali di Android</li>
+<li>Codifica File: nuovo eccezionale design, supporto per codifica di più documenti</li>
+<li>Nuove icone per mostrare lo stato delle chiavi (di Brennan Novak)</li>
+<li>Correzione bug importante: Importazione di grandi collezioni di chiavi da un file ora è possibile</li>
+<li>Notifiche mostrando la frase di accesso nella cache</li>
+<li>Le chiavi sono connesse ai contatti di Android</li>
+</ul>
+<p>Questo rilascio non sarebbe stato possibile senza il lavoro di Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
<h2>2.7</h2>
<ul>
@@ -25,21 +26,21 @@
</ul>
<h2>2.6.1</h2>
<ul>
-<li>Some fixes for regression bugs</li>
+<li>alcune correzioni per i bug di regressione</li>
</ul>
<h2>2.6</h2>
<ul>
-<li>Key certifications (thanks to Vincent Breitmoser)</li>
-<li>Support for GnuPG partial secret keys (thanks to Vincent Breitmoser)</li>
-<li>New design for signature verification</li>
-<li>Custom key length (thanks to Greg Witczak)</li>
-<li>Fix share-functionality from other apps</li>
+<li>Certificazioni chiave (grazie a Vincent Breitmoser)</li>
+<li>supporto per chiavi segrete parziali GnuPG (grazie a Vincent Breitmoser)</li>
+<li>nuovo design per la verifica della firma</li>
+<li>lunghezza chiave personalizzata (grazie a Greg Witczak)</li>
+<li>fix funzionalità di condivisione da altre app</li>
</ul>
<h2>2.5</h2>
<ul>
-<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
-<li>New modern design for encrypt/decrypt screens</li>
+<li>Corretta la decodifica di messaggi PGP / file simmetrici</li>
+<li>Refactoring della schermata di modifica chiave (grazie a Ash Hughes)</li>
+<li>Nuovo design moderno per le schermate di codifica / decodifica</li>
<li>OpenPGP API versione 3 (api account multipli, correzioni interne, ricerca chiavi)</li>
</ul>
<h2>2.4</h2>
@@ -47,45 +48,45 @@
Oltre a numerose piccole correzioni, un notevole numero di patch sono state fatte dalle seguenti persone (in ordine alfabetico):
Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paolo Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
<ul>
-<li>New unified key list</li>
-<li>Colorized key fingerprint</li>
-<li>Support for keyserver ports</li>
-<li>Deactivate possibility to generate weak keys</li>
-<li>Much more internal work on the API</li>
-<li>Certify user ids</li>
-<li>Keyserver query based on machine-readable output</li>
-<li>Lock navigation drawer on tablets</li>
-<li>Suggestions for emails on creation of keys</li>
-<li>Search in public key lists</li>
-<li>And much more improvements and fixes…</li>
+<li>Nuova lista chiave unificata</li>
+<li>Impronta chiave colorata</li>
+<li>Supporto per le porte keyserver</li>
+<li>disattivata la possibilità di generare chiavi deboli</li>
+<li>Molto più lavoro interno sulle API</li>
+<li>Certificazione ID utente</li>
+<li>Interrogazione keyserver basate su output leggibile a livello macchina</li>
+<li>Blocco del menu di navigazione sui tablet</li>
+<li>Suggerimenti per e-mail sulla creazione di chiavi</li>
+<li>Ricerca nelle liste di chiavi pubbliche</li>
+<li>E molti altri miglioramenti e correzioni ...</li>
</ul>
<h2>2.3.1</h2>
<ul>
-<li>Hotfix for crash when upgrading from old versions</li>
+<li>Correzione del crash quando si aggiorna da versioni precedenti</li>
</ul>
<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>Rimossa esportazione non necessaria delle chiavi pubbliche quando si esportano le chiavi private (grazie a Ash Hughes)</li>
+<li>Corretto impostazione data di scadenza delle chiavi (grazie a Ash Hughes)</li>
+<li>Molte altre correzioni interne quando si modificano le chiavi (grazie a Ash Hughes)</li>
+<li>Interrogazione server delle chiavi direttamente dalla schermata di importazione</li>
+<li>Corretta impaginazione e stile di dialogo su Android 2.2-3.0</li>
+<li>Corretto crash su chiavi con id utente vuoto</li>
+<li>Corretto crash e liste vuote quando si torna dalla schermata di firma</li>
<li>Bouncy Castle (libreria crittografica) aggiornata da 1.47 a 1.50 e compilata da sorgente</li>
-<li>Fix upload of key from signing screen</li>
+<li>Corretto caricamento delle chiavi dalla schermata di firma</li>
</ul>
<h2>2.2</h2>
<ul>
-<li>New design with navigation drawer</li>
-<li>New public key list design</li>
-<li>New public key view</li>
-<li>Bug fixes for importing of keys</li>
-<li>Key cross-certification (thanks to Ash Hughes)</li>
-<li>Handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
-<li>First version with new languages (thanks to the contributors on Transifex)</li>
-<li>Sharing of keys via QR Codes fixed and improved</li>
-<li>Package signature verification for API</li>
+<li>Nuovo design con barra di navigazione</li>
+<li>Nuovo design per la lista chiavi pubbliche</li>
+<li>Nuova visuale chiavi pubbliche</li>
+<li>Correzione bug per importazione chiavi</li>
+<li>Chiave certificazione incrociata (grazie a Ash Hughes)</li>
+<li>Password UTF-8 gestite correttamente (grazie a Ash Hughes)</li>
+<li>Prima versione con nuove lingue (grazie ai contributori su Transifex)</li>
+<li>Condivisione di chiavi via Codici QR corretta e migliorata</li>
+<li>Verifica firma pacchetto per API</li>
</ul>
<h2>2.1.1</h2>
<ul>
@@ -93,65 +94,65 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
</ul>
<h2>2.1</h2>
<ul>
-<li>Lots of bug fixes</li>
-<li>New API for developers</li>
+<li>Molte correzioni di bug</li>
+<li>Nuove API per sviluppatori</li>
<li>PRNG bug fix by Google</li>
</ul>
<h2>2.0</h2>
<ul>
-<li>Complete redesign</li>
-<li>Share public keys via qr codes, nfc beam</li>
-<li>Sign keys</li>
-<li>Upload keys to server</li>
-<li>Fixes import issues</li>
-<li>New AIDL API</li>
+<li>Completo restyle</li>
+<li>Condivisione chiavi pubbliche via codici qr, nfc beam</li>
+<li>Firma chiavi</li>
+<li>Caricamento chiavi sul server</li>
+<li>Corrette caratteristiche di importazione</li>
+<li>Nuova API AIDL</li>
</ul>
<h2>1.0.8</h2>
<ul>
-<li>Basic keyserver support</li>
+<li>Supporto base per server delle chiavi</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>
-<li>Bugfixes</li>
-<li>Optimizations</li>
+<li>Aggiunte opzioni per la cache della frase di accesso: 1, 2, 4, 8 ore</li>
+<li>Traduzioni: Norvegese (grazie, Sander Danielsen), Cinese (grazie, Zhang Fredrick)</li>
+<li>Correzione bug</li>
+<li>Ottimizzazioni</li>
</ul>
<h2>1.0.7</h2>
<ul>
-<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>Corretto problema con la verifica firma di testi con capo finale</li>
+<li>Maggiori opzioni per il tempo di mantenimento della cache della frase di accesso (20, 40, 60 minuti)</li>
</ul>
<h2>1.0.6</h2>
<ul>
-<li>Account adding crash on Froyo fixed</li>
-<li>Secure file deletion</li>
-<li>Option to delete key file after import</li>
-<li>Stream encryption/decryption (gallery, etc.)</li>
-<li>New options (language, force v3 signatures)</li>
-<li>Interface changes</li>
-<li>Bugfixes</li>
+<li>Crash della aggiunta degli account risolto su Froyo</li>
+<li>Cancellazione sicura dei file</li>
+<li>Opzione per cancellare file delle chiavi dopo l'importazione</li>
+<li>Flusso codifica/decodifica (galleria, ecc.)</li>
+<li>Nuove opzioni (lingua, forza firme v3)</li>
+<li>Cambiamenti interfaccia</li>
+<li>Correzione bug</li>
</ul>
<h2>1.0.5</h2>
<ul>
<li>Traduzione Italiana e Tedesca</li>
-<li>Much smaller package, due to reduced BC sources</li>
-<li>New preferences GUI</li>
-<li>Layout adjustment for localization</li>
-<li>Signature bugfix</li>
+<li>Dimensioni pacchetto ridotte, a causa della riduzione dei sorgenti BC</li>
+<li>Nuove preferenze GUI</li>
+<li>Regolazione layout per la localizzazione</li>
+<li>Correzione bug firma</li>
</ul>
<h2>1.0.4</h2>
<ul>
-<li>Fixed another crash caused by some SDK bug with query builder</li>
+<li>Corretto altro crash causato da alcuni bug SDK con query builder</li>
</ul>
<h2>1.0.3</h2>
<ul>
-<li>Fixed crashes during encryption/signing and possibly key export</li>
+<li>Corretto crash durante codifica/firma e possibilita' di esportare chiave</li>
</ul>
<h2>1.0.2</h2>
<ul>
-<li>Filterable key lists</li>
-<li>Smarter pre-selection of encryption keys</li>
-<li>New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
-<li>Fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+<li>Liste chiavi filtrabili</li>
+<li>Preselezione di chiavi di codifica intelligente</li>
+<li>Nuovo gestore intent per VIEW e SEND, permette la codifica/decodifica file all'infuori di file manager</li>
+<li>Caratteristiche corrette e aggiunte (preselezione chiavi) per K-9 Mail. nuova build beta disponibile</li>
</ul>
<h2>1.0.1</h2>
<ul>
@@ -160,11 +161,11 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.0</h2>
<ul>
<li>integrazione K-9 Mail, APG supporto beta build di K-9 Mail</li>
-<li>Support of more file managers (including ASTRO)</li>
+<li>Supporto per altri file manager (incluso ASTRO)</li>
<li>traduzione Slovena</li>
-<li>New database, much faster, less memory usage</li>
-<li>Defined Intents and content provider for other apps</li>
-<li>Bugfixes</li>
+<li>Nuovo database, piu' veloce, utilizzo memoria ridotto</li>
+<li>Definiti Intent e ContentProvider per le altre app</li>
+<li>Correzione bug</li>
</ul>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-ja/help_changelog.html b/OpenKeychain/src/main/res/raw-ja/help_changelog.html
index 21f0fa230..0f467c407 100644
--- a/OpenKeychain/src/main/res/raw-ja/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-ja/help_changelog.html
@@ -12,6 +12,7 @@
<li>鍵のステータス表示の新しいアイコン(Brennan Novak提供)</li>
<li>重要なバグ修正: 巨大な鍵コレクションをファイルからインポートするのが可能になりました</li>
<li>キャッシュしたパスフレーズの通知表示</li>
+<li>鍵のアドレスをAndroidの連絡先と連携するようにした</li>
</ul>
<p> Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfiharの働きなくしてはこのリリースはありませんでした</p>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>鍵サーバの基本サポート</li>
<li>App2SD</li>
-<li>パスフレーズのキャッシュ時間について1,2,4,8時間の選択肢追加</li>
+<li>パスフレーズのキャッシュ時間についての選択肢追加: 1,2,4,8時間</li>
<li>翻訳: ノルウェー語 (ありがとう、Sander Danielsen)、中国語 (ありがとう、Zhang Fredrick) 追加</li>
<li>バグ修正</li>
<li>最適化</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>改行を含まないテキストの署名検証問題の修正</li>
-<li>パスフレーズのキャッシュ時間 (20,40,60分) のオプション追加</li>
+<li>パスフレーズのキャッシュ生存時間 (20,40,60分) のオプション追加</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-nl/help_changelog.html b/OpenKeychain/src/main/res/raw-nl/help_changelog.html
index 3bc039642..9edbb718e 100644
--- a/OpenKeychain/src/main/res/raw-nl/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-nl/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API versie 3 (meerdere api accounts, interne fixes, sleutel lookup)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-pl/help_changelog.html b/OpenKeychain/src/main/res/raw-pl/help_changelog.html
index eded2c8c4..2fb953cd2 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-pl/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API wersja 3 (wiele kont API, wewnętrzne poprawki, wyszukiwanie kluczy)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-pt/help_about.html b/OpenKeychain/src/main/res/raw-pt/help_about.html
new file mode 100644
index 000000000..f536fecbd
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/help_about.html
@@ -0,0 +1,54 @@
+<html>
+<head></head>
+<body>
+<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</h2>
+<ul>
+<li>Dominik Schürmann (Maintainer)</li>
+<li>Art O Cathain</li>
+<li>Ash Hughes</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov</li>
+<li>Daniel Albert</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>'mar-v-in'</li>
+<li>Markus Doits</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>'Senecaso'</li>
+<li>Sreeram Boyapati</li>
+<li>Thialfihar (APG 1.x)</li>
+<li>Tim Bray</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Libraries</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/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</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>
+</ul>
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-pt/help_changelog.html b/OpenKeychain/src/main/res/raw-pt/help_changelog.html
new file mode 100644
index 000000000..41ec2cad6
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/help_changelog.html
@@ -0,0 +1,171 @@
+<html>
+<head></head>
+<body>
+<h2>2.8</h2>
+<ul>
+<li>So many bugs have been fixed in this release that we focus on the main new features</li>
+<li>Key edit: awesome new design, key revocation</li>
+<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
+<li>New first time screen</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>File encryption: awesome new design, support for encrypting multiple files</li>
+<li>New icons to show status of key (by Brennan Novak)</li>
+<li>Important bug fix: Importing of large key collections from a file is now possible</li>
+<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
+</ul>
+<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
+
+<h2>2.7</h2>
+<ul>
+<li>Purple! (Dominik, Vincent)</li>
+<li>New key view design (Dominik, Vincent)</li>
+<li>New flat Android buttons (Dominik, Vincent)</li>
+<li>API fixes (Dominik)</li>
+<li>Keybase.io import (Tim Bray)</li>
+</ul>
+<h2>2.6.1</h2>
+<ul>
+<li>Some fixes for regression bugs</li>
+</ul>
+<h2>2.6</h2>
+<ul>
+<li>Key certifications (thanks to Vincent Breitmoser)</li>
+<li>Support for GnuPG partial secret keys (thanks to Vincent Breitmoser)</li>
+<li>New design for signature verification</li>
+<li>Custom key length (thanks to Greg Witczak)</li>
+<li>Fix share-functionality from other apps</li>
+</ul>
+<h2>2.5</h2>
+<ul>
+<li>Fix decryption of symmetric pgp messages/files</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
+<li>New modern design for encrypt/decrypt screens</li>
+<li>OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)</li>
+</ul>
+<h2>2.4</h2>
+<p>Thanks to all applicants of Google Summer of Code 2014 who made this release feature rich and bug free!
+Besides several small patches, a notable number of patches are made by the following people (in alphabetical order):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>New unified key list</li>
+<li>Colorized key fingerprint</li>
+<li>Support for keyserver ports</li>
+<li>Deactivate possibility to generate weak keys</li>
+<li>Much more internal work on the API</li>
+<li>Certify user ids</li>
+<li>Keyserver query based on machine-readable output</li>
+<li>Lock navigation drawer on tablets</li>
+<li>Suggestions for emails on creation of keys</li>
+<li>Search in public key lists</li>
+<li>And much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>Hotfix for crash when upgrading from old versions</li>
+</ul>
+<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>Fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>New design with navigation drawer</li>
+<li>New public key list design</li>
+<li>New public key view</li>
+<li>Bug fixes for importing of keys</li>
+<li>Key cross-certification (thanks to Ash Hughes)</li>
+<li>Handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>First version with new languages (thanks to the contributors on Transifex)</li>
+<li>Sharing of keys via QR Codes fixed and improved</li>
+<li>Package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>Lots of bug fixes</li>
+<li>New API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>Complete redesign</li>
+<li>Share public keys via qr codes, nfc beam</li>
+<li>Sign keys</li>
+<li>Upload keys to server</li>
+<li>Fixes import issues</li>
+<li>New AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>Basic keyserver support</li>
+<li>App2sd</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
+<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>Bugfixes</li>
+<li>Optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>Fixed problem with signature verification of texts with trailing newline</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>Account adding crash on Froyo fixed</li>
+<li>Secure file deletion</li>
+<li>Option to delete key file after import</li>
+<li>Stream encryption/decryption (gallery, etc.)</li>
+<li>New options (language, force v3 signatures)</li>
+<li>Interface changes</li>
+<li>Bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>Much smaller package, due to reduced BC sources</li>
+<li>New preferences GUI</li>
+<li>Layout adjustment for localization</li>
+<li>Signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>Fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>Fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>Filterable key lists</li>
+<li>Smarter pre-selection of encryption keys</li>
+<li>New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>Fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>Support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>New database, much faster, less memory usage</li>
+<li>Defined Intents and content provider for other apps</li>
+<li>Bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-pt/help_nfc_beam.html b/OpenKeychain/src/main/res/raw-pt/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<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>
+</ol>
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-pt/help_start.html b/OpenKeychain/src/main/res/raw-pt/help_start.html
new file mode 100644
index 000000000..51a76c01e
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/help_start.html
@@ -0,0 +1,22 @@
+<html>
+<head></head>
+<body>
+<h2>Getting started</h2>
+<p>First you need a personal secret key. Create one via the option menus in "Keys" or import existing secret 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>Applications</h2>
+<p>Several applications support OpenKeychain to encrypt/sign your private communication:<br><img src="apps_k9"><br>K-9 Mail: OpenKeychain support available in current <a href="https://github.com/k9mail/k-9/releases/tag/4.904">alpha build</a>!<br><a href="market://details?id=eu.siacs.conversations"><img src="apps_conversations"><br>Conversations</a>: Jabber/XMPP client<br><a href="market://details?id=org.lf_net.pgpunlocker"><img src="apps_pgpauth"><br>PGPAuth</a>: App to send a PGP-signed request to a server to open or close something, e.g. a door</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>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-pt/help_wot.html b/OpenKeychain/src/main/res/raw-pt/help_wot.html
new file mode 100644
index 000000000..29790139b
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/help_wot.html
@@ -0,0 +1,17 @@
+<html>
+<head></head>
+<body>
+<h2>Web of Trust</h2>
+<p>The Web of Trust describes the part of PGP which deals with creation and bookkeeping of certifications. It provides mechanisms to help the user keep track of who a public key belongs to, and share this information with others; To ensure the privacy of encrypted communication, it is essential to know that the public key you encrypt to belongs to the person you think it does.</p>
+
+<h2>Support in OpenKeychain</h2>
+<p>There is only basic support for Web of Trust in OpenKeychain. This is a heavy work in progress and subject to changes in upcoming releases.</p>
+
+<h2>Trust Model</h2>
+<p>Trust evaluation is based on the simple assumption that all keys which have secret keys available are trusted. Public keys which contain at least one user id certified by a trusted key will be marked with a green dot in the key listings. It is not (yet) possible to specify trust levels for certificates of other known public keys.</p>
+
+<h2>Certifying keys</h2>
+<p>Support for key certification is available, and user ids can be certified individually. It is not yet possible to specify the level of trust or create local and other special types of certificates.</p>
+
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-pt/nfc_beam_share.html b/OpenKeychain/src/main/res/raw-pt/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw-pt/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<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>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenKeychain/src/main/res/raw-ru/help_changelog.html b/OpenKeychain/src/main/res/raw-ru/help_changelog.html
index f74a54762..6f33e8e01 100644
--- a/OpenKeychain/src/main/res/raw-ru/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-ru/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API версии 3 (множественные аккаунты, внутренние исправления, поиск ключей)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-sl/help_changelog.html b/OpenKeychain/src/main/res/raw-sl/help_changelog.html
index e5ff10005..d9da74e00 100644
--- a/OpenKeychain/src/main/res/raw-sl/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-sl/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>API OpenPGP, verzija 3 (podpora za več API računov, interni popravki, iskanje ključev)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-tr/help_changelog.html b/OpenKeychain/src/main/res/raw-tr/help_changelog.html
index e27ac7475..41ec2cad6 100644
--- a/OpenKeychain/src/main/res/raw-tr/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-tr/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw-uk/help_about.html b/OpenKeychain/src/main/res/raw-uk/help_about.html
index 92fd7db13..106e7cabc 100644
--- a/OpenKeychain/src/main/res/raw-uk/help_about.html
+++ b/OpenKeychain/src/main/res/raw-uk/help_about.html
@@ -5,14 +5,14 @@
<p><a href="http://www.openkeychain.org">OpenKeychain</a> імплементація OpenPGP для Андроїду.</p>
<p>Ліцензія: GPLv3+</p>
-<h2>Developers</h2>
+<h2>Розробники</h2>
<ul>
-<li>Dominik Schürmann (Maintainer)</li>
-<li>Art O Cathain</li>
-<li>Ash Hughes</li>
+<li>Домінік Шурман (супроводжувач)</li>
+<li>Арт О'Катен</li>
+<li>Еш Гуджес</li>
<li>Браян С. Барнс</li>
-<li>Bahtiar 'kalkin' Gadimov</li>
-<li>Daniel Albert</li>
+<li>Бахтіяр 'kalkin' Ґадімов</li>
+<li>Даніель Альберт</li>
<li>Даніель Гаман</li>
<li>Даніель Габ</li>
<li>Ґреґ Вітчак</li>
@@ -34,13 +34,13 @@
<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/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
+<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (ліцензія Apache в2)</li>
<li>
-<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
+<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (ліцензія Apache в2)</li>
<li>
-<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
+<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (ліцензія Apache в2)</li>
<li>
-<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
+<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (ліцензія Apache в2)</li>
<li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (ліцензія Apache в. 2)</li>
<li>
diff --git a/OpenKeychain/src/main/res/raw-uk/help_changelog.html b/OpenKeychain/src/main/res/raw-uk/help_changelog.html
index 7ecb25c2b..1837a243e 100644
--- a/OpenKeychain/src/main/res/raw-uk/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-uk/help_changelog.html
@@ -3,17 +3,18 @@
<body>
<h2>2.8</h2>
<ul>
-<li>So many bugs have been fixed in this release that we focus on the main new features</li>
-<li>Key edit: awesome new design, key revocation</li>
-<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
-<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
-<li>File encryption: awesome new design, support for encrypting multiple files</li>
-<li>New icons to show status of key (by Brennan Novak)</li>
-<li>Important bug fix: Importing of large key collections from a file is now possible</li>
-<li>Notification showing cached passphrases</li>
-</ul>
-<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
+<li>У цій версії виправлено надто багато вад, тому ви зосередилися на основних нових функціях</li>
+<li>Редагування ключа: новий вражаючий дизайн, відкликання ключа</li>
+<li>Імпорт ключа: новий вражаючий дизайн, безпечні з'єднання із сервером ключів через hkps, вирішення сервера ключів через записи DNS SRV</li>
+<li>Новий екран першого запуску</li>
+<li>Новий екран створення ключа: автозавершення імені та ел. пошти на основі вашого особистого профілю на Андроїді</li>
+<li>Шифрування файлу: новий вражаючий дизайн, підтримка шифрування кількох файлів</li>
+<li>Нові піктограми для показу стану ключа (від Бренана Новака)</li>
+<li>Виправлення важливої вади: зараз став можливим імпорт великих збірок ключів із файлу</li>
+<li>Сповіщення для показу кешованих парольних фраз</li>
+<li>Keys are connected to Android's contacts</li>
+</ul>
+<p>Ця версія була б неможливою без роботи Вінсента Брейтмозера (GSoC 2014), mar-v-in (GSoC 2014), Даніеля Альберта, Арт О'Катен, Даніеля Хасс, Тіма Брея, Thialfihar</p>
<h2>2.7</h2>
<ul>
@@ -25,21 +26,21 @@
</ul>
<h2>2.6.1</h2>
<ul>
-<li>Some fixes for regression bugs</li>
+<li>Деякі виправлення для накопичених вад</li>
</ul>
<h2>2.6</h2>
<ul>
-<li>Key certifications (thanks to Vincent Breitmoser)</li>
-<li>Support for GnuPG partial secret keys (thanks to Vincent Breitmoser)</li>
-<li>New design for signature verification</li>
-<li>Custom key length (thanks to Greg Witczak)</li>
-<li>Fix share-functionality from other apps</li>
+<li>Сертифікації ключів (завдяки Вінсенту Бреймозеру)</li>
+<li>Підтримка часткових секретних ключів для GnuPG (завдяки Вінсенту Брейтмозеру)</li>
+<li>Новий дизайн для перевірки підпису</li>
+<li>Власна довжина ключа (завдяки Ґреґу Вітчаку)</li>
+<li>Виправлено функцію поширення з інших програм</li>
</ul>
<h2>2.5</h2>
<ul>
-<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
-<li>New modern design for encrypt/decrypt screens</li>
+<li>Виправлено опис симетричних повідомлень/файлів pgp</li>
+<li>Перероблено екран редагування ключа (завдяки Ash Hughes)</li>
+<li>Новий сучасний дизайн для екранів шифрування/розшифрування</li>
<li>OpenPGP API версія 3 (підтримка кількох профілів, внутрішні зміни, пошук ключа)</li>
</ul>
<h2>2.4</h2>
@@ -47,45 +48,45 @@
Крім окремих незначних латок, значне число латок зробили наступні люди (у алфавітному порядку):
Даніель Гаман, Даніель Габ, Ґреґ Вітчак, Міроджін Бакші, Ніхіл Петер Радж, Пауль Сарбіновський, Срірам Бояпаті, Вінсент Брейтмосер.</p>
<ul>
-<li>New unified key list</li>
-<li>Colorized key fingerprint</li>
-<li>Support for keyserver ports</li>
-<li>Deactivate possibility to generate weak keys</li>
-<li>Much more internal work on the API</li>
-<li>Certify user ids</li>
-<li>Keyserver query based on machine-readable output</li>
-<li>Lock navigation drawer on tablets</li>
-<li>Suggestions for emails on creation of keys</li>
-<li>Search in public key lists</li>
-<li>And much more improvements and fixes…</li>
+<li>Новий єдиний перелік ключів</li>
+<li>Кольоровий відбиток ключа</li>
+<li>Підтримка для портів сервера ключів</li>
+<li>Деактивувати можливість генерувати слабкі ключі</li>
+<li>Набагато більше внутрішньої роботи на API</li>
+<li>Сертифікувано ідентифікатори користувача</li>
+<li>Запит сервера ключів на основі машиночитабельного виводу</li>
+<li>Блокування панелі навігації на планшетах</li>
+<li>Пропозиції для листів при створенні ключів</li>
+<li>Пошук у списках відкритих ключів</li>
+<li>І багато інших покращень та виправлень…</li>
</ul>
<h2>2.3.1</h2>
<ul>
-<li>Hotfix for crash when upgrading from old versions</li>
+<li>Свіже виправлення збою при оновленні із старих версій</li>
</ul>
<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>Видалений непотрібний експорт публічного ключа при експорті секретного ключа (завдяки 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>Fix upload of key from signing screen</li>
+<li>Виправлено завантаження ключа з вікна реєстрації</li>
</ul>
<h2>2.2</h2>
<ul>
-<li>New design with navigation drawer</li>
-<li>New public key list design</li>
-<li>New public key view</li>
-<li>Bug fixes for importing of keys</li>
-<li>Key cross-certification (thanks to Ash Hughes)</li>
-<li>Handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
-<li>First version with new languages (thanks to the contributors on Transifex)</li>
-<li>Sharing of keys via QR Codes fixed and improved</li>
-<li>Package signature verification for API</li>
+<li>Новий дизайн з бічною панеллю</li>
+<li>Новий дизайн списку ключів</li>
+<li>Новий вид перегляду ключа</li>
+<li>Виправлення помилок імпорту ключів</li>
+<li>Крос-сертифікація ключів (завдяки Ash Hughes)</li>
+<li>Правильна обробка паролів в UTF-8 (завдяки Ash Hughes)</li>
+<li>Перша версія з новими мовами (завдяки перекладачам на Transifex)</li>
+<li>Виправлення і поліпшення передачі ключів через QR коди</li>
+<li>Перевірка підписів пакетів для API</li>
</ul>
<h2>2.1.1</h2>
<ul>
@@ -93,65 +94,65 @@
</ul>
<h2>2.1</h2>
<ul>
-<li>Lots of bug fixes</li>
-<li>New API for developers</li>
+<li>Безліч виправлень помилок</li>
+<li>Новий API для розробників</li>
<li>Виправлення вади генератора випадкових чисел від Google</li>
</ul>
<h2>2.0</h2>
<ul>
-<li>Complete redesign</li>
-<li>Share public keys via qr codes, nfc beam</li>
-<li>Sign keys</li>
-<li>Upload keys to server</li>
-<li>Fixes import issues</li>
-<li>New AIDL API</li>
+<li>Переробка дизайну</li>
+<li>Передача ключів через QR-коди і NFC</li>
+<li>Підписати ключ</li>
+<li>Завантаження на сервер ключів</li>
+<li>Виправлення проблем імпорту</li>
+<li>Новий AIDL API</li>
</ul>
<h2>1.0.8</h2>
<ul>
-<li>Basic keyserver support</li>
+<li>Підтримка сервера основних ключів</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>
-<li>Bugfixes</li>
-<li>Optimizations</li>
+<li>Більше варіантів збереження кешу пароля: 1, 2, 4, 8 годин</li>
+<li>Переклади: норвезькою (завдяки Сандер Даніельсен), китайською (завдяки Чжан Фредріку)</li>
+<li>Виправлення вад</li>
+<li>Оптимізації</li>
</ul>
<h2>1.0.7</h2>
<ul>
-<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>Виправлення помилки при перевірці підпису тексту з переведенням рядка</li>
+<li>Більше варіантів збереження кешу пароля (20, 40, 60 хвилин)</li>
</ul>
<h2>1.0.6</h2>
<ul>
-<li>Account adding crash on Froyo fixed</li>
-<li>Secure file deletion</li>
-<li>Option to delete key file after import</li>
-<li>Stream encryption/decryption (gallery, etc.)</li>
-<li>New options (language, force v3 signatures)</li>
-<li>Interface changes</li>
-<li>Bugfixes</li>
+<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>Much smaller package, due to reduced BC sources</li>
-<li>New preferences GUI</li>
-<li>Layout adjustment for localization</li>
-<li>Signature bugfix</li>
+<li>Істотно менший пакунок програми завдяки зменшенню джерел</li>
+<li>Нові налаштунки інтерфейсу</li>
+<li>Зміна розмітки для локалізації</li>
+<li>Виправлення помилки підпису</li>
</ul>
<h2>1.0.4</h2>
<ul>
-<li>Fixed another crash caused by some SDK bug with query builder</li>
+<li>Виправлення ще однієї помилки, що виникає в SDK</li>
</ul>
<h2>1.0.3</h2>
<ul>
-<li>Fixed crashes during encryption/signing and possibly key export</li>
+<li>Виправлення помилок при шифруванні/підписанні та експорті ключів</li>
</ul>
<h2>1.0.2</h2>
<ul>
-<li>Filterable key lists</li>
-<li>Smarter pre-selection of encryption keys</li>
-<li>New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
-<li>Fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+<li>Фільтр списку ключів</li>
+<li>Поліпшення вибору ключів шифрування</li>
+<li>Додана можливість шифрувати файли прямо з файлового менеджера</li>
+<li>Виправлення помилок і нові можливості (попередній вибір ключа) для інтеграції з K-9 Mail, нова бета-збірка доступна</li>
</ul>
<h2>1.0.1</h2>
<ul>
@@ -160,11 +161,11 @@
<h2>1.0.0</h2>
<ul>
<li>інтеграція з K-9 Mail, APG підтримує бета-збірку K-9 Mail</li>
-<li>Support of more file managers (including ASTRO)</li>
+<li>Підтримка сторонніх файлових менеджерів (в т.ч. ASTRO)</li>
<li>Словенський переклад</li>
-<li>New database, much faster, less memory usage</li>
-<li>Defined Intents and content provider for other apps</li>
-<li>Bugfixes</li>
+<li>Нова база даних, швидша робота, менше використання пам'яті</li>
+<li>Додано обробники для взаємодії з іншими програмами</li>
+<li>Виправлення вад</li>
</ul>
</body>
</html>
diff --git a/OpenKeychain/src/main/res/raw-zh/help_changelog.html b/OpenKeychain/src/main/res/raw-zh/help_changelog.html
index e27ac7475..41ec2cad6 100644
--- a/OpenKeychain/src/main/res/raw-zh/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw-zh/help_changelog.html
@@ -7,11 +7,12 @@
<li>Key edit: awesome new design, key revocation</li>
<li>Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records</li>
<li>New first time screen</li>
-<li>New create key screen: autocompletion of name and email based on your personal Android accounts</li>
+<li>New key creation screen: autocompletion of name and email based on your personal Android accounts</li>
<li>File encryption: awesome new design, support for encrypting multiple files</li>
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
@@ -38,7 +39,7 @@
<h2>2.5</h2>
<ul>
<li>Fix decryption of symmetric pgp messages/files</li>
-<li>Refactored edit key screen (thanks to Ash Hughes)</li>
+<li>Refactored key edit screen (thanks to Ash Hughes)</li>
<li>New modern design for encrypt/decrypt screens</li>
<li>OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)</li>
</ul>
@@ -110,7 +111,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<ul>
<li>Basic keyserver support</li>
<li>App2sd</li>
-<li>More choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>More choices for passphrase cache: 1, 2, 4, 8, hours</li>
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
<li>Bugfixes</li>
<li>Optimizations</li>
@@ -118,7 +119,7 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
<h2>1.0.7</h2>
<ul>
<li>Fixed problem with signature verification of texts with trailing newline</li>
-<li>More options for pass phrase cache time to live (20, 40, 60 mins)</li>
+<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
</ul>
<h2>1.0.6</h2>
<ul>
diff --git a/OpenKeychain/src/main/res/raw/help_changelog.html b/OpenKeychain/src/main/res/raw/help_changelog.html
index 5f1798896..c8992ddab 100644
--- a/OpenKeychain/src/main/res/raw/help_changelog.html
+++ b/OpenKeychain/src/main/res/raw/help_changelog.html
@@ -16,6 +16,7 @@ And don't add newlines before or after p tags because of transifex -->
<li>New icons to show status of key (by Brennan Novak)</li>
<li>Important bug fix: Importing of large key collections from a file is now possible</li>
<li>Notification showing cached passphrases</li>
+<li>Keys are connected to Android's contacts</li>
</ul>
<p>This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar</p>
diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index 19e94b4b8..5f62b9036 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -1,14 +1,21 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--title-->
+ <string name="title_select_recipients">Vybrat klíče</string>
+ <string name="title_select_secret_key">Vybrat svůj klíč</string>
<string name="title_encrypt">Zašifrovat</string>
<string name="title_decrypt">Rozšifrovat</string>
<string name="title_authentication">Heslo</string>
+ <string name="title_add_subkey">Přidat podklíč</string>
<string name="title_edit_key">Editovat klíč</string>
<string name="title_preferences">Možnosti</string>
<string name="title_api_registered_apps">Appky</string>
<string name="title_key_server_preference">Nastavení keyservrů</string>
<string name="title_change_passphrase">Změnit heslo</string>
+ <string name="title_share_fingerprint_with">Sdílet otisk s...</string>
+ <string name="title_share_key">Sdílet klíč s...</string>
+ <string name="title_share_file">Sdílet soubor s...</string>
+ <string name="title_share_message">Sdílet zprávu s...</string>
<string name="title_encrypt_to_file">Zašifrovat do souboru</string>
<string name="title_decrypt_to_file">Rozšifrovat do souboru</string>
<string name="title_import_keys">Importovat klíče</string>
@@ -19,6 +26,8 @@
<string name="title_certify_key">Certifikovat identity</string>
<string name="title_key_details">Detaily klíče</string>
<string name="title_help">Nápověda</string>
+ <string name="title_log_display">Log</string>
+ <string name="title_create_key">Vytvořit klíč</string>
<!--section-->
<string name="section_user_ids">Identity</string>
<string name="section_keys">Podklíče</string>
@@ -26,43 +35,68 @@
<string name="section_defaults">Výchozí hodnoty</string>
<string name="section_advanced">Pokročilé</string>
<string name="section_actions">Akce</string>
+ <string name="section_share_key">Celý klíč</string>
<string name="section_certification_key">Klíč použitý pro certifikaci</string>
<string name="section_upload_key">Uploadovat klíč</string>
<string name="section_key_server">Keyserver</string>
+ <string name="section_fingerprint">Otisk</string>
+ <string name="section_key_to_certify">Klíče k ověření</string>
<!--button-->
+ <string name="btn_decrypt_verify_file">Dešifrovat, ověřit a uložit soubor</string>
+ <string name="btn_decrypt_verify_message">Dešifrovat a ověřit zpávu</string>
<string name="btn_encrypt_file">Zaširovat a uložit soubor</string>
+ <string name="btn_encrypt_share_file">Zašifrovat a sdílet soubor</string>
<string name="btn_save">Uložit</string>
<string name="btn_do_not_save">Zrušit</string>
<string name="btn_delete">Smazat</string>
+ <string name="btn_no_date">Žádná expirace</string>
<string name="btn_okay">OK</string>
<string name="btn_export_to_server">Nahrát na keyserver</string>
<string name="btn_next">Další</string>
<string name="btn_back">Zpět</string>
<string name="btn_lookup_key">Vyhledat klíč</string>
+ <string name="btn_share_encrypted_signed">Zašifrovat a sdílet zprávu</string>
+ <string name="btn_view_cert_key">Zobrazit klíč certifikátu</string>
+ <string name="btn_create_key">Vytvořit klíč</string>
+ <string name="btn_add_files">Přidat soubor(y)</string>
<!--menu-->
<string name="menu_preferences">Nastavení</string>
<string name="menu_help">Nápověda</string>
<string name="menu_export_key">Exportovat do souboru</string>
<string name="menu_delete_key">Smazat klíč</string>
+ <string name="menu_create_key">Vytvořit moje klíče</string>
+ <string name="menu_import_existing_key">Importovat existující klíč</string>
<string name="menu_search">Hledat</string>
<string name="menu_beam_preferences">Beam settings</string>
<string name="menu_key_edit_cancel">Zrušit</string>
<string name="menu_encrypt_to">Zašifrovat do...</string>
<string name="menu_select_all">Vybrat vše</string>
<string name="menu_add_keys">Přidat klíče</string>
+ <string name="menu_export_all_keys">Exportovat všechny klíče</string>
+ <string name="menu_advanced">Zobrazit pokročilé info</string>
<!--label-->
<string name="label_message">Zpráva</string>
<string name="label_file">Soubor</string>
+ <string name="label_files">Soubor(y)</string>
+ <string name="label_file_colon">Soubor:</string>
<string name="label_no_passphrase">Bez hesla</string>
<string name="label_passphrase">Heslo</string>
+ <string name="label_passphrase_again">Opakovat heslo</string>
<string name="label_algorithm">Algoritmus</string>
+ <string name="label_ascii_armor">Soubor ASCII armor</string>
+ <string name="label_file_ascii_armor">Soubory: ASCII armor</string>
+ <string name="label_asymmetric_from">Od:</string>
+ <string name="label_to">Komu:</string>
+ <string name="label_delete_after_encryption">Soubory: smazat po zašifrování</string>
<string name="label_delete_after_decryption">Smazat po rozšifrování</string>
<string name="label_encryption_algorithm">Šifrovací algoritmus</string>
<string name="label_hash_algorithm">Hashovací algoritmus</string>
+ <string name="label_asymmetric">Veřejným klíčem</string>
+ <string name="label_symmetric">Heslem</string>
<string name="label_passphrase_cache_ttl">Cache hesel</string>
<string name="label_message_compression">Komprimovat zprávu</string>
<string name="label_file_compression">Komprimovat soubor</string>
- <string name="label_force_v3_signature">Vynutit staré OpenPGPv3 podpisy</string>
+ <string name="label_keyservers">Keyservery</string>
<string name="label_key_id">ID klíče</string>
<string name="label_creation">Vytvořeno</string>
<string name="label_expiry">Expirace</string>
@@ -80,6 +114,8 @@
<string name="no_key">&lt;žádný klíč&gt;</string>
<string name="can_encrypt">slouží k šifrovní</string>
<string name="can_sign">slouží k podpisu</string>
+ <string name="can_certify">může ověřit</string>
+ <string name="can_certify_not">nemůže ověřit</string>
<string name="expired">po epiraci</string>
<string name="revoked">revokovat</string>
<string name="secret_key">Tajný klíč:</string>
@@ -119,6 +155,8 @@
<string name="file_delete_confirmation">Určitě smazat\n%s?</string>
<string name="file_delete_successful">Úspěšně smazáno.</string>
<string name="no_file_selected">Nejprve vyberte soubor.</string>
+ <string name="encrypt_sign_successful">Úspěšně podepsáno a/nebo zašifrováno.</string>
+ <string name="encrypt_sign_clipboard_successful">Úspěšně podepsání a/nebo zašifrováno do schránky.</string>
<string name="enter_passphrase_twice">Heslo zadejte dvakrát.</string>
<string name="select_encryption_key">Vyberte alespoň jeden šifrovací klíč.</string>
<string name="select_encryption_or_signature_key">Vyberte alespoň jeden šifrovací nebo podpisový klíč.</string>
@@ -128,14 +166,19 @@
<string name="key_deletion_confirmation_multi">Opravdu si přejete smazat všechny vybrané veřejné klíče?\nToto nebude možné vzít zpět!</string>
<string name="secret_key_deletion_confirmation">Opravdu chcete smazat TAJNÝ klíč \'%s\'?\nToto je nevratná operace!</string>
<string name="public_key_deletetion_confirmation">Opravdu chcete smazat veřejný klíč \'%s\'?\nToto nebude možné vrátit zpět!</string>
+ <string name="also_export_secret_keys">Zárověň exportovat tajný klíč</string>
<string name="key_exported">Úspěšně exportován 1 klíč.</string>
<string name="keys_exported">Úspěšně exportován %d klíč.</string>
<string name="no_keys_exported">Žádný kláč pro export.</string>
<string name="key_creation_el_gamal_info">Žádný: pouze podklíče podporují ElGamal.</string>
<string name="key_not_found">Nemohu najít klíč %08X.</string>
<string name="key_send_success">Úspěšně nahráno na keyserver.</string>
+ <string name="key_certify_success">Úspěšně ověřené identity</string>
<string name="list_empty">Seznam je prázný!</string>
+ <string name="nfc_successful">Úspěšně odeslaný klíč pomocí NFC Beam!</string>
<string name="key_copied_to_clipboard">Klíč byl zkopírován do schránky!</string>
+ <string name="fingerprint_copied_to_clipboard">Fingerprint byl zkopírován do schránky!</string>
+ <string name="select_key_to_certify">Prosím vyberte klíč pro ověření!</string>
<string name="key_too_big_for_sharing">Klíč je příliš velký aby byl sdílen pomocí této metody!</string>
<!--errors
no punctuation, all lowercase,
@@ -158,16 +201,42 @@
<string name="error_jelly_bean_needed">Musíte mít Android 4.1 abyste mohli používat Androidí NFC Beam technologii!</string>
<string name="error_nfc_needed">NFC není na vašem zařízení k dispozici!</string>
<string name="error_nothing_import">Žádný klíč nenalezen!</string>
+ <string name="error_query_too_short">Vyhledávací dotaz příliš krátký. Prosím specifikujte více dotaz!</string>
+ <string name="error_searching_keys">Při hledání klíčů došlo k chybě.</string>
+ <string name="error_too_many_responses">Dotaz pro vyhledání klíče vrátil příliš mnoho položek. Prosím specifikujte lépe svůj dotaz!</string>
+ <string name="error_too_short_or_too_many_responses">Žádný nebo příliš mnoho klíčů bylo nalezeno. Prosím o vylepšení vašeho dotazu!</string>
+ <string name="error_import_no_valid_keys">Žádný klíč nebyl nalezen v souboru/schránce!</string>
<string name="error_generic_report_bug">Nastala obecná chyba, prosím vytvořte nový bug report pro OpenKeychain.</string>
<!--results shown after decryption/verification-->
+ <string name="decrypt_result_invalid_signature">Špatný podpis!</string>
+ <string name="decrypt_result_signature_unknown_pub_key">Neznámý veřejný klíč</string>
+ <string name="decrypt_result_signature_uncertified">Validní podpis (neověřen)</string>
+ <string name="decrypt_result_signature_certified">Validní podpis (ověřen)</string>
+ <string name="decrypt_result_decrypted">Úspěšně rozšifrováno</string>
+ <string name="decrypt_result_decrypted_unknown_pub_key">Úspěšně rozšifrováno ale neznámý veřejný klíč</string>
+ <string name="decrypt_result_decrypted_and_signature_uncertified">Úspěšně rozšifrováno a validní podpis (neověřen)</string>
+ <string name="decrypt_result_decrypted_and_signature_certified">Úspěšně rozšifrováno a validní podpis (ověřen)</string>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">Hotovo.</string>
<string name="progress_cancel">Zrušit</string>
<string name="progress_saving">ukládám...</string>
<string name="progress_importing">importuji...</string>
<string name="progress_exporting">exportuji...</string>
+ <string name="progress_uploading">uloaduji...</string>
<string name="progress_building_key">vytvářím klíč...</string>
<string name="progress_building_master_key">vytvářím hlavní klíč...</string>
+ <string name="progress_generating_rsa">generuji nový RSA klíč...</string>
+ <string name="progress_generating_dsa">generuji nový DSA klíč...</string>
+ <string name="progress_generating_elgamal">generuji nový ElGamal klíč...</string>
+ <string name="progress_modify">modifikuji klíčenku...</string>
+ <string name="progress_modify_unlock">odemykám klíčenku...</string>
+ <string name="progress_modify_adduid">přidávám uživatelské IDčka...</string>
+ <string name="progress_modify_revokeuid">revokuji uživatelská IDčka...</string>
+ <string name="progress_modify_primaryuid">měním primární uživatelské ID...</string>
+ <string name="progress_modify_subkeychange">modifikuji podklíče...</string>
+ <string name="progress_modify_subkeyrevoke">revokuji podklíče...</string>
+ <string name="progress_modify_subkeyadd">přidávám podklíče...</string>
+ <string name="progress_modify_passphrase">mněním heslo...</string>
<string name="progress_extracting_signature_key">extrahuji podpisový klíč...</string>
<string name="progress_extracting_key">extrahuji klíč...</string>
<string name="progress_preparing_streams">připravuji streamy...</string>
@@ -178,13 +247,13 @@
<string name="progress_processing_signature">zpracovávám podpis...</string>
<string name="progress_verifying_signature">verifikuji podpis...</string>
<string name="progress_signing">podepisuji...</string>
+ <string name="progress_certifying">ověřuji...</string>
<string name="progress_reading_data">načítám data...</string>
<string name="progress_finding_key">hledám klíč...</string>
<string name="progress_decompressing_data">rozbaluji data...</string>
<string name="progress_verifying_integrity">verifikuji integritu...</string>
<string name="progress_deleting_securely">mažu \'%s\' bezpečně...</string>
<!--action strings-->
- <string name="hint_public_keys">Jméno/Email/ID klíče</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -196,6 +265,7 @@
<string name="key_size_8192">8192</string>
<string name="key_size_custom">Vlastní velikost klíče</string>
<string name="key_size_custom_info">Napište vlastní délku klíče (v bitech):</string>
+ <string name="key_size_custom_info_rsa">Délka RSA klíče musí být větší než 1024 a alespoň 16384. Zároveň musí být dělitelná 8mi.</string>
<string name="key_size_custom_info_dsa">Délka DSA klíče musí být alespoň 512 a nejvýše 1024. Zároveň musí být dělitelná 64.</string>
<!--compression-->
<string name="compression_fast">rychle</string>
@@ -209,10 +279,19 @@
<string name="help_tab_about">O aplikaci</string>
<string name="help_about_version">Verze:</string>
<!--Import-->
+ <string name="import_tab_keyserver">Keyserver</string>
+ <string name="import_tab_direct">Soubor/schránka</string>
+ <string name="import_tab_qr_code">QR kód/NFC</string>
+ <string name="import_tab_keybase">Keybase.io</string>
<string name="import_import">Importovat vybrané klíče</string>
<string name="import_qr_code_wrong">QR kód nerozpoznán! Zkuste to znovu prosím!</string>
<string name="import_qr_code_too_short_fingerprint">Fingerprint je příliš krátký (&lt; 16 znaků)</string>
+ <string name="import_qr_code_button">Skenovat QR kód...</string>
<!--Import result toast-->
+ <string name="view_log">Zobrazit log</string>
+ <string name="import_error_nothing">Nic k importu</string>
+ <string name="import_error">Chyba importu klíčů!</string>
+ <string name="import_with_warnings">, s varováními</string>
<!--Intent labels-->
<string name="intent_decrypt_file">Dešifrovat soubor pomocí OpenKeychain</string>
<string name="intent_import_key">Importovat kíč pomocí OpenKeychain</string>
@@ -230,17 +309,17 @@
<string name="api_settings_save">Uložit</string>
<string name="api_settings_cancel">Zrušit</string>
<string name="api_settings_revoke">Zneplatnit přístup</string>
+ <string name="api_settings_start">Spustit aplikaci</string>
<string name="api_settings_delete_account">Smazat účet</string>
<string name="api_settings_package_name">Jméno balíčku</string>
<string name="api_settings_package_signature">SHA-256 z podpisu balíčku</string>
<string name="api_settings_accounts">Účty</string>
<string name="api_settings_accounts_empty">Žádné účty nejsou specifikovány pro tuto appku.</string>
+ <string name="api_create_account_text">Appka žádá o vytvoření nového účtu. Prosím vyberte nějaký existující klíč nebo vytvořte nový.\nAppky jsou omezeny na použití klíčů, které zde vyberete!</string>
<string name="api_register_text">Zobrazená appka chce zašifrovat/rozšifrovat zprávy a podepsat je vačím jménem.\nPovolit přístup?\n\nVAROVÁNÍ: Pokud nevíte proč se tato obrazovka objevila, zamítněte přístup! Také můžete zneplatnit přístup jindy v obrazovce \'Appky\'.</string>
<string name="api_register_allow">Povolit přístup</string>
<string name="api_register_disallow">Zamítnout přístup</string>
<string name="api_register_error_select_key">Prosím vyberte klíč!</string>
- <string name="api_select_pub_keys_missing_text">Nebyl nalezen žádný veřejný klíč pro tyto identity:</string>
- <string name="api_select_pub_keys_dublicates_text">Existuje více jak jeden veřejný klíč pro tyto identity:</string>
<string name="api_select_pub_keys_text">Zkontrolujte prosím seznam příjemců!</string>
<string name="api_error_wrong_signature">Selhala kontrola podpisu! Instalovali jste tuto appku z jiného zdroje? Pokud jste si jistí, že toto není útok, zneplatněte registraci této appky v OpenKeychain a poté ji znovu zaregistrujte.</string>
<!--Share-->
@@ -251,16 +330,51 @@
<string name="key_list_empty_text2">Můžete začít pomocí</string>
<string name="key_list_empty_text3">nebo</string>
<string name="key_list_empty_button_create">vytvářím váš vlastní klíč</string>
+ <string name="key_list_empty_button_import">Importuji existující klíč.</string>
<!--Key view-->
<string name="key_view_action_edit">Editovat klíč</string>
<string name="key_view_action_encrypt">Šifruji pomocí těchto klíčů.</string>
<string name="key_view_action_certify">Certifikovat identity</string>
+ <string name="key_view_action_update">Aktualizuji z keyserveru</string>
+ <string name="key_view_action_share_with">Sdílet pomocí...</string>
+ <string name="key_view_action_share_nfc">Sdílet přes NFC tak, že podržíte zařízení zády k sobě</string>
+ <string name="key_view_action_upload">Aktualizovat na keyserver</string>
<string name="key_view_tab_main">Hlavní info</string>
+ <string name="key_view_tab_share">Sdílet</string>
+ <string name="key_view_tab_keys">Podklíče</string>
<string name="key_view_tab_certs">Certifikáty</string>
<!--Edit key-->
+ <string name="edit_key_action_change_passphrase">Změnit heslo</string>
+ <string name="edit_key_action_add_identity">Přidat identitu</string>
+ <string name="edit_key_action_add_subkey">Přidat podklíč</string>
+ <string name="edit_key_edit_user_id_title">Vyberte akci!</string>
+ <string-array name="edit_key_edit_user_id">
+ <item>Změnit na hlavní identitu</item>
+ <item>Zneplatnit identitu</item>
+ </string-array>
+ <string-array name="edit_key_edit_user_id_revert_revocation">
+ <item>Zrušit zneplatnění</item>
+ </string-array>
+ <string name="edit_key_edit_user_id_revoked">Tato identity byla zneplatněna. Toto není možné vzít zpět.</string>
+ <string name="edit_key_edit_subkey_title">Vyberte akci!</string>
+ <string-array name="edit_key_edit_subkey">
+ <item>Změnit expiraci</item>
+ <item>Zneplatnit podklíč</item>
+ </string-array>
+ <string name="edit_key_new_subkey">nový</string>
<!--Create key-->
+ <string name="create_key_upload">Aktualizovat klíč na keyserver</string>
+ <string name="create_key_empty">Toto pole je vyžadováno</string>
+ <string name="create_key_passphrases_not_equal">Heslo nesouhlasí</string>
+ <string name="create_key_final_text">Zadali jste následující identitu:</string>
+ <string name="create_key_final_robot_text">Vytvoření identity může chvíli tvrvat. Mezitím si dejte šálek kávy.\n(3 podklíče, RSA, 4096 bit)</string>
+ <string name="create_key_text">Zadejte své celé jméno, emailovou adresu a zvolte heslo.</string>
+ <string name="create_key_hint_full_name">Celé jméno, např. Jan Novák</string>
<!--View key-->
+ <string name="view_key_revoked">Tento klíč byl zneplatněn!</string>
+ <string name="view_key_expired">Tento klíč vyexpiroval!</string>
<!--Navigation Drawer-->
+ <string name="nav_keys">Klíče</string>
<string name="nav_encrypt">Podepisuji a šifruji</string>
<string name="nav_decrypt">Dešifruji a kontroluji</string>
<string name="nav_apps">Appky</string>
@@ -268,6 +382,8 @@
<string name="drawer_close">Zavří navigační panel</string>
<string name="my_keys">Moje Klíče</string>
<!--hints-->
+ <string name="encrypt_content_edit_text_hint">Zpráva zadaná sem bude podepsána za použití klíče vybraného v poli \'Od\' a zašifrovaná pro všecny příjemce vybrané v \'Pro\'.</string>
+ <string name="decrypt_content_edit_text_hint">Vložte zašifrovaný text pro jeho rozšifrování a/nebo ověření...</string>
<!--certs-->
<string name="cert_default">výchozí</string>
<string name="cert_none">žádný</string>
@@ -284,6 +400,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="label_user_id">Identita</string>
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index a843a154a..6c5e12266 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -6,10 +6,11 @@
<string name="title_encrypt">Verschlüsseln</string>
<string name="title_decrypt">Entschlüsseln</string>
<string name="title_authentication">Passwort</string>
+ <string name="title_add_subkey">Unterschlüssel hinzufügen</string>
<string name="title_edit_key">Schlüssel bearbeiten</string>
<string name="title_preferences">Einstellungen</string>
<string name="title_api_registered_apps">Apps</string>
- <string name="title_key_server_preference">Schlüsselserver Einstellungen</string>
+ <string name="title_key_server_preference">Schlüsselserver</string>
<string name="title_change_passphrase">Passwort ändern</string>
<string name="title_share_fingerprint_with">Teile Fingerabdruck über…</string>
<string name="title_share_key">Teile Schlüssel über...</string>
@@ -26,6 +27,7 @@
<string name="title_key_details">Schlüsseldetails</string>
<string name="title_help">Hilfe</string>
<string name="title_log_display">Log</string>
+ <string name="title_create_key">Schlüssel erzeugen</string>
<!--section-->
<string name="section_user_ids">Identitäten</string>
<string name="section_keys">Unterschlüssel</string>
@@ -47,12 +49,13 @@
<string name="btn_save">Speichern</string>
<string name="btn_do_not_save">Abbrechen</string>
<string name="btn_delete">Löschen</string>
+ <string name="btn_no_date">Kein Ablaufdatum</string>
<string name="btn_okay">Okay</string>
<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_lookup_key">Schlüssel nachschlagen</string>
- <string name="btn_share_encrypted_signed">Entschlüsseln und teilen</string>
+ <string name="btn_share_encrypted_signed">Verschlüsseln und teilen</string>
<string name="btn_view_cert_key">Beglaubigungsschlüssel anzeigen</string>
<string name="btn_create_key">Schlüssel erzeugen</string>
<string name="btn_add_files">Datei(en) hinzufügen</string>
@@ -70,7 +73,7 @@
<string name="menu_select_all">Alles auswählen</string>
<string name="menu_add_keys">Schlüssel hinzufügen</string>
<string name="menu_export_all_keys">Alle Schlüssel exportieren</string>
- <string name="menu_advanced">Erweiterte Info anzeigen</string>
+ <string name="menu_advanced">Erweiterte Infos anzeigen</string>
<!--label-->
<string name="label_message">Nachricht</string>
<string name="label_file">Datei</string>
@@ -80,9 +83,10 @@
<string name="label_passphrase">Passwort</string>
<string name="label_passphrase_again">Passwort wiederholen</string>
<string name="label_algorithm">Algorithmus</string>
+ <string name="label_ascii_armor">Datei: ASCII Armor</string>
<string name="label_file_ascii_armor">Datei: ASCII Armor</string>
<string name="label_write_version_header">Lass andere wissen dass du OpenKeychain nutzt</string>
- <string name="label_write_version_header_summary">Fügt \'OpenKeychain v2.7\' zu OpenPGP Signaturen, Daten und exportierten Schlüsseln hinzu</string>
+ <string name="label_write_version_header_summary">Fügt \'OpenKeychain v2.7\' zu OpenPGP Signaturen, DAten und exportierten Schlüsseln hinzu</string>
<string name="label_asymmetric_from">Von:</string>
<string name="label_to">An:</string>
<string name="label_delete_after_encryption">Dateien: Nach Verschlüsselung löschen</string>
@@ -94,7 +98,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">Erzwinge alte OpenPGPv3-Signaturen</string>
<string name="label_keyservers">Schlüsselserver</string>
<string name="label_key_id">Schlüssel-ID</string>
<string name="label_creation">Erstellungsdatum</string>
@@ -113,8 +116,8 @@
<string name="no_key">&lt;kein Schlüssel&gt;</string>
<string name="can_encrypt">kann verschlüsseln</string>
<string name="can_sign">kann signieren</string>
- <string name="can_certify">kann bestätigen</string>
- <string name="can_certify_not">kann nicht bestätigen</string>
+ <string name="can_certify">kann beglaubigen</string>
+ <string name="can_certify_not">kann nicht beglaubigen</string>
<string name="expired">abgelaufen</string>
<string name="revoked">widerrufen</string>
<plurals name="n_keys">
@@ -167,9 +170,9 @@
<string name="enter_passphrase_twice">Das Passwort bitte zweimal eingeben.</string>
<string name="select_encryption_key">Mindestens einen Schlüssel zum Verschlüsseln auswählen.</string>
<string name="select_encryption_or_signature_key">Mindestens einen Schlüssel zum Verschlüsseln oder einen zum Signieren auswählen.</string>
- <string name="specify_file_to_encrypt_to">Bitte angeben, in welche Datei verschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
- <string name="specify_file_to_decrypt_to">Bitte angeben, in welche Datei entschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
- <string name="specify_file_to_export_to">Bitte angeben, in welche Datei exportiert werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
+ <string name="specify_file_to_encrypt_to">Bitte angeben in welche Datei verschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
+ <string name="specify_file_to_decrypt_to">Bitte angeben,in welche Datei entschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
+ <string name="specify_file_to_export_to">Bitte angeben in welche Datei exportiert werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert. </string>
<string name="key_deletion_confirmation_multi">Möchtest du wirklich alle ausgewählten öffentlichen Schlüssel löschen?\nDies kann nicht rückgängig gemacht werden!</string>
<string name="secret_key_deletion_confirmation">Soll der PRIVATE Schlüssel \'%s\' wirklich gelöscht werden?\nDies kann nicht rückgängig gemacht werden!</string>
<string name="public_key_deletetion_confirmation">Soll der öffentliche Schlüssel \'%s\' wirklich gelöscht werden?\nDies kann nicht rückgängig gemacht werden! </string>
@@ -234,22 +237,24 @@
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">Fertig.</string>
<string name="progress_cancel">Abbrechen</string>
- <string name="progress_saving">wird gespeichert…</string>
- <string name="progress_importing">wird importiert…</string>
- <string name="progress_exporting">wird exportiert…</string>
- <string name="progress_uploading">hochladen...</string>
+ <string name="progress_saving">Wird gespeichert…</string>
+ <string name="progress_importing">Wird importiert…</string>
+ <string name="progress_exporting">Wird exportiert…</string>
+ <string name="progress_uploading">Wird hochgeladen...</string>
<string name="progress_building_key">Schlüssel wird erstellt…</string>
<string name="progress_building_master_key">Hauptschlüssel wird erstellt…</string>
- <string name="progress_generating_rsa">erzeuge neuen RSA Schlüssel...</string>
- <string name="progress_generating_dsa">erzeuge neuen DSA Schlüssel...</string>
- <string name="progress_generating_elgamal">erzeuge neuen ElGamal Schlüssel...</string>
- <string name="progress_modify">verändere Schlüsselbund...</string>
- <string name="progress_modify_unlock">entsperre Schlüsselbund...</string>
- <string name="progress_modify_adduid">füge User ID hinzu...</string>
- <string name="progress_modify_primaryuid">ändere Haupt User ID...</string>
- <string name="progress_modify_subkeychange">verändere Unterschlüssel...</string>
- <string name="progress_modify_subkeyadd">füge Unterschlüssel hinzu...</string>
- <string name="progress_modify_passphrase">ändere Passwort...</string>
+ <string name="progress_generating_rsa">Erzeuge neuen RSA-Schlüssel...</string>
+ <string name="progress_generating_dsa">Erzeuge neuen DSA-Schlüssel...</string>
+ <string name="progress_generating_elgamal">Erzeuge neuen ElGamal-Schlüssel...</string>
+ <string name="progress_modify">Schlüsselbund wird verändert...</string>
+ <string name="progress_modify_unlock">Schlüsselbund wird entsperrt...</string>
+ <string name="progress_modify_adduid">User-ID wird hinzugefügt...</string>
+ <string name="progress_modify_revokeuid">User-IDs werden widerrufen...</string>
+ <string name="progress_modify_primaryuid">Primäre User-ID wird geändert...</string>
+ <string name="progress_modify_subkeychange">Unterschlüssel werden verändert...</string>
+ <string name="progress_modify_subkeyrevoke">Unterschlüssel wird widerrufen...</string>
+ <string name="progress_modify_subkeyadd">Unterschlüssel wird hinzugefügt...</string>
+ <string name="progress_modify_passphrase">Passwort wird geändert...</string>
<plurals name="progress_exporting_key">
<item quantity="one">Schlüssel wird exportiert…</item>
<item quantity="other">Schlüssel werden exportiert…</item>
@@ -263,15 +268,14 @@
<string name="progress_generating_signature">Signatur wird erstellt…</string>
<string name="progress_processing_signature">Signatur wird verarbeitet…</string>
<string name="progress_verifying_signature">Signatur wird verifiziert…</string>
- <string name="progress_signing">wird signiert…</string>
+ <string name="progress_signing">Wird signiert…</string>
+ <string name="progress_certifying">Wird beglaubige...</string>
<string name="progress_reading_data">Daten werden gelesen…</string>
<string name="progress_finding_key">Schlüssel wird gesucht…</string>
<string name="progress_decompressing_data">Daten werden entpackt…</string>
<string name="progress_verifying_integrity">Integrität wird überprüft…</string>
<string name="progress_deleting_securely">\'%s\' wird sicher gelöscht…</string>
<!--action strings-->
- <string name="hint_public_keys">Name/Email/Schlüssel ID...</string>
- <string name="hint_keybase_search">Name/Keybase.io Benutzername...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -283,6 +287,7 @@
<string name="key_size_8192">8192</string>
<string name="key_size_custom">Benutzerdefinierte Schlüssellänge</string>
<string name="key_size_custom_info">Benutzerdefinierte Schlüssellänge (in Bit):</string>
+ <string name="key_size_custom_info_rsa">Die RSA-Schlüssellänge muss grösser als 1024 und höchstens 16384 sein. Sie muss auch ein Mehrfaches von 8 sein.</string>
<string name="key_size_custom_info_dsa">Die DSA-Schlüssellänge muss mindestens 512 und höchstens 1024 sein. Auch muss sie ein Mehrfaches von 64 sein.</string>
<!--compression-->
<string name="compression_fast">schnell</string>
@@ -298,12 +303,12 @@
<!--Import-->
<string name="import_tab_keyserver">Schlüsselserver</string>
<string name="import_tab_direct">Datei/Zwischenablage</string>
- <string name="import_tab_qr_code">QR Kode/NFC</string>
+ <string name="import_tab_qr_code">QR-Code/NFC</string>
<string name="import_tab_keybase">Keybase.io</string>
<string name="import_import">Ausgewählte Schlüssel importieren</string>
<string name="import_qr_code_wrong">Falsch formatierter QR-Code! Bitte erneut versuchen!</string>
<string name="import_qr_code_too_short_fingerprint">Der Fingerabdruck ist zu kurz (&lt; 16 Zeichen)</string>
- <string name="import_qr_code_button">QR Kode Einlesen...</string>
+ <string name="import_qr_code_button">QR-Code Einlesen...</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
<item quantity="one">1 Schlüssel erfolgreich importiert</item>
@@ -344,12 +349,11 @@
<string name="api_settings_package_signature">SHA-256 der Paketsignatur</string>
<string name="api_settings_accounts">Konten</string>
<string name="api_settings_accounts_empty">Keine Konten mit dieser Anwendung verknüpft.</string>
- <string name="api_register_text">Folgende Anwendung möchte Nachrichten ver-/entschlüsseln und in Ihrem Namen signieren\nZugriff erlauben?\n\nVORSICHT: Sollten Sie nicht wissen warum dieses Fenster erscheint, sollten Sie den Zugriff nicht gewähren! Sie können Zugriffe später über das Menü \'Anwendungen\' widerrufen.</string>
+ <string name="api_create_account_text">Die App verlangt die Erstellung eines neuen Accounts. Bitte wähle einen deiner existierenden Schlüssel aus oder erstelle einen neuen.\nApps können nur hier ausgewählte Schlüssel nutzen.</string>
+ <string name="api_register_text">Folgende Anwendung möchte Nachrichten ver-/entschlüsseln und in Ihrem Namen signieren.\nZugriff erlauben?\n\nVORSICHT: Sollten Sie nicht wissen warum dieses Fenster erscheint, sollten Sie den Zugriff verbieten! Sie können Zugriffe später über das Menü \'Apps\' widerrufen.</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>
- <string name="api_select_pub_keys_missing_text">Für diese Identität wurden keine öffentlichen Schlüssel gefunden:</string>
- <string name="api_select_pub_keys_dublicates_text">Für diese Identität existieren mehrere öffentliche Schlüssel:</string>
<string name="api_select_pub_keys_text">Bitte die Liste der Empfänger überprüfen!</string>
<string name="api_error_wrong_signature">Signaturüberprüfung fehlgeschlagen! Haben Sie diese Anwendung aus einer anderen Quelle installiert? Wenn Sie eine Attacke ausschliessen können, sollten Sie die Registrierung der App in OpenKeychain widerrufen und die Anwendung erneut registrieren.</string>
<!--Share-->
@@ -364,21 +368,33 @@
<string name="key_list_empty_text2">Du kannst anfangen OpenKeychain zu benutzen indem du</string>
<string name="key_list_empty_text3">oder</string>
<string name="key_list_empty_button_create">deinen eigenen Schlüssel erstellst</string>
+ <string name="key_list_empty_button_import">Importiere einen existierenden Schlüssel.</string>
<!--Key view-->
<string name="key_view_action_edit">Schlüssel bearbeiten</string>
<string name="key_view_action_encrypt">Mit diesem Schlüssel verschlüsseln</string>
<string name="key_view_action_certify">Identitäten beglaubigen</string>
+ <string name="key_view_action_update">Von Schlüsselserver aktualisieren</string>
<string name="key_view_action_share_with">Teilen über...</string>
<string name="key_view_action_share_nfc">Teilen über NFC (Geräte Rückseite an Rückseite halten)</string>
+ <string name="key_view_action_upload">Auf Schlüsselserver hochladen</string>
<string name="key_view_tab_main">Informationen</string>
<string name="key_view_tab_share">Teilen</string>
<string name="key_view_tab_keys">Unterschlüssel</string>
<string name="key_view_tab_certs">Beglaubigungen</string>
+ <string name="user_id_info_revoked_title">Wiederrufen</string>
+ <string name="user_id_info_invalid_title">Ungültig</string>
<!--Edit key-->
+ <string name="edit_key_action_change_passphrase">Passwort ändern</string>
<string name="edit_key_action_add_identity">Identität hinzufügen</string>
<string name="edit_key_action_add_subkey">Unterschlüssel hinzufügen</string>
+ <string name="edit_key_new_subkey">neu</string>
<!--Create key-->
+ <string name="create_key_upload">Schlüssel auf Schlüsselserver hochladen</string>
+ <string name="create_key_passphrases_not_equal">Passwörter stimmen nicht überein</string>
+ <string name="create_key_hint_full_name">Vollständiger Name, z.B. Max Mustermann</string>
<!--View key-->
+ <string name="view_key_revoked">Dieser Schlüssel wurde widerrufen!</string>
+ <string name="view_key_expired">Dieser Schlüssel ist nicht mehr gültig!</string>
<!--Navigation Drawer-->
<string name="nav_keys">Schlüssel</string>
<string name="nav_encrypt">Signieren und Verschlüsseln</string>
@@ -396,25 +412,38 @@
<string name="cert_casual">einfach überprüft</string>
<string name="cert_positive">positiv</string>
<string name="cert_revoke">widerrufen</string>
+ <string name="cert_verify_ok">OK</string>
<string name="cert_verify_failed">fehlgeschlagen!</string>
<string name="cert_verify_error">Fehler!</string>
<string name="cert_verify_unavailable">Schlüssel nicht verfügbar</string>
<!--Import Public log entries-->
<string name="msg_ip_delete_old_ok">Alte Schlüssel aus der Datenbank löschen</string>
<string name="msg_ip_encode_fail">Die Anwendung ist wegen Kodierungsfehler fehlgeschlagen</string>
- <string name="msg_ip_fail_io_exc">Die Anwendung is wegen Eingabe/Ausgabe-Fehler fehlgeschlagen</string>
+ <string name="msg_ip_fail_io_exc">Die Anwendung ist wegen eines Eingabe/Ausgabe-Fehlers fehlgeschlagen</string>
<string name="msg_ip_fail_remote_ex">Die Anwendung ist wegen internen Fehler fehlgeschlagen</string>
+ <string name="msg_ip">Importiere öffentlichen Schlüsselbund %s</string>
<string name="msg_ip_insert_keyring">Schlüsselbund-daten werden kodiert</string>
<string name="msg_ip_prepare">Datenbank-Transaktionen werden vorbereitet</string>
+ <string name="msg_ip_master">Hauptschlüssel %s wird verarbeitet</string>
<string name="msg_ip_subkey">Unterschlüssel %s wird bearbeitet</string>
+ <string name="msg_ip_uid_revoked">Benutzerkennung wurde widerrufen</string>
<!--Import Secret log entries-->
+ <string name="msg_is_db_exception">Datenbankfehler!</string>
<string name="msg_is_importing_subkeys">Geheime Unterschlüssel werden bearbeitet</string>
+ <string name="msg_is_success_identical">Schlüsselbund enthält keine neuen Daten, es gibt nichts zu tun.</string>
+ <string name="msg_is_success">Geheimer Schlüsselbund erfolgreich importiert</string>
<!--Keyring Canonicalization log entries-->
+ <string name="msg_kc_sub">Verarbeite Unterschlüssel %s</string>
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <string name="msg_mf_uid_primary">Ändere primäre Benutzerkenung auf %s</string>
+ <string name="msg_mf_uid_revoke">Widerrufe Benutzerkennung %s</string>
+ <string name="msg_mf_uid_error_empty">Benutzerkennung darf nicht leer sein!</string>
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
+ <string name="internal_error">Interner Fehler!</string>
<string name="section_certifier_id">Beglaubiger</string>
<string name="section_cert">Zertifikatdetails</string>
<string name="label_user_id">Identität</string>
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 80c2060d1..16d60dc82 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -27,6 +27,7 @@
<string name="title_key_details">Detalles de la clave</string>
<string name="title_help">Ayuda</string>
<string name="title_log_display">Registro (log)</string>
+ <string name="title_create_key">Crear clave</string>
<!--section-->
<string name="section_user_ids">Identidades</string>
<string name="section_keys">Subclaves</string>
@@ -84,8 +85,8 @@
<string name="label_algorithm">Algoritmo</string>
<string name="label_ascii_armor">Armadura ASCII del fichero</string>
<string name="label_file_ascii_armor">Ficheros: Armadura ASCII</string>
- <string name="label_write_version_header">Permitir a otros saber que está usando OpenKeychain</string>
- <string name="label_write_version_header_summary">Escribe \'OpenKeychain v2.7\' en las firmas OpenPGP, el texto cifrado, y las claves exportadas</string>
+ <string name="label_write_version_header">Permitir conocer a otros que usted está usando OpenKeychain</string>
+ <string name="label_write_version_header_summary">Escribe \'OpenKeychain v2.7\' en las firmas OpenPGP, texto cifrado, y claves exportadas</string>
<string name="label_asymmetric_from">Desde:</string>
<string name="label_to">Hacia:</string>
<string name="label_delete_after_encryption">Ficheros: Borrar después del cifrado</string>
@@ -97,7 +98,6 @@
<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_keyservers">Servidores de claves</string>
<string name="label_key_id">ID de clave</string>
<string name="label_creation">Creación</string>
@@ -275,9 +275,12 @@
<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_deleting">borrando claves...</string>
+ <string name="progress_con_saving">consolidación: guardando en caché...</string>
+ <string name="progress_con_reimport">consolidación: reimportando</string>
<!--action strings-->
- <string name="hint_public_keys">Identidad de Nombre/Correo/Clave...</string>
- <string name="hint_keybase_search">Nombre de usuario de Nombre/Keybase.io...</string>
+ <string name="hint_keyserver_search_hint">Nombre/Correo electrónico/Identidad de clave...</string>
+ <string name="hint_keybase_search_hint">Nombre/Correo electrónico/Prueba/Clave...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -356,13 +359,15 @@
<string name="api_settings_accounts">Cuentas</string>
<string name="api_settings_accounts_empty">No hay cuentas adjuntas a esta aplicación</string>
<string name="api_create_account_text">La aplicación solicita la creación de una nueva cuenta. Por favor, seleccione una de sus claves existentes o cree una nueva.\n¡Las aplicaciones están restringidas al uso de las claves que usted seleccione aquí!</string>
+ <string name="api_update_account_text">La clave guardada para esta cuenta ha sido borrada. ¡Por favor seleccione una diferente!\n¡Las aplicaciones están restringidas al uso de las claves que seleccione aquí!</string>
<string name="api_register_text">La aplicación mostrada quiere cifrar, descrifrar y firmar mensajes en su nombre.\n¿Permitir acceso?\n\nADVERTENCIA: Si no sabe por qué apareció esta pantalla, ¡no permita el acceso! Puede revocar el acceso más tarde usando la pantalla de \'Aplicaciones\'.</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 encontraron claves públicas para estas identidades:</string>
- <string name="api_select_pub_keys_dublicates_text">Existe más de una clave pública para estas identidades:</string>
+ <string name="api_select_pub_keys_missing_text">No se encontraron claves para estas identidades:</string>
+ <string name="api_select_pub_keys_dublicates_text">Existe más de una clave para estas identidades:</string>
<string name="api_select_pub_keys_text">¡Por favor, revisa la lista de destinatarios!</string>
+ <string name="api_select_pub_keys_text_no_user_ids">¡Por favor seleccione los receptores!</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 OpenKeychain y regístrala de nuevo.</string>
<!--Share-->
<string name="share_qr_code_dialog_title">Compartir con código QR</string>
@@ -389,6 +394,14 @@
<string name="key_view_tab_share">Compartir</string>
<string name="key_view_tab_keys">Subclaves</string>
<string name="key_view_tab_certs">Certificados</string>
+ <string name="user_id_info_revoked_title">Revocada</string>
+ <string name="user_id_info_revoked_text">Esta identidad ha sido revocada por el propietario de la clave. En adelante no es válida.</string>
+ <string name="user_id_info_verified_title">Verificada</string>
+ <string name="user_id_info_verified_text">Esta identidad ha sido verificada</string>
+ <string name="user_id_info_not_verified_title">No verificada</string>
+ <string name="user_id_info_not_verified_text">Esta identidad no se ha verificado aún. No puede estar seguro de si la identidad realmente corresponde a una persona en concreto.</string>
+ <string name="user_id_info_invalid_title">No válido</string>
+ <string name="user_id_info_invalid_text">¡Algo está mal con esta identidad!</string>
<!--Edit key-->
<string name="edit_key_action_change_passphrase">Cambiar frase contraseña</string>
<string name="edit_key_action_add_identity">Añadir identidad</string>
@@ -408,6 +421,7 @@
<item>Revocar subclave</item>
</string-array>
<string name="edit_key_new_subkey">nueva</string>
+ <string name="edit_key_select_flag">¡Por favor, seleccione al menos un indicador!</string>
<!--Create key-->
<string name="create_key_upload">Subir clave al servidor de claves</string>
<string name="create_key_empty">Este campo es obligatorio</string>
@@ -443,6 +457,7 @@
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">Aplicando operación de inserción por lote.</string>
<string name="msg_ip_bad_type_secret">Se intentó importar un juego de claves (keyring) secreto como público. Esto es un fallo, por favor ¡consigne un informe!</string>
+ <string name="msg_kc_v3_key">Esta clave es una clave OpenPGP versión 3 y por tanto insegura. No ha sido importada.</string>
<string name="msg_ip_delete_old_fail">No se borró ninguna clave antigua (¿crear una nueva?)</string>
<string name="msg_ip_delete_old_ok">Clave antigua borrada de la base de datos</string>
<string name="msg_ip_encode_fail">La operación falló debido a un error de codificación</string>
@@ -548,7 +563,7 @@
<string name="msg_kc_uid_bad_time">Eliminando identidad de usuario con marca de tiempo futura</string>
<string name="msg_kc_uid_bad_type">Eliminando certificado de identidad de usuario, de tipo desconocido (%s)</string>
<string name="msg_kc_uid_bad">Eliminando auto-certificado defectuoso para la identidad de usuario \"%s\"</string>
- <string name="msg_kc_uid_dup">Eliminando auto-certificado desactualizado para el identificador de usuario \"%s\"</string>
+ <string name="msg_kc_uid_cert_dup">Eliminando auto-certificado desactualizado para el identificador de usuario \"%s\"</string>
<string name="msg_kc_uid_foreign">Eliminando certificado ajeno de identidad de usuario por %s</string>
<string name="msg_kc_uid_revoke_dup">Eliminando certificado redundate de revocación para la identidad de usuario \"%s\"</string>
<string name="msg_kc_uid_revoke_old">Eliminando certificado desactualizado de revocación para la identidad de usuario \"%s\"</string>
@@ -557,8 +572,8 @@
<!--Keyring merging log entries-->
<string name="msg_mg_public">Incorporándolas en el juego de claves públicas %s</string>
<string name="msg_mg_secret">Incorporándolas en el juego de claves secretas (privadas) %s</string>
- <string name="msg_mg_fatal_encode">Error fatal codificando la firma</string>
- <string name="msg_mg_heterogeneous">Se intentaron consolidar juegos de claves heterogéneos</string>
+ <string name="msg_mg_error_encode">Error fatal codificando la firma</string>
+ <string name="msg_mg_error_heterogeneous">¡Se intentaron fusionar juegos de claves con diferentes huellas de validación de claves!</string>
<string name="msg_mg_new_subkey">Añadiendo nueva subclave %s</string>
<string name="msg_mg_found_new">Se encontraron %s nuevos certificados en el juego de claves</string>
<string name="msg_mg_unchanged">No hay nuevos certificados</string>
@@ -567,6 +582,7 @@
<string name="msg_cr_error_no_master">¡No se especificaron opciones de clave!</string>
<string name="msg_cr_error_no_user_id">¡Los juegos de claves tienen que estar creados con al menos una identidad de usuario!</string>
<string name="msg_cr_error_no_certify">¡La clave maestra debe tener el indicador de certificado!</string>
+ <string name="msg_cr_error_null_expiry">El periodo hasta la expiración no puede ser \"el mismo que antes\" al crear la clave. Esto es un error de programación, por favor ¡rellene un informe de fallo!</string>
<string name="msg_cr_error_keysize_512">¡El tamaño de la clave debe ser mayor o igual de 512!</string>
<string name="msg_cr_error_internal_pgp">¡Error PGP interno!</string>
<string name="msg_cr_error_unknown_algo">¡Seleccionado algoritmo defectuoso!</string>
@@ -577,18 +593,26 @@
<string name="msg_mf_error_fingerprint">¡La actual huella de validación de clave no coincide con la esperada!</string>
<string name="msg_mf_error_keyid">No hay identidad de clave. Esto es un error interno, por favor ¡consigne un informe de error!</string>
<string name="msg_mf_error_integrity">Error interno, ¡fallo en la comprobación de integridad!</string>
+ <string name="msg_mf_error_master_none">¡No se encontró certificado maestro sobre el que operar! (¿Todos revocados?)</string>
<string name="msg_mf_error_noexist_primary">¡Especificada identidad de usuario primaria defectuosa!</string>
+ <string name="msg_mf_error_noexist_revoke">¡Se especificó una mala identidad de usuario para revocación!</string>
<string name="msg_mf_error_revoked_primary">¡Las identidades de usuario revocadas no pueden ser primarias!</string>
+ <string name="msg_mf_error_null_expiry">El periodo hasta la expiración no puede ser \"el mismo que antes\" al crear subclave. Esto es un error de programación, por favor ¡rellene un informe de fallo!</string>
+ <string name="msg_mf_error_passphrase_master">¡Error fatal descrifrando la clave maestra! Probablemente esto se daba a un error de programación, por favor ¡rellene un informe de fallo!</string>
<string name="msg_mf_error_pgp">¡Excepción interna de PGP!</string>
<string name="msg_mf_error_sig">¡Excepción con la firma!</string>
- <string name="msg_mf_passphrase">Cambiando frase contraseña</string>
+ <string name="msg_mf_master">Modificando certificaciones maestras</string>
+ <string name="msg_mf_passphrase">Cambiando frase contraseña para el juego de claves (keyring)...</string>
+ <string name="msg_mf_passphrase_key">Re-cifrando subclave %s con nueva frase contraseña</string>
+ <string name="msg_mf_passphrase_empty_retry">Fallo al establecer nueva frase contraseña, intentándolo de nuevo con una antigua frase contraseña vacía</string>
+ <string name="msg_mf_passphrase_fail">¡La frase contraseña para la subclave no pudo cambiarse! (¿Tiene la subclave una diferente de la de las otras claves?)</string>
<string name="msg_mf_primary_replace_old">Reemplazando certificado de la anterior identidad de usuario primaria </string>
<string name="msg_mf_primary_new">Generando nuevo certificado para nueva identidad de usuario primaria</string>
<string name="msg_mf_subkey_change">Modificando subclave %s</string>
- <string name="msg_mf_subkey_missing">¡Intentó operar sobre una subclave ausente %s!</string>
- <string name="msg_mf_subkey_new">Generando nueva subclave %2$s de %1$s bits</string>
+ <string name="msg_mf_error_subkey_missing">¡Se intentó operar sobre una subclave desaparecida %s!</string>
+ <string name="msg_mf_subkey_new">Añadiendo nueva subclave de tipo %2$s (%1$s bits)</string>
<string name="msg_mf_subkey_new_id">Nueva identidad de subclave: %s</string>
- <string name="msg_mf_subkey_past_expiry">¡La fecha de expiración no puede ser del pasado!</string>
+ <string name="msg_mf_error_past_expiry">¡La fecha de expiración no puede ser del pasado!</string>
<string name="msg_mf_subkey_revoke">Revocando subclave %s</string>
<string name="msg_mf_success">Juego de claves modificado con éxito</string>
<string name="msg_mf_uid_add">Añadiendo identidad de usuario %s</string>
@@ -596,7 +620,41 @@
<string name="msg_mf_uid_revoke">Revocando identidad de usuario %s</string>
<string name="msg_mf_uid_error_empty">¡La identidad de usuario no debe estar vacía!</string>
<string name="msg_mf_unlock_error">¡Error desbloqueando juego de claves!</string>
- <string name="msg_mf_unlock">Desbloqueando juego de claves</string>
+ <string name="msg_mf_unlock">Desbloqueando juego de claves (keyring)</string>
+ <!--Consolidate-->
+ <string name="msg_con">Consolidando base de datos</string>
+ <string name="msg_con_error_bad_state">¡La consolidación se inició cuando ninguna base de datos estaba cacheada! Probablemente esto es un error de programación, por favor consigne un informe de fallo.</string>
+ <string name="msg_con_error_concurrent">¡Consolidación abortada, ejecutándose ya en otro hilo!</string>
+ <string name="msg_con_save_secret">Guardando juegos de claves secretas (privadas)</string>
+ <string name="msg_con_save_public">Guardando juegos de claves públicas</string>
+ <string name="msg_con_db_clear">Limpiando base de datos</string>
+ <string name="msg_con_success">Base de datos consolidada con éxito</string>
+ <string name="msg_con_critical_in">Entrando en fase crítica</string>
+ <string name="msg_con_critical_out">Abandonando fase crítica</string>
+ <string name="msg_con_delete_public">Borrando fichero de caché de juego de claves públicas</string>
+ <string name="msg_con_delete_secret">Borrando fichero de caché de juego de claves secretas (privadas)</string>
+ <string name="msg_con_error_db">¡Error al abrir la base de datos!</string>
+ <string name="msg_con_error_io_public">¡Error de E/S al escribir claves públicas en caché!</string>
+ <string name="msg_con_error_io_secret">¡Error de E/S al escribir claves secretas (privadas) en caché!</string>
+ <string name="msg_con_error_public">¡Error al reimportar claves públicas!</string>
+ <string name="msg_con_error_secret">¡Error reimportando claves secretas (privadas)!</string>
+ <plurals name="msg_con_recover">
+ <item quantity="one">Recuperando consolidación con %1$d clave secreta (privada) y %2$d pública</item>
+ <item quantity="other">Recuperando consolidación con %1$d claves secretas (privadas) y %2$d públicas</item>
+ </plurals>
+ <string name="msg_con_recover_unknown">Recuperando desde un estado desconocido</string>
+ <plurals name="msg_con_reimport_public">
+ <item quantity="one">Reimportando una clave pública</item>
+ <item quantity="other">Reimportando %d claves públicas</item>
+ </plurals>
+ <string name="msg_con_reimport_public_skip">No hay claves públicas a reimportar, omitiendo...</string>
+ <plurals name="msg_con_reimport_secret">
+ <item quantity="one">Reimportando una clave secreta (privada)</item>
+ <item quantity="other">Reimportando %d claves secretas (privadas)</item>
+ </plurals>
+ <string name="msg_con_reimport_secret_skip">No hay claves públicas a reimportar, omitiendo...</string>
+ <string name="msg_con_warn_delete_public">Excepción borrando fichero de caché de claves públicas</string>
+ <string name="msg_con_warn_delete_secret">Excepción al borrar fichero de caché de claves secretas (privadas)</string>
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Haga clic para limpiar las frases contraseña almacenadas en caché</string>
<string name="passp_cache_notif_n_keys">OpenKeychain ha almacenado en caché %d frases contraseña</string>
@@ -610,6 +668,7 @@
<string name="label_user_id">Identidad</string>
<string name="unknown_uid">&lt;desconocido&gt;</string>
<string name="empty_certs">No hay certificados para esta clave</string>
+ <string name="certs_text">Sólo los auto-certificados y los certificados creados con las claves de usted se muestran aquí.</string>
<string name="section_uids_to_certify">Identidades a certificar</string>
<string name="label_revocation">Razón de la revocación</string>
<string name="label_verify_status">Estado de la verificación</string>
diff --git a/OpenKeychain/src/main/res/values-et/strings.xml b/OpenKeychain/src/main/res/values-et/strings.xml
index fdd7f026a..6ea0d1236 100644
--- a/OpenKeychain/src/main/res/values-et/strings.xml
+++ b/OpenKeychain/src/main/res/values-et/strings.xml
@@ -97,6 +97,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index e30ebb883..f383ac40b 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -27,6 +27,7 @@
<string name="title_key_details">Détails sur la clef</string>
<string name="title_help">Aide</string>
<string name="title_log_display">Journal</string>
+ <string name="title_create_key">Créer une clef</string>
<!--section-->
<string name="section_user_ids">identités</string>
<string name="section_keys">Sous-clefs</string>
@@ -84,8 +85,8 @@
<string name="label_algorithm">Algorithme</string>
<string name="label_ascii_armor">Fichier ASCII Armor</string>
<string name="label_file_ascii_armor">Fichier : ASCII Armor</string>
- <string name="label_write_version_header">Informez les autres de votre utilisation d\'OpenKeychain</string>
- <string name="label_write_version_header_summary">Ajoute « OpenKeychain v2.7 » aux signatures OpenPGP, aux cryptogrammes, et aux clefs exportées</string>
+ <string name="label_write_version_header">Faire savoir aux autres que vous utilisez OpenKeychain</string>
+ <string name="label_write_version_header_summary">Ajoute « OpenKeychain v2.7 » aux signatures OpenPGP, aux cryptogrammes et aux clefs exportées</string>
<string name="label_asymmetric_from">De :</string>
<string name="label_to">À :</string>
<string name="label_delete_after_encryption">Fichier : supprimer après chiffrement</string>
@@ -97,9 +98,8 @@
<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 anciennes signatures OpenPGP v3</string>
<string name="label_keyservers">Serveurs de clefs</string>
- <string name="label_key_id">ID de le clef</string>
+ <string name="label_key_id">ID de clef</string>
<string name="label_creation">Création</string>
<string name="label_expiry">Expiration</string>
<string name="label_usage">Utilisation</string>
@@ -248,8 +248,8 @@
<string name="progress_generating_elgamal">génération d\'une nouvelle clef ElGamal...</string>
<string name="progress_modify">modification du trousseau...</string>
<string name="progress_modify_unlock">déverrouillage du trousseau...</string>
- <string name="progress_modify_adduid">ajout des IDs d\'utilisateur...</string>
- <string name="progress_modify_revokeuid">révocation des IDs d\'utilisateur...</string>
+ <string name="progress_modify_adduid">ajout des ID d\'utilisateur...</string>
+ <string name="progress_modify_revokeuid">révocation des ID d\'utilisateur...</string>
<string name="progress_modify_primaryuid">changement de l\'ID d\'utilisateur principale...</string>
<string name="progress_modify_subkeychange">modification des sous-clefs...</string>
<string name="progress_modify_subkeyrevoke">révocation des sous-clefs...</string>
@@ -275,9 +275,12 @@
<string name="progress_decompressing_data">décompression des données...</string>
<string name="progress_verifying_integrity">vérification de l\'intégrité...</string>
<string name="progress_deleting_securely">suppression sûre de « %s »...</string>
+ <string name="progress_deleting">suppression des clefs...</string>
+ <string name="progress_con_saving">consolider : enregistrement dans le cache...</string>
+ <string name="progress_con_reimport">consolider : réimportation...</string>
<!--action strings-->
- <string name="hint_public_keys">Nom/courriel/ ID clef...</string>
- <string name="hint_keybase_search">Nom/nom d\'utilisateur keybase.io...</string>
+ <string name="hint_keyserver_search_hint">Nom/courriel/ID de clef...</string>
+ <string name="hint_keybase_search_hint">Nom/courriel/preuve/clef...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -356,13 +359,15 @@
<string name="api_settings_accounts">Comptes</string>
<string name="api_settings_accounts_empty">Aucun compte n\'est attaché à cette appli.</string>
<string name="api_create_account_text">L\'appli demande la création d\'un nouveau compte. Veuillez choisir une de vos clefs existantes ou en créer une nouvelle.\nLes applis ne peuvent utiliser que les clefs que vous choisissez ici !</string>
+ <string name="api_update_account_text">La clef enregistrée pour ce compte a été supprimée. Veuillez en choisir une autre !\nLes applis sont restreintes à l\'utilisation de clefs choisies ici.</string>
<string name="api_register_text">L\'application affichée veut chiffrer/déchiffrer des messages et les signer en votre nom.\nPermettre l\'accès ?\n\nAVERTISSEMENT : si vous ne savez pas pourquoi cet écran est apparu, refusez l\'accès ! Vous pourrez révoquer l\'accès plus tard en utilisant l\'écran « Applis ».</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>
- <string name="api_select_pub_keys_missing_text">Aucune clef publique n\'a été trouvée pour ces identités :</string>
- <string name="api_select_pub_keys_dublicates_text">Plus d\'une clef publique existe pour ces identités :</string>
+ <string name="api_select_pub_keys_missing_text">Aucune clef n\'a été trouvée pour ces identités :</string>
+ <string name="api_select_pub_keys_dublicates_text">Plus d\'une clef existe pour ces identités :</string>
<string name="api_select_pub_keys_text">Veuillez revoir la liste des destinataires !</string>
+ <string name="api_select_pub_keys_text_no_user_ids">Veuillez choisir les destinataires !</string>
<string name="api_error_wrong_signature">La vérification de la signature a échoué ! Avez-vous installé cette appli à partir d\'une source différente ? Si vous êtes sûr que ce n\'est pas une attaque, révoquez l\'enregistrement de cette appli dans OpenKeychain et enregistrez-la à nouveau.</string>
<!--Share-->
<string name="share_qr_code_dialog_title">Partager par un code QR</string>
@@ -389,6 +394,14 @@
<string name="key_view_tab_share">Partager</string>
<string name="key_view_tab_keys">Sous-clefs</string>
<string name="key_view_tab_certs">Certificats</string>
+ <string name="user_id_info_revoked_title">Révoquée</string>
+ <string name="user_id_info_revoked_text">Cette identité a été révoquée par le propriétaire de la clef. Elle n\'est plus valide.</string>
+ <string name="user_id_info_verified_title">Vérifiée</string>
+ <string name="user_id_info_verified_text">Cette identité a été vérifiée.</string>
+ <string name="user_id_info_not_verified_title">Non vérifiée</string>
+ <string name="user_id_info_not_verified_text">Cette identité n\'a pas encore été vérifiée. Vous ne pouvez pas être certain si l\'identité corresponds vraiment à une personne spécifique.</string>
+ <string name="user_id_info_invalid_title">Invalide</string>
+ <string name="user_id_info_invalid_text">Quelque chose ne va pas avec cette identité !</string>
<!--Edit key-->
<string name="edit_key_action_change_passphrase">Changer la phrase de passe</string>
<string name="edit_key_action_add_identity">Ajouter une identité</string>
@@ -408,6 +421,7 @@
<item>Révoquer la sous-clef</item>
</string-array>
<string name="edit_key_new_subkey">nouvelle</string>
+ <string name="edit_key_select_flag">Veuillez sélectionner au moins un drapeau !</string>
<!--Create key-->
<string name="create_key_upload">Téléverser la clef vers le serveur de clefs</string>
<string name="create_key_empty">Ce champ est exigé</string>
@@ -443,6 +457,7 @@
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">Application de l\'opération d\'insertion par lot.</string>
<string name="msg_ip_bad_type_secret">Tentative d\'importer le trousseau secret comme public. Ceci est un bogue, veuillez remplir un rapport !</string>
+ <string name="msg_kc_v3_key">Cette clef est une clef d\'OpenPGP version 3 et n\'est, par conséquent, pas sécuritaire. Elle n\'a pas été importée. </string>
<string name="msg_ip_delete_old_fail">Aucune ancienne clef de supprimée (création d\'une nouvelle ?)</string>
<string name="msg_ip_delete_old_ok">L\'ancienne clef a été supprimée de la base de données</string>
<string name="msg_ip_encode_fail">Échec de l\'opération causé par une erreur d\'encodage</string>
@@ -548,7 +563,7 @@
<string name="msg_kc_uid_bad_time">Suppression de l\'ID d\'utilisateur ayant une estampille temporelle dans le futur</string>
<string name="msg_kc_uid_bad_type">Suppression du certificat d\'ID d\'utilisateur de type inconnu (%s)</string>
<string name="msg_kc_uid_bad">Suppression du mauvais auto-certificat pour l\'ID d\'utilisateur « %s »</string>
- <string name="msg_kc_uid_dup">Suppression de l\'auto-certificat périmé pour l\'ID d\'utilisateur « %s »</string>
+ <string name="msg_kc_uid_cert_dup">Suppression de l\'auto-certificat périmé pour l\'ID d\'utilisateur « %s »</string>
<string name="msg_kc_uid_foreign">Suppression du certificat étranger d\'ID d\'utilisateur par %s</string>
<string name="msg_kc_uid_revoke_dup">Suppression du certificat de révocation redondant pour l\'ID d\'utilisateur « %s »</string>
<string name="msg_kc_uid_revoke_old">Suppression du certificat de révocation périmé pour l\'ID d\'utilisateur « %s »</string>
@@ -557,8 +572,8 @@
<!--Keyring merging log entries-->
<string name="msg_mg_public">Fusion vers le trousseau public %s</string>
<string name="msg_mg_secret">Fusion vers le trousseau secret %s</string>
- <string name="msg_mg_fatal_encode">Erreur fatale lors de l\'encodage de la signature</string>
- <string name="msg_mg_heterogeneous">Il a été tenté de consolider les trousseaux hétérogènes</string>
+ <string name="msg_mg_error_encode">Erreur fatale lors de l\'encodage de la signature</string>
+ <string name="msg_mg_error_heterogeneous">Il a été tenté de fusionner des trousseaux avec des empreintes différentes !</string>
<string name="msg_mg_new_subkey">Ajout de la nouvelle sous-clef %s</string>
<string name="msg_mg_found_new">%s nouveaux certificats trouvés dans le trousseau</string>
<string name="msg_mg_unchanged">Aucun nouveau certificat</string>
@@ -567,6 +582,7 @@
<string name="msg_cr_error_no_master">Aucune option de clef maîtresse n\'a été spécifiée !</string>
<string name="msg_cr_error_no_user_id">Les trousseaux doivent être créés avec au moins un ID d\'utilisateur !</string>
<string name="msg_cr_error_no_certify">La clef maîtresse doit avoir le drapeau « certifié » !</string>
+ <string name="msg_cr_error_null_expiry">L\'expiration ne peut pas être « pareille qu\'avant » lors de la création de clefs. Ceci est une erreur de programmation, veuillez remplir un rapport de bogue !</string>
<string name="msg_cr_error_keysize_512">La taille de la clef doit être supérieure ou égale à 512 !</string>
<string name="msg_cr_error_internal_pgp">Erreur interne PGP !</string>
<string name="msg_cr_error_unknown_algo">Mauvais choix d’algorithme !</string>
@@ -577,18 +593,26 @@
<string name="msg_mf_error_fingerprint">L\'empreinte de clef effective ne correspond pas à celle attendue !</string>
<string name="msg_mf_error_keyid">Aucune ID de clef. Ceci est une erreur interne, veuillez remplir un rapport de bogue !</string>
<string name="msg_mf_error_integrity">Erreur interne, le contrôle d\'intégrité a échoué !</string>
- <string name="msg_mf_error_noexist_primary">Mauvais ID principal spécifié !</string>
- <string name="msg_mf_error_revoked_primary">Les IDs d\'utilisateurs révoqués ne peuvent pas être principaux !</string>
+ <string name="msg_mf_error_master_none">Aucun certificat maître sur lequel se basé n\'a été trouvé ! (Tous révoqués ?)</string>
+ <string name="msg_mf_error_noexist_primary">Mauvais ID d\'utilisateur principal spécifié !</string>
+ <string name="msg_mf_error_noexist_revoke">Mauvais ID d\'utilisateur spécifié pour la révocation !</string>
+ <string name="msg_mf_error_revoked_primary">Les ID d\'utilisateurs révoqués ne peuvent pas être principaux !</string>
+ <string name="msg_mf_error_null_expiry">L\'expiration ne peut pas être « pareille qu\'avant » lors de la création de sous-clefs. Ceci est une erreur de programmation, veuillez remplir un rapport de bogue !</string>
+ <string name="msg_mf_error_passphrase_master">Erreur fatale lors du déchiffrement de la clef maîtresse ! Ceci est probablement une erreur de programmation, veuillez remplir un rapport de bogue !</string>
<string name="msg_mf_error_pgp">Exception interne PGP !</string>
<string name="msg_mf_error_sig">Exception de signature !</string>
- <string name="msg_mf_passphrase">Changement de la phrase de passe</string>
+ <string name="msg_mf_master">Modification des certifications maîtresses</string>
+ <string name="msg_mf_passphrase">Changement de la phrase de passe pour le trousseau...</string>
+ <string name="msg_mf_passphrase_key">Rechiffrement de la sous-clef %s avec la nouvelle phrase de passe</string>
+ <string name="msg_mf_passphrase_empty_retry">Échec lors de la définition de la nouvelle phrase de passe, nouvel essai avec une ancienne phrase de passe vide</string>
+ <string name="msg_mf_passphrase_fail">La phrase de passe de la sous-clef n\'a pas pu être changée ! (Est-elle différente des autres clefs ?)</string>
<string name="msg_mf_primary_replace_old">Remplacement du certificat de l\'ID d\'utilisateur principal précédent</string>
<string name="msg_mf_primary_new">Génération d\'un nouveau certificat pour le nouvel ID d\'utilisateur principal</string>
<string name="msg_mf_subkey_change">Modification de la sous-clef %s</string>
- <string name="msg_mf_subkey_missing">Une action a été tentée sur la sous-clef manquante %s !</string>
- <string name="msg_mf_subkey_new">Génération d\'une nouvelle sous-clef %2$s de %1$s bit</string>
- <string name="msg_mf_subkey_new_id">ID de la nouvelle sous-clef : %s</string>
- <string name="msg_mf_subkey_past_expiry">La date d\'expiration ne peut pas être dans le passé !</string>
+ <string name="msg_mf_error_subkey_missing">Une action a été tentée sur la sous-clef manquante %s !</string>
+ <string name="msg_mf_subkey_new">Ajout de la nouvelle sous-clef de type %2$s (%1$s bit)</string>
+ <string name="msg_mf_subkey_new_id">Nouvelle ID de sous-clef : %s</string>
+ <string name="msg_mf_error_past_expiry">La date d\'expiration ne peut pas être dans le passé !</string>
<string name="msg_mf_subkey_revoke">Révocation de la sous-clef %s</string>
<string name="msg_mf_success">Trousseau modifié avec succès</string>
<string name="msg_mf_uid_add">Ajout de l\'ID d\'utilisateur %s</string>
@@ -597,6 +621,40 @@
<string name="msg_mf_uid_error_empty">L\'ID d\'utilisateur ne peut pas être vide !</string>
<string name="msg_mf_unlock_error">Erreur lors du déverrouillage du trousseau !</string>
<string name="msg_mf_unlock">Déverrouillage du trousseau</string>
+ <!--Consolidate-->
+ <string name="msg_con">Consolidation de la base de données</string>
+ <string name="msg_con_error_bad_state">La consolidation a été commencée alors qu\'aucune base de données n\'était en cache ! Ceci est probablement une erreur de programmation, veuillez remplir un rapport de bogue !</string>
+ <string name="msg_con_error_concurrent">La consolidation a été abandonnée, elle est déjà en cours sur un autre exétron !</string>
+ <string name="msg_con_save_secret">Enregistrement des trousseaux secrets</string>
+ <string name="msg_con_save_public">Enregistrement des trousseaux publiques</string>
+ <string name="msg_con_db_clear">Nettoyage de la base de données</string>
+ <string name="msg_con_success">Base de données consolidée avec succès</string>
+ <string name="msg_con_critical_in">Début de la phase critique</string>
+ <string name="msg_con_critical_out">Fin de la phase critique</string>
+ <string name="msg_con_delete_public">Suppression du fichier de cache du trousseau public</string>
+ <string name="msg_con_delete_secret">Suppression du fichier de cache du trousseau secret</string>
+ <string name="msg_con_error_db">Erreur lors de l\'ouverture de la base de données !</string>
+ <string name="msg_con_error_io_public">Erreur E/S lors de l\'écriture des clefs publiques vers le cache !</string>
+ <string name="msg_con_error_io_secret">Erreur E/S lors de l\'écriture des clefs secrètes vers le cache !</string>
+ <string name="msg_con_error_public">Erreur lors de la réimportation des clefs publiques !</string>
+ <string name="msg_con_error_secret">Erreur lors de la réimportation des clefs secrètes !</string>
+ <plurals name="msg_con_recover">
+ <item quantity="one">Consolidation de récupération avec %1$d clef secrète et %2$d publique</item>
+ <item quantity="other">Consolidation de récupération avec %1$d clefs secrètes et %2$d publiques</item>
+ </plurals>
+ <string name="msg_con_recover_unknown">Récupération à partir d\'un état inconnu</string>
+ <plurals name="msg_con_reimport_public">
+ <item quantity="one">Réimportation d\'une clef publique</item>
+ <item quantity="other">Réimportation de %d clefs publiques</item>
+ </plurals>
+ <string name="msg_con_reimport_public_skip">Aucune clef publique à réimporter, étape ignorée...</string>
+ <plurals name="msg_con_reimport_secret">
+ <item quantity="one">Réimportation d\'une clef secrète</item>
+ <item quantity="other">Réimportation de %d clefs secrètes</item>
+ </plurals>
+ <string name="msg_con_reimport_secret_skip">Aucune clef secrète à réimporter, étape ignorée...</string>
+ <string name="msg_con_warn_delete_public">Une exception a eu lieu lors de la suppression du fichier de cache public</string>
+ <string name="msg_con_warn_delete_secret">Une exception a eu lieu lors de la suppression du fichier de cache secret</string>
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Cliquer ici pour effacer les phrases de passe mises en cache</string>
<string name="passp_cache_notif_n_keys">OpenKeychain a mis en cache %d phrases de passe</string>
@@ -610,6 +668,7 @@
<string name="label_user_id">identité</string>
<string name="unknown_uid">&lt;inconnu&gt;</string>
<string name="empty_certs">Aucun certificat pour cette clef</string>
+ <string name="certs_text">Seuls les auto-certificats et les certificats créés avec vos clefs sont affichés ici.</string>
<string name="section_uids_to_certify">Identités à certifier</string>
<string name="label_revocation">Raison de la révocation</string>
<string name="label_verify_status">État de vérification</string>
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 89e09783b..e4e08ca78 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -1,9 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--title-->
+ <string name="title_select_recipients">Seleziona chiavi</string>
+ <string name="title_select_secret_key">Seleziona la Tua Chiave</string>
<string name="title_encrypt">Codifica</string>
<string name="title_decrypt">Decodifica</string>
<string name="title_authentication">Frase di accesso</string>
+ <string name="title_add_subkey">Aggiungi Sottochiave</string>
<string name="title_edit_key">Modifica Chiave</string>
<string name="title_preferences">Preferenze</string>
<string name="title_api_registered_apps">Apps</string>
@@ -12,6 +15,7 @@
<string name="title_share_fingerprint_with">Condivi impronta con...</string>
<string name="title_share_key">Condividi chiave con...</string>
<string name="title_share_file">Condividi file con...</string>
+ <string name="title_share_message">Condividi messaggio con...</string>
<string name="title_encrypt_to_file">Codifica File</string>
<string name="title_decrypt_to_file">Decodifica File</string>
<string name="title_import_keys">Importa Chiavi</string>
@@ -23,6 +27,7 @@
<string name="title_key_details">Dettagli Chiave</string>
<string name="title_help">Aiuto</string>
<string name="title_log_display">Registro</string>
+ <string name="title_create_key">Crea Chiave</string>
<!--section-->
<string name="section_user_ids">Identità</string>
<string name="section_keys">Sottochiavi</string>
@@ -40,20 +45,27 @@
<string name="btn_decrypt_verify_file">Decodifica, verifica e salva su file</string>
<string name="btn_decrypt_verify_message">Decodifica e verifica messaggio</string>
<string name="btn_encrypt_file">Codifica e salva file</string>
+ <string name="btn_encrypt_share_file">Codifica e condividi file</string>
<string name="btn_save">Salva</string>
<string name="btn_do_not_save">Annulla</string>
<string name="btn_delete">Elimina</string>
+ <string name="btn_no_date">Nessuna Scadenza</string>
<string name="btn_okay">OK</string>
<string name="btn_export_to_server">Carica sul Server delle Chiavi</string>
<string name="btn_next">Prossimo</string>
<string name="btn_back">Precedente</string>
<string name="btn_lookup_key">Chiave di ricerca</string>
+ <string name="btn_share_encrypted_signed">Codifica e condividi messaggio</string>
<string name="btn_view_cert_key">Mostra chiave di certificazione</string>
+ <string name="btn_create_key">Crea chiave</string>
+ <string name="btn_add_files">Aggiungi file(s)</string>
<!--menu-->
<string name="menu_preferences">Impostazioni</string>
<string name="menu_help">Aiuto</string>
<string name="menu_export_key">Esporta su un file</string>
<string name="menu_delete_key">Cancella chiave</string>
+ <string name="menu_create_key">Crea mia chiave</string>
+ <string name="menu_import_existing_key">Importa chiavi esistenti</string>
<string name="menu_search">Cerca</string>
<string name="menu_beam_preferences">Impostazioni Beam</string>
<string name="menu_key_edit_cancel">Annulla</string>
@@ -65,19 +77,27 @@
<!--label-->
<string name="label_message">Messaggio</string>
<string name="label_file">File</string>
+ <string name="label_files">File(s)</string>
+ <string name="label_file_colon">File:</string>
<string name="label_no_passphrase">Nessuna Frase di Accesso</string>
<string name="label_passphrase">Frase di Accesso</string>
<string name="label_passphrase_again">Ripeti Frase di Accesso</string>
<string name="label_algorithm">Algortimo</string>
+ <string name="label_ascii_armor">Documenti con Armatura ASCII</string>
+ <string name="label_file_ascii_armor">Documenti: Armatura ASCII</string>
<string name="label_write_version_header">Fai sapere agli altri che utilizzi OpenKeychain</string>
<string name="label_write_version_header_summary">Scrive \'OpenKeychain v2.7\' nelle firme OpenPGP, testi cifrati e chiavi esportate</string>
+ <string name="label_asymmetric_from">Da:</string>
+ <string name="label_to">A:</string>
+ <string name="label_delete_after_encryption">Documenti: Cancella Dopo Codifica</string>
<string name="label_delete_after_decryption">Cancella Dopo Decodifica</string>
<string name="label_encryption_algorithm">Algoritmo di Codifica</string>
<string name="label_hash_algorithm">Algoritmo di Hash</string>
+ <string name="label_asymmetric">Con Chiave Pubblica</string>
+ <string name="label_symmetric">Con Frase di Accesso</string>
<string name="label_passphrase_cache_ttl">Cache Frase di Accesso</string>
<string name="label_message_compression">Compressione Messaggio</string>
<string name="label_file_compression">Compressione File</string>
- <string name="label_force_v3_signature">Forza vecchie Firme OpenPGPv3</string>
<string name="label_keyservers">Server Chiavi</string>
<string name="label_key_id">ID Chiave</string>
<string name="label_creation">Creazione</string>
@@ -156,6 +176,7 @@
<string name="key_deletion_confirmation_multi">Vuoi veramente eliminare tutte le chiavi pubbliche selezionate?\nNon potrai annullare!</string>
<string name="secret_key_deletion_confirmation">Vuoi veramente eliminare la chiave PRIVATA \'%s\'?\nNon potrai annullare!</string>
<string name="public_key_deletetion_confirmation">Vuoi veramente eliminare la chiave pubblica \'%s\'?\nNon potrai annullare!</string>
+ <string name="also_export_secret_keys">Esporta anche chiave segreta</string>
<string name="key_exported">1 chiave esportata correttamente.</string>
<string name="keys_exported">%d chiavi esportate correttamente.</string>
<string name="no_keys_exported">Nessuna chiave esportata.</string>
@@ -194,6 +215,11 @@
<string name="error_jelly_bean_needed">Devi avere Android 4.1 per usare Android NFC Beam!</string>
<string name="error_nfc_needed">NFC non disponibile nel tuo dispositivo!</string>
<string name="error_nothing_import">Nessuna chiave trovata!</string>
+ <string name="error_query_too_short">Query di ricerca troppo. Per favore ridefinisci la tua ricerca!</string>
+ <string name="error_searching_keys">C\'è stato un errore durante la ricerca delle chiavi.</string>
+ <string name="error_too_many_responses">La query di ricerca della chiave ha generato troppi risultati. Per favore ridefinisci la tua ricerca!</string>
+ <string name="error_too_short_or_too_many_responses">In entrambi i casi sono state trovate troppe o nessuna chiave. Si prega di migliorare la vostra ricerca!</string>
+ <string name="error_import_no_valid_keys">Nessuna chiave valida trovata nei File/Appunti!</string>
<string name="error_generic_report_bug">Si è verificato un errore generico, si prega di creare una nuova segnalazione di errore per OpenKeychain.</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">parte del file caricato e\' un oggetto OpenPGP valido, ma non una chave OpenPGP</item>
@@ -214,8 +240,21 @@
<string name="progress_saving">salvataggio...</string>
<string name="progress_importing">importazione...</string>
<string name="progress_exporting">esportazione...</string>
+ <string name="progress_uploading">caricamento...</string>
<string name="progress_building_key">fabbricazione chiave...</string>
<string name="progress_building_master_key">fabbricazione portachiavi principale...</string>
+ <string name="progress_generating_rsa">generazione di una nuova chiave RSA...</string>
+ <string name="progress_generating_dsa">generazione di una nuova chiave DSA...</string>
+ <string name="progress_generating_elgamal">generazione di una nuova chiave ElGamal...</string>
+ <string name="progress_modify">modifica portachiavi...</string>
+ <string name="progress_modify_unlock">Sblocco portachiavi...</string>
+ <string name="progress_modify_adduid">Aggiunta ID utente...</string>
+ <string name="progress_modify_revokeuid">Revoca ID utente...</string>
+ <string name="progress_modify_primaryuid">Cambio ID utente primario...</string>
+ <string name="progress_modify_subkeychange">Modifica sottochiave...</string>
+ <string name="progress_modify_subkeyrevoke">Revoca sottochiave...</string>
+ <string name="progress_modify_subkeyadd">Aggiunta sottochiave...</string>
+ <string name="progress_modify_passphrase">Cambio frase di accesso...</string>
<plurals name="progress_exporting_key">
<item quantity="one">esportazione chiave...</item>
<item quantity="other">esportazione chiavi...</item>
@@ -230,14 +269,18 @@
<string name="progress_processing_signature">elaborazione firma...</string>
<string name="progress_verifying_signature">verifica firma...</string>
<string name="progress_signing">firma...</string>
+ <string name="progress_certifying">certificazione...</string>
<string name="progress_reading_data">lettura dati...</string>
<string name="progress_finding_key">ricerca chiave...</string>
<string name="progress_decompressing_data">decompressione dati...</string>
<string name="progress_verifying_integrity">verifica integrita\'...</string>
<string name="progress_deleting_securely">eliminazione sicura di \'%s\'...</string>
+ <string name="progress_deleting">cancellazione chiavi...</string>
+ <string name="progress_con_saving">consolidazione: salvataggio della cache...</string>
+ <string name="progress_con_reimport">consolidazione: reimportazione...</string>
<!--action strings-->
- <string name="hint_public_keys">Nome/Email/ID Chiave...</string>
- <string name="hint_keybase_search">Nome/Keybase.io nome utente...</string>
+ <string name="hint_keyserver_search_hint">Nome/Email/ID Chiave...</string>
+ <string name="hint_keybase_search_hint">Nome/Email/Certificato/Chiave...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -249,6 +292,7 @@
<string name="key_size_8192">8192</string>
<string name="key_size_custom">Lunghezza chiave peronalizzata</string>
<string name="key_size_custom_info">Digita lunghezza chiave personalizzata (in bit):</string>
+ <string name="key_size_custom_info_rsa">La lunghezza della chiave RSA deve essere maggiore di 1024 e al massimo 16384. Inoltre, deve essere multipla di 8.</string>
<string name="key_size_custom_info_dsa">La lunghezza della chiave DSA deve essere almeno 512 e al massimo 1024. Inoltre, deve essere multipla di 64.</string>
<!--compression-->
<string name="compression_fast">veloce</string>
@@ -275,6 +319,10 @@
<item quantity="one">Chiave importata correttamente.</item>
<item quantity="other">%1$d chiavi importate correttamente.</item>
</plurals>
+ <plurals name="import_keys_added_and_updated_2">
+ <item quantity="one">e chiave%2$s aggiornata.</item>
+ <item quantity="other">e aggiornate %1$d chiavi%2$s.</item>
+ </plurals>
<plurals name="import_keys_added">
<item quantity="one">Chiave%2$s importata correttamente.</item>
<item quantity="other">%1$d chiavi%2$s importate correttamente.</item>
@@ -310,13 +358,16 @@
<string name="api_settings_package_signature">SHA-256 della Firma del Pacchetto</string>
<string name="api_settings_accounts">Account</string>
<string name="api_settings_accounts_empty">Nessun account collegato a questa applicazione</string>
+ <string name="api_create_account_text">L\'applicazione richiede la creazione di un nuovo account. Si prega di selezionare una chiave esistente o crearne una nuova.\nLe applicazioni sono limitate all\'utilizzo delle chiavi selezionate qui!</string>
+ <string name="api_update_account_text">La chiave salvata per questo account è stata cancellata. Perfavore selezionane una diversa!\nLe applicazioni sono limitate all\'utilizzo delle chiavi qui selezionate!</string>
<string name="api_register_text">Le app visualizzate hanno richiesto l\'accesso a OpenKeychain.\nPermetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' apparsa, nega l\'accesso! Puoi revocare l\'accesso dopo, usando la schermata \'App Registrate\'.</string>
<string name="api_register_allow">Permetti accesso</string>
<string name="api_register_disallow">Nega accesso</string>
<string name="api_register_error_select_key">Per favore selezionare una chiave!</string>
- <string name="api_select_pub_keys_missing_text">Nessuna chiave pubblica trovata per queste identità:</string>
- <string name="api_select_pub_keys_dublicates_text">Esistono piu\' di una chiave pubblica per queste identità:</string>
+ <string name="api_select_pub_keys_missing_text">Nessuna chiave trovata per queste identità:</string>
+ <string name="api_select_pub_keys_dublicates_text">Esistono piu\' di una chiave per queste identità:</string>
<string name="api_select_pub_keys_text">Per favore ricontrolla la lista destinatari!</string>
+ <string name="api_select_pub_keys_text_no_user_ids">Per favore seleziona i destinatari!</string>
<string name="api_error_wrong_signature">Controllo della firma fallito! Hai installato questa app da una fonte diversa? Se sei sicuro che non sia un attacco, revoca la registrazione di questa app in OpenKeychain e dopo registra di nuovo l\'app.</string>
<!--Share-->
<string name="share_qr_code_dialog_title">Condividi tramite Codice QR</string>
@@ -330,16 +381,27 @@
<string name="key_list_empty_text2">Puoi iniziare da</string>
<string name="key_list_empty_text3">o</string>
<string name="key_list_empty_button_create">creazione della tua chiave</string>
+ <string name="key_list_empty_button_import">importazione di chiave esistente.</string>
<!--Key view-->
<string name="key_view_action_edit">Modifica chiave</string>
<string name="key_view_action_encrypt">Codifica con questa chiave</string>
<string name="key_view_action_certify">Certifica identità</string>
+ <string name="key_view_action_update">Aggiorna dal server delle chiavi</string>
<string name="key_view_action_share_with">Condividi con...</string>
<string name="key_view_action_share_nfc">Condividi con NFC tenendo i dispositivi a stretto contatto</string>
+ <string name="key_view_action_upload">Carica nel server delle chiavi</string>
<string name="key_view_tab_main">Info Principale</string>
<string name="key_view_tab_share">Condividi</string>
<string name="key_view_tab_keys">Sottochiavi</string>
<string name="key_view_tab_certs">Certificati</string>
+ <string name="user_id_info_revoked_title">Revocato</string>
+ <string name="user_id_info_revoked_text">Questa identità è stata revocata dal suo proprietario. Non è più valida.</string>
+ <string name="user_id_info_verified_title">Verificato</string>
+ <string name="user_id_info_verified_text">Questa identità è stata verificata.</string>
+ <string name="user_id_info_not_verified_title">Non verificato</string>
+ <string name="user_id_info_not_verified_text">Questa identità non è stata ancora verificata. Non puoi esser sicuro che l\'identità corrisponda veramente ad una specifica persona.</string>
+ <string name="user_id_info_invalid_title">Non valido</string>
+ <string name="user_id_info_invalid_text">C\'è qualcosa che non va con questa identità!</string>
<!--Edit key-->
<string name="edit_key_action_change_passphrase">Cambia Frase Di Accesso</string>
<string name="edit_key_action_add_identity">Aggiungi Identità</string>
@@ -349,14 +411,25 @@
<item>Cambia in Identita\' Primaria</item>
<item>Revoca identita\'</item>
</string-array>
+ <string-array name="edit_key_edit_user_id_revert_revocation">
+ <item>Ripristina revoca</item>
+ </string-array>
+ <string name="edit_key_edit_user_id_revoked">Questa identità è stata revocata. Ciò non può essere annullato.</string>
<string name="edit_key_edit_subkey_title">Seleziona un azione!</string>
<string-array name="edit_key_edit_subkey">
<item>Cambia Scadenza</item>
<item>Revoca Sottochiave</item>
</string-array>
+ <string name="edit_key_new_subkey">nuovo</string>
+ <string name="edit_key_select_flag">Per favore seleziona almeno una spunta!</string>
<!--Create key-->
<string name="create_key_upload">Carica chiave nel server delle chiavi</string>
<string name="create_key_empty">Questo campo è necessario</string>
+ <string name="create_key_passphrases_not_equal">Le frasi di accesso non coincidono.</string>
+ <string name="create_key_final_text">Hai inserito la seguente identità:</string>
+ <string name="create_key_final_robot_text">La creazione di una chiave richiede un po\' di tempo, prendi un caffè nel frattempo...\n(3 sottochiavi, RSA, 4096 bit)</string>
+ <string name="create_key_text">Inserisci Nome Completo, Email e scegli una Frase di Accesso.</string>
+ <string name="create_key_hint_full_name">Nome completo, es: Mario Rossi</string>
<!--View key-->
<string name="view_key_revoked">Questa chiave è stata revocata!</string>
<string name="view_key_expired">Questa chiave è scaduta</string>
@@ -369,6 +442,7 @@
<string name="drawer_close">Chiudi drawer di navigazione</string>
<string name="my_keys">Le Mie Chiavi</string>
<!--hints-->
+ <string name="encrypt_content_edit_text_hint">Il messaggio inserito in questo campo verrà firmato con la chiave selezionata in \'Da\' e crittografato per tutti i destinatari selezionati in \'A\'.</string>
<string name="decrypt_content_edit_text_hint">Inserisci il testo cifrato qui per la decodifica e/o verifica...</string>
<!--certs-->
<string name="cert_default">predefiniti</string>
@@ -383,6 +457,7 @@
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">Applicazione inserimento operazioni in batch.</string>
<string name="msg_ip_bad_type_secret">Ho cercato di importare portachiavi privato come pubblico. Questo è un bug, per cortesia inviateci un rapporto!</string>
+ <string name="msg_kc_v3_key">Questa chiave è una chiave OpenPGP versione 3 e quindi non sicura. Non è stata importata.</string>
<string name="msg_ip_delete_old_fail">Nessuna vecchia chiave cancellata (stai creando una nuova?)</string>
<string name="msg_ip_delete_old_ok">Cancellate vecchie chiavi dal database</string>
<string name="msg_ip_encode_fail">Operazione fallita a causa di un errore di codifica</string>
@@ -488,7 +563,7 @@
<string name="msg_kc_uid_bad_time">Rimozione ID utente con marca temporale futura</string>
<string name="msg_kc_uid_bad_type">Rimozione certificato ID utente di tipo sconosciuto (%s)</string>
<string name="msg_kc_uid_bad">Rimozione autocertificazione corrotta per ID utente \"%s\"</string>
- <string name="msg_kc_uid_dup">Rimozione autocertificazione scaduta per ID utente \"%s\"</string>
+ <string name="msg_kc_uid_cert_dup">Rimozione autocertificazione scaduta per ID utente \"%s\"</string>
<string name="msg_kc_uid_foreign">Rimozione certificato ID utente estraneo di %s</string>
<string name="msg_kc_uid_revoke_dup">Rimozione certificato di revoca ridondante per ID utente \"%s\"</string>
<string name="msg_kc_uid_revoke_old">Rimozione certificato di revoca scaduto per ID utente \"%s\"</string>
@@ -497,8 +572,8 @@
<!--Keyring merging log entries-->
<string name="msg_mg_public">Fusione nel portachiavi pubblico %s</string>
<string name="msg_mg_secret">Fusione nel portachiavi privato %s</string>
- <string name="msg_mg_fatal_encode">Errore fatale nella codifica della firma</string>
- <string name="msg_mg_heterogeneous">Tentativo di consolidare portachiavi eterogenei</string>
+ <string name="msg_mg_error_encode">Errore fatale nella codifica della firma</string>
+ <string name="msg_mg_error_heterogeneous">Tentativo di unire portachiavi con impronte digitali diverse!</string>
<string name="msg_mg_new_subkey">Aggiunta nuova sottochiave %s</string>
<string name="msg_mg_found_new">Trovati %s nuovi certificati nel portachiavi</string>
<string name="msg_mg_unchanged">Nessun nuovo certificato</string>
@@ -507,6 +582,7 @@
<string name="msg_cr_error_no_master">Nessuna opzione della chiave principale specificata!</string>
<string name="msg_cr_error_no_user_id">I portachiavi devono essere creati con almeno un ID utente!</string>
<string name="msg_cr_error_no_certify">La chiave principale deve avere la caratteristica di certificazione!</string>
+ <string name="msg_cr_error_null_expiry">La data di scadenza non può essere \"come prima\" sulla creazione di chiavi. Questo è un errore di programmazione, si prega di inviare una segnalazione di bug!</string>
<string name="msg_cr_error_keysize_512">La grandezza della chiave deve essere di 512bit o maggiore</string>
<string name="msg_cr_error_internal_pgp">Errore PGP interno!</string>
<string name="msg_cr_error_unknown_algo">Pessima opzione di algortimo!</string>
@@ -517,18 +593,26 @@
<string name="msg_mf_error_fingerprint">Impronta chiave attuale non corrispondente!</string>
<string name="msg_mf_error_keyid">Nessun ID chiave. Questo è un errore di programmazione, per favore invia una segnalazione!</string>
<string name="msg_mf_error_integrity">Errore interno, controllo di integrità fallito!</string>
+ <string name="msg_mf_error_master_none">Nessun certificato principale trovato su cui operare! (Tutti revocati?)</string>
<string name="msg_mf_error_noexist_primary">ID utente primario specificato non valido!</string>
+ <string name="msg_mf_error_noexist_revoke">ID utente specificato non valido per la revoca!</string>
<string name="msg_mf_error_revoked_primary">ID utente revocato non può essere primario!</string>
+ <string name="msg_mf_error_null_expiry">La data di scadenza non può essere \"come prima\" sulla creazione di sottochiavi. Questo è un errore di programmazione, si prega di inviare una segnalazione di bug!</string>
+ <string name="msg_mf_error_passphrase_master">Errore irreversibile nella decodifica della chiave principale! Questo è probabilmente un errore di programmazione, si prega di inviare una segnalazione di bug!</string>
<string name="msg_mf_error_pgp">Eccezione interna di PGP!</string>
<string name="msg_mf_error_sig">Eccezione di firma!</string>
- <string name="msg_mf_passphrase">Cambio frase di accesso</string>
+ <string name="msg_mf_master">Modifica delle certificazioni principali</string>
+ <string name="msg_mf_passphrase">Cambio frase di accesso del portachiavi...</string>
+ <string name="msg_mf_passphrase_key">Ri-codifica sottochiave %s con nuova frase di accesso</string>
+ <string name="msg_mf_passphrase_empty_retry">Impostazione nuova frase di accesso fallita, provo di nuovo con frase precedente di accesso vuota</string>
+ <string name="msg_mf_passphrase_fail">La frase di accesso per la sottochiave non può essere modificata! (Ne ha una diversa dalle altre chiavi?)</string>
<string name="msg_mf_primary_replace_old">Sostituzione certificato del ID utente primario precedente</string>
<string name="msg_mf_primary_new">Generazione di un nuovo certificato per il nuovo ID utente primario</string>
<string name="msg_mf_subkey_change">Modifica sottochiave %s</string>
- <string name="msg_mf_subkey_missing">Tentativo di operare su sottochiave mancante %s!</string>
- <string name="msg_mf_subkey_new">Generazione nuovi %1$s bit %2$s sottochiave</string>
+ <string name="msg_mf_error_subkey_missing">Tentativo di operare su sottochiave %s mancante!</string>
+ <string name="msg_mf_subkey_new">Aggiunta nuova sottochiave di tipo %2$s (%1$s bit)</string>
<string name="msg_mf_subkey_new_id">Nuovo ID sottochiave: %s</string>
- <string name="msg_mf_subkey_past_expiry">La data di scadenza non può essere passata!</string>
+ <string name="msg_mf_error_past_expiry">La data di scadenza non può essere nel passato!</string>
<string name="msg_mf_subkey_revoke">Revoca sottochiave %s</string>
<string name="msg_mf_success">Portachiavi modificato con successo</string>
<string name="msg_mf_uid_add">Aggiunta id utente %s</string>
@@ -537,6 +621,40 @@
<string name="msg_mf_uid_error_empty">ID Utente non può essere vuoto!</string>
<string name="msg_mf_unlock_error">Errore di apertura portachiavi!</string>
<string name="msg_mf_unlock">Apertura portachiavi</string>
+ <!--Consolidate-->
+ <string name="msg_con">Consolidazione database</string>
+ <string name="msg_con_error_bad_state">Il consolidamento è stato avviato mentre nessun database è stato memorizzato nella cache! Questo è probabilmente un errore di programmazione, si prega di aprire un bug report.</string>
+ <string name="msg_con_error_concurrent">Consolidamento interrotto, già in esecuzione su un altro processo!</string>
+ <string name="msg_con_save_secret">Salvataggio portachiavi privati</string>
+ <string name="msg_con_save_public">Salvataggio portachiavi pubblico</string>
+ <string name="msg_con_db_clear">Pulizia database</string>
+ <string name="msg_con_success">Consolidamento database con successo</string>
+ <string name="msg_con_critical_in">Ingresso fase critica</string>
+ <string name="msg_con_critical_out">Uscita fase critica</string>
+ <string name="msg_con_delete_public">Eliminazione del file di cache del portachiavi pubblico</string>
+ <string name="msg_con_delete_secret">Eliminazione del file di cache del portachiavi privato</string>
+ <string name="msg_con_error_db">Errore nell\'apertura del database</string>
+ <string name="msg_con_error_io_public">Errore di IO durante la scrittura delle chiavi pubbliche nella cache!</string>
+ <string name="msg_con_error_io_secret">Errore di IO durante la scrittura delle chiavi private nella cache!</string>
+ <string name="msg_con_error_public">Errore nella re-importazione delle chiavi pubbliche!</string>
+ <string name="msg_con_error_secret">Errore nella re-importazione delle chiavi private!</string>
+ <plurals name="msg_con_recover">
+ <item quantity="one">Recupero consolidamento con %1$d chiavi segrete e %2$d chiavi pubbliche</item>
+ <item quantity="other">Recupero consolidamento con %1$d chiavi segrete e %2$d chiavi pubbliche</item>
+ </plurals>
+ <string name="msg_con_recover_unknown">Recupero da situazione ignota</string>
+ <plurals name="msg_con_reimport_public">
+ <item quantity="one">Reimportazione di una chiave pubblica</item>
+ <item quantity="other">Reimportazione di %d chiavi pubbliche</item>
+ </plurals>
+ <string name="msg_con_reimport_public_skip">Nessuna chiave pubblica da reimportare, proseguo...</string>
+ <plurals name="msg_con_reimport_secret">
+ <item quantity="one">Reimportazione di una chiave privata</item>
+ <item quantity="other">Reimportazione di %d chiavi private</item>
+ </plurals>
+ <string name="msg_con_reimport_secret_skip">Nessuna chiave privata da reimportare, proseguo...</string>
+ <string name="msg_con_warn_delete_public">Eccezione durante la eliminazione del file di cache pubblico</string>
+ <string name="msg_con_warn_delete_secret">Eccezione durante la eliminazione del file di cache privato</string>
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Clicca per rimuovere la frase di accesso nella cache</string>
<string name="passp_cache_notif_n_keys">OpenKeychain ha memorizzato nella cache %d frasi di accesso</string>
@@ -550,6 +668,7 @@
<string name="label_user_id">Identit</string>
<string name="unknown_uid">&lt;sconosciuto&gt;</string>
<string name="empty_certs">Nessun certificato per questa chiave</string>
+ <string name="certs_text">Solo le autocertificazioni e i certificati creati con le tue chiavi vengono visualizzati qui.</string>
<string name="section_uids_to_certify">Identità da certificare</string>
<string name="label_revocation">Ragione della Revoca</string>
<string name="label_verify_status">Stato Verifica</string>
@@ -557,6 +676,7 @@
<string name="error_key_not_found">Chiave non trovata!</string>
<string name="error_key_processing">Errore di elaborazione chiave!</string>
<string name="key_stripped">ripulito</string>
+ <string name="secret_cannot_multiple">Le vostre chiavi possono essere eliminate solo singolarmente!</string>
<string name="title_view_cert">Visualizza Dettagli Certificati</string>
<string name="unknown_algorithm">sconosciuto</string>
<string name="can_sign_not">non può firmare</string>
@@ -565,5 +685,7 @@
<string name="contact_show_key">Mostra chiave (%s)</string>
<!--First Time-->
<string name="first_time_text1">Riappropriati della tua riservatezza con OpenKeychain!</string>
+ <string name="first_time_create_key">Crea mia chiave</string>
+ <string name="first_time_import_key">Importa Chiave esistente</string>
<string name="first_time_skip">Salta Installazione</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index dbb52d208..36cbe64b5 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -27,6 +27,7 @@
<string name="title_key_details">鍵の概要</string>
<string name="title_help">ヘルプ</string>
<string name="title_log_display">ログ</string>
+ <string name="title_create_key">鍵の生成</string>
<!--section-->
<string name="section_user_ids">ユーザID</string>
<string name="section_keys">副鍵</string>
@@ -97,7 +98,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">強制的に古いOpenPGPV3形式の署名にする</string>
<string name="label_keyservers">鍵サーバ</string>
<string name="label_key_id">鍵ID</string>
<string name="label_creation">生成</string>
@@ -271,8 +271,8 @@
<string name="progress_verifying_integrity">完全性の検証中...</string>
<string name="progress_deleting_securely">\'%s\' を完全に削除中…</string>
<!--action strings-->
- <string name="hint_public_keys">名前/メール/鍵ID...</string>
- <string name="hint_keybase_search">名前/Keybase.io名...</string>
+ <string name="hint_keyserver_search_hint">名前/メール/鍵ID...</string>
+ <string name="hint_keybase_search_hint">名前/メール/証明/鍵...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -347,13 +347,15 @@
<string name="api_settings_accounts">アカウント</string>
<string name="api_settings_accounts_empty">このアプリに接続されてるアカウントはありません。</string>
<string name="api_create_account_text">このアプリは新しいアカウントの生成を要求しています。すでにある鍵1つを選択するか、新たに生成してください。\nここであなたが選択する鍵の使い道についてアプリケーションには制約があります!</string>
+ <string name="api_update_account_text">このアカウントの削除された鍵を保存しました。異るものを選択してください!\nここであなたが選択する鍵の使い道についてはアプリには制約があります!</string>
<string name="api_register_text">表示されているアプリはメッセージの暗号/復号化とあなたの名前での署名付けを要求しています。\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_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_select_pub_keys_text_no_user_ids">受信者を選択してください!</string>
<string name="api_error_wrong_signature">署名チェックが失敗! 違うところからこのアプリをインストールしましたか? もし攻撃されてでなくそうであるなら、OpenKeychainにあるこのアプリの登録を破棄し、再度アプリを登録してください。</string>
<!--Share-->
<string name="share_qr_code_dialog_title">QRコードで共有</string>
@@ -379,6 +381,14 @@
<string name="key_view_tab_share">共有</string>
<string name="key_view_tab_keys">副鍵</string>
<string name="key_view_tab_certs">証明</string>
+ <string name="user_id_info_revoked_title">破棄</string>
+ <string name="user_id_info_revoked_text">このIDは鍵の所有者により破棄されています。もう適正ではありません。</string>
+ <string name="user_id_info_verified_title">検証</string>
+ <string name="user_id_info_verified_text">このIDは検証されています。</string>
+ <string name="user_id_info_not_verified_title">未検証</string>
+ <string name="user_id_info_not_verified_text">このIDはまだ検証されていません。IDが本当に特定の人に対応している場合を、あなたは確認することができません。</string>
+ <string name="user_id_info_invalid_title">不適正</string>
+ <string name="user_id_info_invalid_text">このIDではなにかしら問題があります!</string>
<!--Edit key-->
<string name="edit_key_action_change_passphrase">パスフレーズの変更</string>
<string name="edit_key_action_add_identity">ユーザIDの追加</string>
@@ -398,6 +408,7 @@
<item>副鍵を破棄</item>
</string-array>
<string name="edit_key_new_subkey">新規</string>
+ <string name="edit_key_select_flag">最低1つフラグを選択してください!</string>
<!--Create key-->
<string name="create_key_upload">鍵サーバへアップロード</string>
<string name="create_key_empty">このフィールドは必須です</string>
@@ -433,6 +444,7 @@
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">連続挿入処理を適用する。</string>
<string name="msg_ip_bad_type_secret">秘密鍵の鍵輪を公開鍵としてインポートを試行しました。これはバグで、ファイルをレポートしてください!</string>
+ <string name="msg_kc_v3_key">この鍵はOpenPGP v3形式の鍵で安全ではありません。そのためインポートできません。</string>
<string name="msg_ip_delete_old_fail">削除された古い鍵はありません (新しく作りますか?)</string>
<string name="msg_ip_delete_old_ok">データベースから古い鍵を削除しました</string>
<string name="msg_ip_encode_fail">エンコードエラーにより操作が失敗しました</string>
@@ -534,7 +546,7 @@
<string name="msg_kc_uid_bad_time">未来にタイムスタンプがあるユーザIDを破棄中</string>
<string name="msg_kc_uid_bad_type">不明な型 (%s) でのユーザID検証を破棄中</string>
<string name="msg_kc_uid_bad">ユーザID \"%s\" による問題のある自己検証を破棄中</string>
- <string name="msg_kc_uid_dup">期限の切れたユーザID \"%s\" による自己検証を破棄中</string>
+ <string name="msg_kc_uid_cert_dup">期限の切れたユーザID \"%s\" による自己検証を破棄中</string>
<string name="msg_kc_uid_foreign">%s によって検証されている外部ユーザIDを破棄中</string>
<string name="msg_kc_uid_revoke_dup">ユーザID \"%s\" による重複した破棄証明を破棄中</string>
<string name="msg_kc_uid_revoke_old">ユーザID \"%s\" による期限切れ破棄証明を破棄中</string>
@@ -543,8 +555,8 @@
<!--Keyring merging log entries-->
<string name="msg_mg_public">公開鍵の鍵輪 %s にマージ中</string>
<string name="msg_mg_secret">秘密鍵の鍵輪 %s にマージ中</string>
- <string name="msg_mg_fatal_encode">署名のエンコードでの致命的なエラー</string>
- <string name="msg_mg_heterogeneous">種類の異なる鍵輪を統合しようとした</string>
+ <string name="msg_mg_error_encode">署名のエンコードでの致命的なエラー</string>
+ <string name="msg_mg_error_heterogeneous">指紋が異なる鍵輪をマージしようとしています!</string>
<string name="msg_mg_new_subkey">新しい副鍵 %s を追加中</string>
<string name="msg_mg_found_new">鍵輪に新しい検証を %s 発見</string>
<string name="msg_mg_unchanged">新しい証明がない</string>
@@ -553,6 +565,7 @@
<string name="msg_cr_error_no_master">主鍵オプション特有ではありません!</string>
<string name="msg_cr_error_no_user_id">鍵輪は最低でも1つのユーザIDの生成が必要です!</string>
<string name="msg_cr_error_no_certify">主鍵は検証フラグが必須です!</string>
+ <string name="msg_cr_error_null_expiry">鍵の生成時に期限を\"過去\"とすることはできません。これはプログラムエラーで、バグレポートとしてファイルを送ってください!</string>
<string name="msg_cr_error_keysize_512">鍵サイズは512かそれ以上が必須です!</string>
<string name="msg_cr_error_internal_pgp">PGP内部エラー!</string>
<string name="msg_cr_error_unknown_algo">悪いアルゴリズムを選択しています!</string>
@@ -563,18 +576,24 @@
<string name="msg_mf_error_fingerprint">現実の鍵指紋が想定の1つと合致しませんでした!</string>
<string name="msg_mf_error_keyid">鍵IDがない。 これは内部エラーで、バグレポートの提出をお願いします!</string>
<string name="msg_mf_error_integrity">内部エラー、完全性チェックが失敗!</string>
+ <string name="msg_mf_error_master_none">マスター認証が操作で見付かりませんでした(すべて破棄しましたか?)</string>
<string name="msg_mf_error_noexist_primary">問題のある主ユーザIDが指定された!</string>
+ <string name="msg_mf_error_noexist_revoke">破棄において問題のあるユーザIDが指定された!</string>
<string name="msg_mf_error_revoked_primary">主ユーザIDの破棄はできません!</string>
+ <string name="msg_mf_error_null_expiry">副鍵の生成時に期限を\"過去\"とすることはできません。これはプログラムエラーで、バグレポートとしてファイルを送ってください!</string>
+ <string name="msg_mf_error_passphrase_master">主鍵の復号で致命的な失敗! これはプログラミングのエラーの場合がありますので、バグレポートの提出をお願いします!</string>
<string name="msg_mf_error_pgp">PGP内部例外!</string>
<string name="msg_mf_error_sig">署名例外!</string>
- <string name="msg_mf_passphrase">パスフレーズの変更中</string>
+ <string name="msg_mf_master">マスター認証を変更</string>
+ <string name="msg_mf_passphrase">鍵輪のパスフレーズの変更中...</string>
+ <string name="msg_mf_passphrase_empty_retry">新しいパスフレーズの設定に失敗しました、空の古いパスフレーズで再度試してください</string>
+ <string name="msg_mf_passphrase_fail">副鍵のパスフレーズは変更されていません! (他の鍵とは異なるになっていませんか?)</string>
<string name="msg_mf_primary_replace_old">以前の主ユーザIDで証明を入れ替え中</string>
<string name="msg_mf_primary_new">新しい主ユーザIDで新しい証明を生成中</string>
<string name="msg_mf_subkey_change">副鍵 %s を変更中</string>
- <string name="msg_mf_subkey_missing">遺失した副鍵 %s の操作をしようとした!</string>
- <string name="msg_mf_subkey_new">新しい %1$s ビットの %2$s 副鍵の生成中</string>
+ <string name="msg_mf_error_subkey_missing">見付からない副鍵 %s の操作をしようとした!</string>
<string name="msg_mf_subkey_new_id">新しい副鍵 ID: %s</string>
- <string name="msg_mf_subkey_past_expiry">期限切れ日を過去にはできません!</string>
+ <string name="msg_mf_error_past_expiry">期限切れ日を過去にはできません!</string>
<string name="msg_mf_subkey_revoke">副鍵 %s を破棄中</string>
<string name="msg_mf_success">鍵輪の変更に成功</string>
<string name="msg_mf_uid_add">ユーザID %s を追加中</string>
@@ -583,6 +602,34 @@
<string name="msg_mf_uid_error_empty">ユーザIDは空にすることはできません!</string>
<string name="msg_mf_unlock_error">鍵輪のロック解除エラー!</string>
<string name="msg_mf_unlock">鍵輪のロック解除中</string>
+ <!--Consolidate-->
+ <string name="msg_con">データベースの統合中</string>
+ <string name="msg_con_save_secret">秘密鍵の鍵輪を保存中</string>
+ <string name="msg_con_save_public">公開鍵の鍵輪を保存中</string>
+ <string name="msg_con_db_clear">データベースの消去中</string>
+ <string name="msg_con_success">データベースの統合が成功しました</string>
+ <string name="msg_con_critical_in">クリティカルなフェーズに入りました</string>
+ <string name="msg_con_critical_out">クリティカルなフェーズを抜けました</string>
+ <string name="msg_con_delete_public">公開鍵輪のキャッシュファイルを削除中</string>
+ <string name="msg_con_delete_secret">秘密鍵輪のキャッシュファイルを削除中</string>
+ <string name="msg_con_error_db">データベースオープン中のエラー!</string>
+ <string name="msg_con_error_io_public">キャッシュに公開鍵を書く際にI/Oエラー!</string>
+ <string name="msg_con_error_io_secret">キャッシュに秘密鍵を書く際にI/Oエラー!</string>
+ <string name="msg_con_error_public">公開鍵の再インポートのエラー!</string>
+ <string name="msg_con_error_secret">秘密鍵の再インポートのエラー!</string>
+ <plurals name="msg_con_recover">
+ <item quantity="other">%1$d の秘密鍵と %2$d の公開鍵の統合のリカバリー中</item>
+ </plurals>
+ <string name="msg_con_recover_unknown">不明な状態からリカバリー中</string>
+ <plurals name="msg_con_reimport_public">
+ <item quantity="other">%d の公開鍵を再インポート中</item>
+ </plurals>
+ <string name="msg_con_reimport_public_skip">再インポートで公開鍵がありません、スキップします...</string>
+ <plurals name="msg_con_reimport_secret">
+ <item quantity="other">%d の秘密鍵を再インポート中</item>
+ </plurals>
+ <string name="msg_con_reimport_secret_skip">再インポートで秘密鍵がありません、スキップします...</string>
+ <string name="msg_con_warn_delete_public">公開鍵キャッシュファイルの削除例外</string>
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">クリックしてパスフレーズのキャッシュをクリア</string>
<string name="passp_cache_notif_n_keys">OpenKeychainは %d のパスフレーズをキャッシュしています</string>
diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml
index f225e204a..7f93d0d51 100644
--- a/OpenKeychain/src/main/res/values-nl/strings.xml
+++ b/OpenKeychain/src/main/res/values-nl/strings.xml
@@ -71,7 +71,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">Forceer oude OpenPGPv3 Handtekeningen</string>
<string name="label_keyservers">Sleutelservers</string>
<string name="label_key_id">Sleutel-id</string>
<string name="label_creation">Aanmaak</string>
@@ -281,8 +280,6 @@
<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>
- <string name="api_select_pub_keys_missing_text">Geen publieke sleutels zijn gevonden voor deze identiteiten:</string>
- <string name="api_select_pub_keys_dublicates_text">Meer dan een publieke sleutel bestaat voor deze identiteiten:</string>
<string name="api_select_pub_keys_text">Bekijkt u a.u.b. de ontvangers</string>
<string name="api_error_wrong_signature">Handtekening check mislukt! Hebt u deze app van een andere bron geïnstalleerd? Als u zeker weet dat dit geen aanval is, haal dan de registratie van deze app in OpenKeychain weg en registreer de app opnieuw.</string>
<!--Share-->
@@ -334,6 +331,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="section_certifier_id">Certificeer</string>
diff --git a/OpenKeychain/src/main/res/values-pl/strings.xml b/OpenKeychain/src/main/res/values-pl/strings.xml
index a4a66e30c..f96753662 100644
--- a/OpenKeychain/src/main/res/values-pl/strings.xml
+++ b/OpenKeychain/src/main/res/values-pl/strings.xml
@@ -59,7 +59,6 @@
<string name="label_passphrase_cache_ttl">Bufor haseł</string>
<string name="label_message_compression">Kompresja wiadomości</string>
<string name="label_file_compression">Kompresja plików</string>
- <string name="label_force_v3_signature">Wymuś stare podpisy OpenPGPv3</string>
<string name="label_keyservers">Serwery kluczy</string>
<string name="label_key_id">Identyfikator klucza</string>
<string name="label_creation">Utworzenia</string>
@@ -311,6 +310,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="section_cert">Szczegóły certyfikatu</string>
diff --git a/OpenKeychain/src/main/res/values-pt/strings.xml b/OpenKeychain/src/main/res/values-pt/strings.xml
new file mode 100644
index 000000000..9a8c94e31
--- /dev/null
+++ b/OpenKeychain/src/main/res/values-pt/strings.xml
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <!--section-->
+ <!--button-->
+ <!--menu-->
+ <!--label-->
+ <!--choice-->
+ <!--key flags-->
+ <!--sentences-->
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--errors without preceeding Error:-->
+ <!--results shown after decryption/verification-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Import result toast-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Edit key-->
+ <!--Create key-->
+ <!--View key-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+ <!--certs-->
+ <!--Import Public log entries-->
+ <!--Import Secret log entries-->
+ <!--Keyring Canonicalization log entries-->
+ <!--Keyring merging log entries-->
+ <!--createSecretKeyRing-->
+ <!--modifySecretKeyRing-->
+ <!--Consolidate-->
+ <!--PassphraseCache-->
+ <!--unsorted-->
+ <!--First Time-->
+</resources>
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index fd2c0312d..dba0aed12 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -74,7 +74,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">Использовать OpenPGPv3 подписи (устар.)</string>
<string name="label_keyservers">Серверы ключей</string>
<string name="label_key_id">ID ключа</string>
<string name="label_creation">Создан</string>
@@ -238,7 +237,6 @@
<string name="progress_verifying_integrity">проверка целостности...</string>
<string name="progress_deleting_securely">безопасное удаление \'%s\'...</string>
<!--action strings-->
- <string name="hint_public_keys">Имя/Email/ID ключа…</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -304,8 +302,6 @@
<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">Для этих идентификаторов не найдены публичные ключи:</string>
- <string name="api_select_pub_keys_dublicates_text">Для этих идентификаторов найдено более одного публичного ключа: </string>
<string name="api_select_pub_keys_text">Пожалуйста, проверьте получателей!</string>
<string name="api_error_wrong_signature">Проверка подписи пакета не удалась! Если вы установили программу из другого источника, отзовите для неё доступ к этой программе или обновите право доступа.</string>
<!--Share-->
@@ -383,14 +379,13 @@
<string name="msg_mf_error_revoked_primary">Аннулированные идентификаторы не могут быть основными!</string>
<string name="msg_mf_error_pgp">Внутренняя ошибка PGP!</string>
<string name="msg_mf_error_sig">Ошибка подписи!</string>
- <string name="msg_mf_passphrase">Изменение пароля</string>
- <string name="msg_mf_subkey_past_expiry">Срок годности не может быть в прошлом!</string>
<string name="msg_mf_success">Связка успешно изменена</string>
<string name="msg_mf_uid_add">Добавление id %s</string>
<string name="msg_mf_uid_primary">Изменение основного uid на %s</string>
<string name="msg_mf_uid_revoke">Аннулирование id %s</string>
<string name="msg_mf_unlock_error">Ошибка разблокирования связки!</string>
<string name="msg_mf_unlock">Разблокирование связки</string>
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="section_certifier_id">Кем подписан</string>
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 0a7b4713e..a24c1ddf1 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -74,7 +74,6 @@
<string name="label_passphrase_cache_ttl">Hranjenje gesla v spominu</string>
<string name="label_message_compression">Stiskanje sporočil</string>
<string name="label_file_compression">Stiskanje datotek</string>
- <string name="label_force_v3_signature">Vsili stare podpise OpenPGPv3</string>
<string name="label_keyservers">Strežniki</string>
<string name="label_key_id">ID ključa</string>
<string name="label_creation">Ustvarjanje</string>
@@ -243,8 +242,6 @@
<string name="progress_verifying_integrity">preverjam neokrnjenost...</string>
<string name="progress_deleting_securely">varno brišem \'%s\'…</string>
<!--action strings-->
- <string name="hint_public_keys">Ime/e-pošta/ID ključa</string>
- <string name="hint_keybase_search">Ime/Keybase.io uporabniško ime...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -303,8 +300,6 @@
<string name="api_register_allow">Dovoli dostop</string>
<string name="api_register_disallow">Zavrni dostop</string>
<string name="api_register_error_select_key">Izberite ključ!</string>
- <string name="api_select_pub_keys_missing_text">Za te identitete ni bil najden noben javni ključ:</string>
- <string name="api_select_pub_keys_dublicates_text">Za te identitete obstaja več ključev:</string>
<string name="api_select_pub_keys_text">Preverite seznam prejemnikov!</string>
<string name="api_error_wrong_signature">Preverjanje podpisa ni uspelo! Ste namestili to aplikacijo iz drugega vira? Če ste prepričani, da to ni napad, prekličite registracijo te aplikacije v OpenKeychain in jo izvedite znova.</string>
<!--Share-->
@@ -406,6 +401,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="section_certifier_id">Overovitelj</string>
diff --git a/OpenKeychain/src/main/res/values-tr/strings.xml b/OpenKeychain/src/main/res/values-tr/strings.xml
index f8c26f140..f8ef23467 100644
--- a/OpenKeychain/src/main/res/values-tr/strings.xml
+++ b/OpenKeychain/src/main/res/values-tr/strings.xml
@@ -162,6 +162,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<string name="can_sign_not">imzalanamadı</string>
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index 42ac94c32..f1533f4f2 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -1,9 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--title-->
+ <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_add_subkey">Додати підключ</string>
<string name="title_edit_key">Редагувати ключ</string>
<string name="title_preferences">Налаштування</string>
<string name="title_api_registered_apps">Програми</string>
@@ -12,6 +15,7 @@
<string name="title_share_fingerprint_with">Поділитися відбитком із…</string>
<string name="title_share_key">Поділитися ключем з…</string>
<string name="title_share_file">Поширити файл з…</string>
+ <string name="title_share_message">Поширити повідомлення із…</string>
<string name="title_encrypt_to_file">Зашифрувати до файлу</string>
<string name="title_decrypt_to_file">Розшифрувати до файлу</string>
<string name="title_import_keys">Імпортувати ключі</string>
@@ -23,6 +27,7 @@
<string name="title_key_details">Подробиці про ключ</string>
<string name="title_help">Довідка</string>
<string name="title_log_display">Журнал</string>
+ <string name="title_create_key">Створити ключ</string>
<!--section-->
<string name="section_user_ids">Сутності</string>
<string name="section_keys">Підключі</string>
@@ -40,20 +45,27 @@
<string name="btn_decrypt_verify_file">Розшифрувати, перевірити та зберегти файл</string>
<string name="btn_decrypt_verify_message">Розшифрувати і перевірити повідомлення</string>
<string name="btn_encrypt_file">Шифрувати і зберегти файл</string>
+ <string name="btn_encrypt_share_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">Гаразд</string>
<string name="btn_export_to_server">Завантажити на сервер ключів</string>
<string name="btn_next">Далі</string>
<string name="btn_back">Назад</string>
<string name="btn_lookup_key">Шукати ключ</string>
+ <string name="btn_share_encrypted_signed">Зашифрувати і поширити повідомлення</string>
<string name="btn_view_cert_key">Переглянути ключ сертифікації</string>
+ <string name="btn_create_key">Створити ключ</string>
+ <string name="btn_add_files">Додати файл(и)</string>
<!--menu-->
<string name="menu_preferences">Параметри</string>
<string name="menu_help">Довідка</string>
<string name="menu_export_key">Експорт до файлу</string>
<string name="menu_delete_key">Вилучити ключ</string>
+ <string name="menu_create_key">Створити мій ключ</string>
+ <string name="menu_import_existing_key">Імпортувати наявний ключ</string>
<string name="menu_search">Пошук</string>
<string name="menu_beam_preferences">Налаштування променя</string>
<string name="menu_key_edit_cancel">Скасувати</string>
@@ -65,16 +77,27 @@
<!--label-->
<string name="label_message">Повідомлення</string>
<string name="label_file">Файл</string>
+ <string name="label_files">Файл(и)</string>
+ <string name="label_file_colon">Файл:</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">Файл ASCII Armor</string>
+ <string name="label_file_ascii_armor">Файли: ASCII Armor</string>
+ <string name="label_write_version_header">Нехай інші дізнаються, що ви користуєтеся OpenKeychain</string>
+ <string name="label_write_version_header_summary">Напишіть \'OpenKeychain v2.7\' для підписів, зашифрованого тексту та експортованих ключів OpenPGP</string>
+ <string name="label_asymmetric_from">Від:</string>
+ <string name="label_to">Кому:</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_keyservers">Сервери ключів</string>
<string name="label_key_id">ІД ключа</string>
<string name="label_creation">Створення</string>
@@ -155,6 +178,7 @@
<string name="key_deletion_confirmation_multi">Ви справді хочете вилучити усі вибрані відкриті ключі?\nВи не зможете це відмінити!</string>
<string name="secret_key_deletion_confirmation">Ви справді хочете вилучити секретний ключ \'%s\'?\nВи не зможете це відмінити!</string>
<string name="public_key_deletetion_confirmation">Ви справді хочете вилучити відкритий ключ \'%s\'?\nВи не зможете це відмінити!</string>
+ <string name="also_export_secret_keys">Також експортувати секретні ключі</string>
<string name="key_exported">Успішно експортовано 1 ключ.</string>
<string name="keys_exported">Успішно експортовано %d ключів.</string>
<string name="no_keys_exported">Жодного ключа не експортовано.</string>
@@ -194,6 +218,11 @@
<string name="error_jelly_bean_needed">Вам потрібний Android 4.1 для використання функції Androids NFC промінь!</string>
<string name="error_nfc_needed">NFC недоступний на вашому пристрої!</string>
<string name="error_nothing_import">Ключ не знайдено!</string>
+ <string name="error_query_too_short">Надто короткий пошуковий запит. Поліпшіть його!</string>
+ <string name="error_searching_keys">Трапилася помилка при пошуці за ключами.</string>
+ <string name="error_too_many_responses">Запит пошуку ключа видав надто багато варіантів. Уточніть пошуковий запит!</string>
+ <string name="error_too_short_or_too_many_responses">Нема жодного ключа або знайдено надто багато! Поліпшіть свій запит!</string>
+ <string name="error_import_no_valid_keys">Жодного дійсного ключа не знайдено у File/Clipboard!</string>
<string name="error_generic_report_bug">Трапилася загальна помилка, будь ласка, створіть новий звіт про помилку для OpenKeychain.</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">частина завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
@@ -215,8 +244,21 @@
<string name="progress_saving">збереження…</string>
<string name="progress_importing">імпортується…</string>
<string name="progress_exporting">експортується…</string>
+ <string name="progress_uploading">відвантаження…</string>
<string name="progress_building_key">будується ключ…</string>
<string name="progress_building_master_key">побудова основного кільця…</string>
+ <string name="progress_generating_rsa">генерується новий ключ RSA…</string>
+ <string name="progress_generating_dsa">генерується новий ключ DSA…</string>
+ <string name="progress_generating_elgamal">генерується новий ключ ElGamal…</string>
+ <string name="progress_modify">змінюється в\'язка ключів…</string>
+ <string name="progress_modify_unlock">розблоковується в\'язка…</string>
+ <string name="progress_modify_adduid">розблоковуються ID користувачів…</string>
+ <string name="progress_modify_revokeuid">відхилення ІД користувачів…</string>
+ <string name="progress_modify_primaryuid">змінюється ІД первинного користувача…</string>
+ <string name="progress_modify_subkeychange">змінюються підключі…</string>
+ <string name="progress_modify_subkeyrevoke">відхилення підключів…</string>
+ <string name="progress_modify_subkeyadd">додаються підключі…</string>
+ <string name="progress_modify_passphrase">змінюється пароль…</string>
<plurals name="progress_exporting_key">
<item quantity="one">експортується ключ…</item>
<item quantity="few">експортуються ключі…</item>
@@ -232,13 +274,15 @@
<string name="progress_processing_signature">обробляється підпис…</string>
<string name="progress_verifying_signature">перевірка підпису…</string>
<string name="progress_signing">підписання…</string>
+ <string name="progress_certifying">сертифікується…</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>
<!--action strings-->
- <string name="hint_public_keys">Назва/Ел. пошта/ІД ключа…</string>
+ <string name="hint_keyserver_search_hint">Назва/Ел. пошта/ІД ключа…</string>
+ <string name="hint_keybase_search_hint">Назва/Ел.пошта/Доказ/Ключ…</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_768">768</string>
@@ -250,6 +294,7 @@
<string name="key_size_8192">8192</string>
<string name="key_size_custom">Особливий розмір ключа</string>
<string name="key_size_custom_info">Введіть інший розмір ключа (у бітах):</string>
+ <string name="key_size_custom_info_rsa">Довжина ключа RSA має бути більша за 1024 та менша за 16384. Також він має мати кратність 8.</string>
<string name="key_size_custom_info_dsa">Довжина ключа DSA має бути більша за 512 та менша за 1024. Також він має мати кратність 64.</string>
<!--compression-->
<string name="compression_fast">швидке</string>
@@ -277,11 +322,22 @@
<item quantity="few">Успішно імпортовано %1$d ключі.</item>
<item quantity="other">Успішно імпортовано %1$d ключів.</item>
</plurals>
+ <plurals name="import_keys_added_and_updated_2">
+ <item quantity="one">та оновлено ключ%2$s.</item>
+ <item quantity="few">та оновлено %1$d ключі%2$s.</item>
+ <item quantity="other">та оновлено %1$d ключів%2$s.</item>
+ </plurals>
<plurals name="import_keys_added">
<item quantity="one">Успішно імпортований ключ%2$s.</item>
<item quantity="few">Успішно імпортовано %1$d ключі%2$s.</item>
<item quantity="other">Успішно імпортовано %1$d ключів%2$s.</item>
</plurals>
+ <plurals name="import_keys_updated">
+ <item quantity="one">Успішно оновлено ключ%2$s.</item>
+ <item quantity="few">Успішно оновлено %1$d ключі%2$s.</item>
+ <item quantity="other">Успішно оновлено %1$d ключів%2$s.</item>
+ </plurals>
+ <string name="view_log">Переглянути журнал</string>
<string name="import_error_nothing">Нема що імпортувати.</string>
<string name="import_error">Помилка імпорту ключів!</string>
<string name="import_with_warnings">, із застереженнями</string>
@@ -291,6 +347,7 @@
<string name="intent_send_encrypt">Зашифрувати з OpenKeychain</string>
<string name="intent_send_decrypt">Розшифрувати з OpenKeychain</string>
<!--Remote API-->
+ <string name="api_no_apps">Незареєстровані програми!\n\nСписок підтримуваних сторонніх програм можна знайти у Довідці!</string>
<string name="api_settings_show_info">Показати додаткову інформацію</string>
<string name="api_settings_hide_info">Приховати додаткову інформацію</string>
<string name="api_settings_show_advanced">Показати додаткові налаштування</string>
@@ -306,12 +363,17 @@
<string name="api_settings_package_name">Назва пакунку</string>
<string name="api_settings_package_signature">SHA-256 підписку пакунку</string>
<string name="api_settings_accounts">Облікові записи</string>
+ <string name="api_settings_accounts_empty">Немає облікового запису приєднаного до цієї програми.</string>
+ <string name="api_create_account_text">Ця програма вимагає створення нового профілю. Будь ласка, виберіть наявний приватний ключ або створіть інший.\nПрограми обмежені використання ключів, які ви тут оберете!</string>
+ <string name="api_update_account_text">Збережений для цього профілю ключ вже вилучений. Будь ласка, виберіть інший!\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>
- <string name="api_select_pub_keys_missing_text">Немає публічних ключів для цих сутностей:</string>
- <string name="api_select_pub_keys_dublicates_text">Наявно більше одного публічного ключа для цих сутностей:</string>
+ <string name="api_select_pub_keys_missing_text">Не знайдено жодного ключа для цих сутностей:</string>
+ <string name="api_select_pub_keys_dublicates_text">Наявно більше одного ключа для цих сутностей:</string>
<string name="api_select_pub_keys_text">Будь ласка, перевірте список одержувачів!</string>
+ <string name="api_select_pub_keys_text_no_user_ids">Будь ласка, виберіть одержувачів!</string>
<string name="api_error_wrong_signature">Перевірка підпису пакету не вдалася! Може ви встановили програму з іншого джерела? Якщо ви впевнені, що це не атака, то відкличте реєстрацію програми у OpenKeychain та знову зареєструйте її.</string>
<!--Share-->
<string name="share_qr_code_dialog_title">Відправити як штрих-код</string>
@@ -326,19 +388,57 @@
<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_edit">Редагувати ключ</string>
<string name="key_view_action_encrypt">Шифрувати з цим ключем</string>
<string name="key_view_action_certify">Сертифікувати сутності</string>
+ <string name="key_view_action_update">Оновити із сервера ключів</string>
<string name="key_view_action_share_with">Поділитися із…</string>
<string name="key_view_action_share_nfc">Поширити через NFC, тримаючи пристрої пліч-о-пліч</string>
+ <string name="key_view_action_upload">Відвантажити на сервер ключів</string>
<string name="key_view_tab_main">Основна інформація</string>
<string name="key_view_tab_share">Поділитися</string>
<string name="key_view_tab_keys">Підключі</string>
<string name="key_view_tab_certs">Сертифікати</string>
+ <string name="user_id_info_revoked_title">Відхилено</string>
+ <string name="user_id_info_revoked_text">Ця сутність вже відкликана власником ключа. Вона більше не дійсна.</string>
+ <string name="user_id_info_verified_title">Перевірено</string>
+ <string name="user_id_info_verified_text">Не перевірено</string>
+ <string name="user_id_info_not_verified_title">Не перевірено</string>
+ <string name="user_id_info_not_verified_text">Ця сутність ще не перевірена. Ви не можете переконатися, чи сутність справді відповідає вказаній особі.</string>
+ <string name="user_id_info_invalid_title">Недійсна</string>
+ <string name="user_id_info_invalid_text">Щось неправильне у цій сутності!</string>
<!--Edit key-->
+ <string name="edit_key_action_change_passphrase">Змінити пароль</string>
+ <string name="edit_key_action_add_identity">Додати сутність</string>
+ <string name="edit_key_action_add_subkey">Додати підключ</string>
+ <string name="edit_key_edit_user_id_title">Виберіть дію!</string>
+ <string-array name="edit_key_edit_user_id">
+ <item>Змінити на первинну сутність</item>
+ <item>Відкликати сутність</item>
+ </string-array>
+ <string-array name="edit_key_edit_user_id_revert_revocation">
+ <item>Обернути відкликання</item>
+ </string-array>
+ <string name="edit_key_edit_user_id_revoked">Ця сутність вже відкликана. Це не можна скасувати.</string>
+ <string name="edit_key_edit_subkey_title">Виберіть дію!</string>
+ <string-array name="edit_key_edit_subkey">
+ <item>Змінити термін дії</item>
+ <item>Відкликати підключ</item>
+ </string-array>
+ <string name="edit_key_new_subkey">новий</string>
<!--Create key-->
+ <string name="create_key_upload">Відвантажити ключ на сервер ключів</string>
+ <string name="create_key_empty">Це поле - обов\'язкове</string>
+ <string name="create_key_passphrases_not_equal">Паролі фрази не збігаються</string>
+ <string name="create_key_final_text">Ви ввели наступну сутність:</string>
+ <string name="create_key_final_robot_text">Створення ключа може зайняти деякий час, випийте чашечку кави за цей час ...\n(3 підключі, RSA, 4096 біт)</string>
+ <string name="create_key_text">Введіть ваше повне ім\'я, електронну адреса та оберіть парольну фразу.</string>
+ <string name="create_key_hint_full_name">Повне ім\'я, наприклад Степан Бандера</string>
<!--View key-->
+ <string name="view_key_revoked">Цей ключ вже відкликано!</string>
+ <string name="view_key_expired">Термін дії цього ключа вже минув!</string>
<!--Navigation Drawer-->
<string name="nav_keys">Ключі</string>
<string name="nav_encrypt">Підписати і зашифрувати</string>
@@ -348,6 +448,7 @@
<string name="drawer_close">Закрити панель навігації</string>
<string name="my_keys">Мої ключі</string>
<!--hints-->
+ <string name="encrypt_content_edit_text_hint">Введене тут повідомлення буде підписане, використовуючи ключ, вибраний у Звідки та зашифрований для всіх одержувачів, вказаних у Кому.</string>
<string name="decrypt_content_edit_text_hint">Уведіть зашифрований текст тут для його розшифрування та/або перевірки…</string>
<!--certs-->
<string name="cert_default">типово</string>
@@ -355,48 +456,152 @@
<string name="cert_casual">випадковий</string>
<string name="cert_positive">додатний</string>
<string name="cert_revoke">відкликано</string>
+ <string name="cert_verify_ok">Гаразд</string>
<string name="cert_verify_failed">Невдача!</string>
<string name="cert_verify_error">Помилка!</string>
<string name="cert_verify_unavailable">Недоступний ключ</string>
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">Застосовується пакетна операція вставки.</string>
+ <string name="msg_ip_bad_type_secret">Спробували імпортувати секретну в\'язку як публічну. Це вада. Будь ласка, відправте звіт!</string>
+ <string name="msg_kc_v3_key">Цей ключ зроблений OpenPGP версії 3, а тому небезпечний. Його не можна імпортувати.</string>
<string name="msg_ip_delete_old_fail">Нема вилученого старого ключа (створюється новий?)</string>
<string name="msg_ip_delete_old_ok">Вилучений старий ключ з бази даних</string>
<string name="msg_ip_encode_fail">Операція не вдалася через помилку кодування</string>
<string name="msg_ip_fail_io_exc">Операція не вдалася через помилку вводу/виводу</string>
+ <string name="msg_ip_fail_op_exc">Операція не вдалася через помилку бази даних</string>
<string name="msg_ip_fail_remote_ex">Операція не вдалася через внутрішню помилку</string>
+ <string name="msg_ip">Імпортується публічна в\'язка %s</string>
<string name="msg_ip_insert_keyring">Шифруються дані із в\'язки</string>
<string name="msg_ip_insert_keys">Аналізуються ключі</string>
<string name="msg_ip_prepare">Підготовка операцій з базою даних</string>
<string name="msg_ip_master">Обробляється основний ключа %s</string>
+ <string name="msg_ip_master_expired">В\'язка закінчилася %s</string>
+ <string name="msg_ip_master_expires">В\'язка закінчується %s</string>
+ <string name="msg_ip_master_flags_ces">Прапори основного ключа: certify, encrypt, sign</string>
+ <string name="msg_ip_master_flags_cex">Прапори основного ключа: certify, encrypt</string>
+ <string name="msg_ip_master_flags_cxs">Прапори основного ключа: certify, sign</string>
+ <string name="msg_ip_master_flags_xes">Прапори основного ключа: encrypt, sign</string>
+ <string name="msg_ip_master_flags_cxx">Прапори основного ключа: certify</string>
+ <string name="msg_ip_master_flags_xex">Прапори основного ключа: encrypt</string>
+ <string name="msg_ip_master_flags_xxs">Прапори основного ключа: sign</string>
+ <string name="msg_ip_master_flags_xxx">Прапори основного ключа: немає</string>
<string name="msg_ip_subkey">Опрацьовується підключ %s</string>
+ <string name="msg_ip_subkey_expired">Підключ закінчився %s</string>
+ <string name="msg_ip_subkey_expires">Підключ закінчуєтья %s</string>
+ <string name="msg_ip_subkey_flags_ces">Прапори підключів: certify, encrypt, sign</string>
+ <string name="msg_ip_subkey_flags_cex">Прапори підключів: certify, encrypt</string>
+ <string name="msg_ip_subkey_flags_cxs">Прапори підключів: certify, sign</string>
+ <string name="msg_ip_subkey_flags_xes">Прапори підключів: encrypt, sign</string>
+ <string name="msg_ip_subkey_flags_cxx">Прапори підключів: certify</string>
+ <string name="msg_ip_subkey_flags_xex">Прапори підключів: encrypt</string>
+ <string name="msg_ip_subkey_flags_xxs">Прапори підключів: sign</string>
+ <string name="msg_ip_subkey_flags_xxx">Прапори підключів: жодний</string>
<string name="msg_ip_success">Успішно імпортована публічна в\'язка</string>
+ <string name="msg_ip_success_identical">В\'язка не містить нових даних. Нема що робити.</string>
<string name="msg_ip_reinsert_secret">Повторне вставлення секретного ключа</string>
<string name="msg_ip_uid_cert_bad">Виявлено поганий сертифікат!</string>
<string name="msg_ip_uid_cert_error">Помилка опрацювання сертифікату!</string>
+ <string name="msg_ip_uid_cert_good">ІД користувача сертифіковано %1$s</string>
+ <plurals name="msg_ip_uid_certs_unknown">
+ <item quantity="one">Ігнорується один сертифікат виданий невідомим відкритим ключем</item>
+ <item quantity="few">Ігнорується %s сертифікати, виданих невідомими відкритими ключами</item>
+ <item quantity="other">Ігнорується %s сертифікатів, виданих невідомими відкритими ключами</item>
+ </plurals>
+ <string name="msg_ip_uid_classifying_zero">Класифікуються ІД користувача (нема доступних надійних ключів)</string>
+ <plurals name="msg_ip_uid_classifying">
+ <item quantity="one">Класифікуються ІД користувача (за допомогою одного надійного ключа)</item>
+ <item quantity="few">Класифікуються ІД користувача (за допомогою %s надійних ключів)</item>
+ <item quantity="other">Класифікуються ІД користувача (за допомогою %s надійних ключів)</item>
+ </plurals>
+ <string name="msg_ip_uid_reorder">Перевпорядкування ІД користувачів</string>
<string name="msg_ip_uid_processing">Обробляється ІД користувача %s</string>
+ <string name="msg_ip_uid_revoked">ІД користувача відхилене</string>
+ <string name="msg_is_bad_type_public">Спробували імпортувати публічну в\'язку як секретну. Це вада. Будь ласка, відправте звіт!</string>
+ <string name="msg_is_bad_type_uncanon">Спробували імпортувати в\'язку без канонізації. Це вада. Будь ласка, відправте звіт!</string>
<!--Import Secret log entries-->
<string name="msg_is">Імпортується секретний ключ %s</string>
<string name="msg_is_db_exception">Помилка бази даних!</string>
<string name="msg_is_importing_subkeys">Опрацьовуються секретні підключі</string>
<string name="msg_is_io_exc">Помилка шифрування в’язки</string>
+ <string name="msg_is_pubring_generate">Генерується публічна в\'язка із секретної</string>
<string name="msg_is_subkey_nonexistent">Підключ %s недоступний у публічному ключі</string>
<string name="msg_is_subkey_ok">Позначено %s як доступно</string>
+ <string name="msg_is_success_identical">В\'язка не містить нових даних. Нема що робити.</string>
<string name="msg_is_success">Успішно імпортована секретна в\'язка</string>
<!--Keyring Canonicalization log entries-->
+ <string name="msg_kc_public">Канонізація публічної в\'язки %s</string>
+ <string name="msg_kc_secret">Канонізація секретної в\'язки %s</string>
+ <string name="msg_kc_fatal_no_uid">Невдала канонізація в\'язки: в\'язка не має дійсних ІД користувача</string>
<string name="msg_kc_master">Обробляється основний ключ…</string>
<string name="msg_kc_sub">Опрацьовується підключ %s</string>
+ <string name="msg_kc_sub_bad_type">Тип сертифікату невідомого ключа: %s</string>
+ <string name="msg_kc_sub_no_cert">Не знайдено дійсного сертифікату для %s, вилучення із кільця</string>
+ <string name="msg_kc_success">Успішна канонізація в\'язки, без змін</string>
+ <plurals name="msg_kc_success_bad">
+ <item quantity="one">Успішна канонізація в\'язки, вилучено один хибний сертифікат</item>
+ <item quantity="few">Успішна канонізація в\'язки, вилучено %d хибні сертифікати</item>
+ <item quantity="other">Успішна канонізація в\'язки, вилучено %d хибних сертифікатів</item>
+ </plurals>
+ <string name="msg_kc_success_bad_and_red">Успішна канонізація в\'язки, вилучено %1$s хибних та %2$s надлишкових сертифікатів</string>
+ <plurals name="msg_kc_success_redundant">
+ <item quantity="one">Успішна канонізація в\'язки, вилучено один надлишковий сертифікат</item>
+ <item quantity="few">Успішна канонізація в\'язки, вилучено %d надлишкові сертифікати</item>
+ <item quantity="other">Успішна канонізація в\'язки, вилучено %d надлишкових сертифікатів</item>
+ </plurals>
+ <string name="msg_kc_uid_remove">Вилучення недійсного ІД користувача %s</string>
<!--Keyring merging log entries-->
+ <string name="msg_mg_public">Злиття у публічну в\'язку %s</string>
+ <string name="msg_mg_secret">Злиття у секретну в\'язку %s</string>
+ <string name="msg_mg_error_encode">Фатальна помилка шифрування підпису</string>
+ <string name="msg_mg_error_heterogeneous">Спробували злити в\'язки із різними відбитками!</string>
<string name="msg_mg_new_subkey">Додається новий підключ %s</string>
+ <string name="msg_mg_found_new">Знайдено %s нових сертифікатів у в\'язці</string>
+ <string name="msg_mg_unchanged">Немає нових сертифікатів</string>
<!--createSecretKeyRing-->
+ <string name="msg_cr">Генерується новий основний ключ</string>
+ <string name="msg_cr_error_no_master">Не вказано параметрів основного ключа!</string>
+ <string name="msg_cr_error_no_user_id">В\'язка мусить бути створеною хоча б одним ІД користувача!</string>
+ <string name="msg_cr_error_no_certify">Основний ключ повинен мати прапорець certify!</string>
+ <string name="msg_cr_error_keysize_512">Розмір ключа має бути більшим або рівним 512!</string>
+ <string name="msg_cr_error_internal_pgp">Внутрішня помилка PGP!</string>
+ <string name="msg_cr_error_unknown_algo">Поганий вибір алгоритму!</string>
+ <string name="msg_cr_error_master_elgamal">Основний ключ не може бути ключем ElGamal!</string>
<!--modifySecretKeyRing-->
+ <string name="msg_mr">Змінюється в\'язка %s</string>
+ <string name="msg_mf_error_encode">Виняток шифрування!</string>
+ <string name="msg_mf_error_fingerprint">Дійсний відбиток ключа не зібгається з очікуваним!</string>
+ <string name="msg_mf_error_keyid">Немає ІД ключа. Це внутрішня помилка! Будь ласка, надішліть звіт про ваду!</string>
<string name="msg_mf_error_integrity">Внутрішня помилка - збій перевірки цілісності!</string>
+ <string name="msg_mf_error_master_none">Не знайдено основного сертифікату для операцій! (Усе відкликано?)</string>
+ <string name="msg_mf_error_noexist_primary">Вказаний поганий ІД первинного користувача!</string>
+ <string name="msg_mf_error_noexist_revoke">Вказаний поганий ІД первинного користувача!</string>
<string name="msg_mf_error_revoked_primary">ІД відхилених користувачів не може бути первинним!</string>
<string name="msg_mf_error_pgp">Внутрішній виняток PGP!</string>
- <string name="msg_mf_passphrase">Змінюється парольна фраза</string>
+ <string name="msg_mf_error_sig">Виняток підпису!</string>
+ <string name="msg_mf_master">Змінюються основі сертифікації</string>
+ <string name="msg_mf_primary_replace_old">Замінюється сертифікат ІД попереднього первинного користувача</string>
+ <string name="msg_mf_primary_new">Генерується новий сертифікат для ІД нового первинного користувача</string>
+ <string name="msg_mf_subkey_change">Змінюється підключ %s</string>
+ <string name="msg_mf_error_subkey_missing">Спробували працювати із втраченим підключем %s!</string>
+ <string name="msg_mf_subkey_new_id">Новий ід підключа: %s</string>
+ <string name="msg_mf_error_past_expiry">Дата завершення дії не може бути у минулому!</string>
+ <string name="msg_mf_subkey_revoke">Відкликається підключ %s</string>
+ <string name="msg_mf_success">Успішно модифіковано в\'язку</string>
+ <string name="msg_mf_uid_add">Додається ід користувача %s</string>
+ <string name="msg_mf_uid_primary">Змінюється первинне uid на %s</string>
+ <string name="msg_mf_uid_revoke">Відхилення ІД користувача %s</string>
+ <string name="msg_mf_uid_error_empty">ІД користувача не повинно бути порожнім!</string>
+ <string name="msg_mf_unlock_error">Помилка розблокування в\'язки!</string>
<string name="msg_mf_unlock">Розблоковується в\'язка</string>
+ <!--Consolidate-->
<!--PassphraseCache-->
+ <string name="passp_cache_notif_click_to_clear">Клацніть для очищення кешованих парольних фраз</string>
+ <string name="passp_cache_notif_n_keys">OpenKeychain має %d кешованих парольних фраз</string>
+ <string name="passp_cache_notif_keys">Кешовані парольні фрази:</string>
+ <string name="passp_cache_notif_clear">Очистити кеш</string>
+ <string name="passp_cache_notif_pwd">Пароль</string>
<!--unsorted-->
+ <string name="internal_error">Внутрішня помилка!</string>
<string name="section_certifier_id">Ким підписаний</string>
<string name="section_cert">Дані сертифікату</string>
<string name="label_user_id">Сутність</string>
@@ -409,6 +614,7 @@
<string name="error_key_not_found">Ключ не знайдено!</string>
<string name="error_key_processing">Помилка опрацювання ключа!</string>
<string name="key_stripped">голий</string>
+ <string name="secret_cannot_multiple">Ваші власні ключі можна вилучити лише окремо!</string>
<string name="title_view_cert">Переглянути дані сертифікату</string>
<string name="unknown_algorithm">невідомий</string>
<string name="can_sign_not">не можна підписати</string>
@@ -416,4 +622,8 @@
<string name="info_no_manual_account_creation">Вручну не створюються профілі OpenKeychain.\nЗа подробицями дивіться Довідку.</string>
<string name="contact_show_key">Показати ключ (%s)</string>
<!--First Time-->
+ <string name="first_time_text1">Заберіть вашу приватність із OpenKeychain!</string>
+ <string name="first_time_create_key">Створити мій ключ</string>
+ <string name="first_time_import_key">Імпортувати наявний ключ</string>
+ <string name="first_time_skip">Пропустити установку</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-zh/strings.xml b/OpenKeychain/src/main/res/values-zh/strings.xml
index 8e5d42bb7..9d0848c07 100644
--- a/OpenKeychain/src/main/res/values-zh/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh/strings.xml
@@ -144,6 +144,7 @@
<!--Keyring merging log entries-->
<!--createSecretKeyRing-->
<!--modifySecretKeyRing-->
+ <!--Consolidate-->
<!--PassphraseCache-->
<!--unsorted-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values/attr.xml b/OpenKeychain/src/main/res/values/attr.xml
index 86622b3e0..5dfa03987 100644
--- a/OpenKeychain/src/main/res/values/attr.xml
+++ b/OpenKeychain/src/main/res/values/attr.xml
@@ -4,8 +4,6 @@
<declare-styleable name="FoldableLinearLayout">
<attr name="foldedLabel" format="string" />
<attr name="unFoldedLabel" format="string" />
- <attr name="foldedIcon" format="string" />
- <attr name="unFoldedIcon" format="string" />
</declare-styleable>
</resources> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 09a434d5d..d31a08081 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -109,6 +109,7 @@
<string name="label_expiry">Expiry</string>
<string name="label_usage">Usage</string>
<string name="label_key_size">Key Size</string>
+ <string name="label_ecc_curve">Elliptic Curve</string>
<string name="label_main_user_id">Primary identity</string>
<string name="label_name">Name</string>
<string name="label_comment">Comment</string>
@@ -156,6 +157,8 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
+ <string name="ecdh">ECDH</string>
+ <string name="ecdsa">ECDSA</string>
<string name="filemanager_title_open">Open…</string>
<string name="warning">Warning</string>
<string name="error">Error</string>
@@ -268,6 +271,8 @@
<string name="progress_generating_rsa">generating new RSA key…</string>
<string name="progress_generating_dsa">generating new DSA key…</string>
<string name="progress_generating_elgamal">generating new ElGamal key…</string>
+ <string name="progress_generating_ecdsa">generating new ECDSA key…</string>
+ <string name="progress_generating_ecdh">generating new ECDH key…</string>
<string name="progress_modify">modifying keyring…</string>
@@ -301,10 +306,14 @@
<string name="progress_decompressing_data">decompressing data…</string>
<string name="progress_verifying_integrity">verifying integrity…</string>
<string name="progress_deleting_securely">deleting \'%s\' securely…</string>
+ <string name="progress_deleting">deleting keys…</string>
+
+ <string name="progress_con_saving">consolidate: saving to cache…</string>
+ <string name="progress_con_reimport">consolidate: reimporting…</string>
<!-- action strings -->
- <string name="hint_public_keys">Name/Email/Key ID…</string>
- <string name="hint_keybase_search">Name/Keybase.io username…</string>
+ <string name="hint_keyserver_search_hint">Name/Email/Key ID…</string>
+ <string name="hint_keybase_search_hint">Name/Email/Proof/Key…</string>
<!-- key bit length selections -->
<string name="key_size_512">512</string>
@@ -320,6 +329,16 @@
<string name="key_size_custom_info_rsa">RSA key length must be greater than 1024 and at most 16384. Also it must be multiplicity of 8.</string>
<string name="key_size_custom_info_dsa">DSA key length must be at least 512 and at most 1024. Also it must be multiplicity of 64.</string>
+ <!-- elliptic curve names -->
+ <string name="key_curve_nist_p256">NIST P-256</string>
+ <string name="key_curve_nist_p384">NIST P-384</string>
+ <string name="key_curve_nist_p521">NIST P-521</string>
+ <!-- not in for now, see SaveKeyringParcel
+ <string name="key_curve_bp_p256">Brainpool P-256</string>
+ <string name="key_curve_bp_p384">Brainpool P-384</string>
+ <string name="key_curve_bp_p512">Brainpool P-512</string>
+ -->
+
<!-- compression -->
<string name="compression_fast">fast</string>
<string name="compression_very_slow">very slow</string>
@@ -395,9 +414,10 @@
<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 identities:</string>
- <string name="api_select_pub_keys_dublicates_text">More than one public key exist for these identities:</string>
+ <string name="api_select_pub_keys_missing_text">No keys were found for these identities:</string>
+ <string name="api_select_pub_keys_dublicates_text">More than one key exist for these identities:</string>
<string name="api_select_pub_keys_text">Please review the list of recipients!</string>
+ <string name="api_select_pub_keys_text_no_user_ids">Please select the 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 OpenKeychain and then register the app again.</string>
<!-- Share -->
@@ -433,7 +453,7 @@
<string name="user_id_info_verified_title">Verified</string>
<string name="user_id_info_verified_text">This identity has been verified.</string>
<string name="user_id_info_not_verified_title">Not verified</string>
- <string name="user_id_info_not_verified_text">This identity has not been verified yet. You can not be sure if the identity really corresponds to a specific person.</string>
+ <string name="user_id_info_not_verified_text">This identity has not been verified yet. You cannot be sure if the identity really corresponds to a specific person.</string>
<string name="user_id_info_invalid_title">Invalid</string>
<string name="user_id_info_invalid_text">Something is wrong with this identity!</string>
@@ -456,6 +476,7 @@
<item>Revoke Subkey</item>
</string-array>
<string name="edit_key_new_subkey">new</string>
+ <string name="edit_key_select_flag">Please select at least one flag!</string>
<!-- Create key -->
<string name="create_key_upload">Upload key to keyserver</string>
@@ -494,9 +515,12 @@
<string name="cert_verify_error">error!</string>
<string name="cert_verify_unavailable">key unavailable</string>
+ <!-- LogType log messages. Errors should have _ERROR_ in their name and end with a ! -->
+
<!-- Import Public log entries -->
<string name="msg_ip_apply_batch">Applying insert batch operation.</string>
<string name="msg_ip_bad_type_secret">Tried to import secret keyring as public. This is a bug, please file a report!</string>
+ <string name="msg_kc_v3_key">This key is an OpenPGP version 3 key and thus insecure. It has not been imported.</string>
<string name="msg_ip_delete_old_fail">No old key deleted (creating a new one?)</string>
<string name="msg_ip_delete_old_ok">Deleted old key from database</string>
<string name="msg_ip_encode_fail">Operation failed due to encoding error</string>
@@ -604,18 +628,20 @@
<string name="msg_kc_uid_bad_time">Removing user id with future timestamp</string>
<string name="msg_kc_uid_bad_type">Removing user id certificate of unknown type (%s)</string>
<string name="msg_kc_uid_bad">Removing bad self certificate for user id "%s"</string>
- <string name="msg_kc_uid_dup">Removing outdated self certificate for user id "%s"</string>
+ <string name="msg_kc_uid_cert_dup">Removing outdated self certificate for user id "%s"</string>
<string name="msg_kc_uid_foreign">Removing foreign user id certificate by %s</string>
<string name="msg_kc_uid_revoke_dup">Removing redundant revocation certificate for user id "%s"</string>
<string name="msg_kc_uid_revoke_old">Removing outdated revocation certificate for user id "%s"</string>
<string name="msg_kc_uid_no_cert">No valid self-certificate found for user id %s, removing from ring</string>
<string name="msg_kc_uid_remove">Removing invalid user id %s</string>
+ <string name="msg_kc_uid_dup">Removing duplicate user id "%s". The secret key contained two of them. This may result in missing certifications!</string>
<!-- Keyring merging log entries -->
+ <string name="msg_mg_error_secret_dummy">New public subkey found, but secret subkey dummy generation is not supported!</string>
+ <string name="msg_mg_error_heterogeneous">Tried to merge keyrings with differing fingerprints!</string>
+ <string name="msg_mg_error_encode">Fatal error encoding signature!</string>
<string name="msg_mg_public">Merging into public keyring %s</string>
<string name="msg_mg_secret">Merging into secret keyring %s</string>
- <string name="msg_mg_fatal_encode">Fatal error encoding signature</string>
- <string name="msg_mg_heterogeneous">Tried to consolidate heterogeneous keyrings</string>
<string name="msg_mg_new_subkey">Adding new subkey %s</string>
<string name="msg_mg_found_new">Found %s new certificates in keyring</string>
<string name="msg_mg_unchanged">No new certificates</string>
@@ -625,10 +651,16 @@
<string name="msg_cr_error_no_master">No master key options specified!</string>
<string name="msg_cr_error_no_user_id">Keyrings must be created with at least one user id!</string>
<string name="msg_cr_error_no_certify">Master key must have certify flag!</string>
+ <string name="msg_cr_error_null_expiry">Expiry time cannot be "same as before" on key creation. This is a programming error, please file a bug report!</string>
<string name="msg_cr_error_keysize_512">Key size must be greater or equal 512!</string>
+ <string name="msg_cr_error_no_curve">No key size specified! This is a programming error, please file a bug report!</string>
+ <string name="msg_cr_error_no_keysize">No elliptic curve specified! This is a programming error, please file a bug report!</string>
<string name="msg_cr_error_internal_pgp">Internal PGP error!</string>
- <string name="msg_cr_error_unknown_algo">Bad algorithm choice!</string>
- <string name="msg_cr_error_master_elgamal">Master key must not be of type ElGamal!</string>
+ <string name="msg_cr_error_unknown_algo">Unknown algorithm selected! This is a programming error, please file a bug report!</string>
+ <string name="msg_cr_error_flags_dsa">Bad key flags selected, DSA cannot be used for encryption!</string>
+ <string name="msg_cr_error_flags_elgamal">Bad key flags selected, ElGamal cannot be used for signing!</string>
+ <string name="msg_cr_error_flags_ecdsa">Bad key flags selected, ECDSA cannot be used for encryption!</string>
+ <string name="msg_cr_error_flags_ecdh">Bad key flags selected, ECDH cannot be used for signing!</string>
<!-- modifySecretKeyRing -->
<string name="msg_mr">Modifying keyring %s</string>
@@ -636,18 +668,26 @@
<string name="msg_mf_error_fingerprint">Actual key fingerprint does not match the expected one!</string>
<string name="msg_mf_error_keyid">No key ID. This is an internal error, please file a bug report!</string>
<string name="msg_mf_error_integrity">Internal error, integrity check failed!</string>
+ <string name="msg_mf_error_master_none">No master certificate found to operate on! (All revoked?)</string>
<string name="msg_mf_error_noexist_primary">Bad primary user id specified!</string>
+ <string name="msg_mf_error_noexist_revoke">Bad user id for revocation specified!</string>
<string name="msg_mf_error_revoked_primary">Revoked user ids cannot be primary!</string>
+ <string name="msg_mf_error_null_expiry">Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!</string>
+ <string name="msg_mf_error_passphrase_master">Fatal error decrypting master key! This is likely a programming error, please file a bug report!</string>
<string name="msg_mf_error_pgp">PGP internal exception!</string>
<string name="msg_mf_error_sig">Signature exception!</string>
- <string name="msg_mf_passphrase">Changing passphrase</string>
+ <string name="msg_mf_master">Modifying master certifications</string>
+ <string name="msg_mf_passphrase">Changing passphrase for keyring…</string>
+ <string name="msg_mf_passphrase_key">Re-encrypting subkey %s with new passphrase</string>
+ <string name="msg_mf_passphrase_empty_retry">Setting new passphrase failed, trying again with empty old passphrase</string>
+ <string name="msg_mf_passphrase_fail">Passphrase for subkey could not be changed! (Does it have a different one from the other keys?)</string>
<string name="msg_mf_primary_replace_old">Replacing certificate of previous primary user id</string>
<string name="msg_mf_primary_new">Generating new certificate for new primary user id</string>
<string name="msg_mf_subkey_change">Modifying subkey %s</string>
- <string name="msg_mf_subkey_missing">Tried to operate on missing subkey %s!</string>
- <string name="msg_mf_subkey_new">Generating new %1$s bit %2$s subkey</string>
+ <string name="msg_mf_error_subkey_missing">Tried to operate on missing subkey %s!</string>
+ <string name="msg_mf_subkey_new">Adding new subkey of type %s</string>
<string name="msg_mf_subkey_new_id">New subkey ID: %s</string>
- <string name="msg_mf_subkey_past_expiry">Expiry date cannot be in the past!</string>
+ <string name="msg_mf_error_past_expiry">Expiry date cannot be in the past!</string>
<string name="msg_mf_subkey_revoke">Revoking subkey %s</string>
<string name="msg_mf_success">Keyring successfully modified</string>
<string name="msg_mf_uid_add">Adding user id %s</string>
@@ -657,6 +697,41 @@
<string name="msg_mf_unlock_error">Error unlocking keyring!</string>
<string name="msg_mf_unlock">Unlocking keyring</string>
+ <!-- Consolidate -->
+ <string name="msg_con">Consolidating database</string>
+ <string name="msg_con_error_bad_state">Consolidation was started while no database was cached! This is probably a programming error, please file a bug report.</string>
+ <string name="msg_con_error_concurrent">Consolidation aborted, already running on other thread!</string>
+ <string name="msg_con_save_secret">Saving secret keyrings</string>
+ <string name="msg_con_save_public">Saving public keyrings</string>
+ <string name="msg_con_db_clear">Clearing database</string>
+ <string name="msg_con_success">Successfully consolidated database</string>
+ <string name="msg_con_critical_in">Entering critical phase</string>
+ <string name="msg_con_critical_out">Leaving critical phase</string>
+ <string name="msg_con_delete_public">Deleting public keyring cache file</string>
+ <string name="msg_con_delete_secret">Deleting secret keyring cache file</string>
+ <string name="msg_con_error_db">Error opening database!</string>
+ <string name="msg_con_error_io_public">IO error writing public keys to cache!</string>
+ <string name="msg_con_error_io_secret">IO error writing secret keys to cache!</string>
+ <string name="msg_con_error_public">Error reimporting public keys!</string>
+ <string name="msg_con_error_secret">Error reimporting secret keys!</string>
+ <plurals name="msg_con_recover">
+ <item quantity="one">Recovering consolidation with %1$d secret and %2$d public keys</item>
+ <item quantity="other">Recovering consolidation with %1$d secret and %2$d public keys</item>
+ </plurals>
+ <string name="msg_con_recover_unknown">Recovering from unknown state</string>
+ <plurals name="msg_con_reimport_public">
+ <item quantity="one">Reimporting one public key</item>
+ <item quantity="other">Reimporting %d public keys</item>
+ </plurals>
+ <string name="msg_con_reimport_public_skip">No public keys to reimport, skipping…</string>
+ <plurals name="msg_con_reimport_secret">
+ <item quantity="one">Reimporting one secret key</item>
+ <item quantity="other">Reimporting %d secret keys</item>
+ </plurals>
+ <string name="msg_con_reimport_secret_skip">No secret keys to reimport, skipping…</string>
+ <string name="msg_con_warn_delete_public">Exception deleting public cache file</string>
+ <string name="msg_con_warn_delete_secret">Exception deleting secret cache file</string>
+
<!-- PassphraseCache -->
<string name="passp_cache_notif_click_to_clear">Click to clear cached passphrases</string>
<string name="passp_cache_notif_n_keys">OpenKeychain has cached %d passphrases</string>
@@ -671,6 +746,7 @@
<string name="label_user_id">Identity</string>
<string name="unknown_uid">&lt;unknown&gt;</string>
<string name="empty_certs">No certificates for this key</string>
+ <string name="certs_text">Only self-certificates and certificates created with your keys are displayed here.</string>
<string name="section_uids_to_certify">Identities to certify</string>
<string name="label_revocation">Revocation Reason</string>
<string name="label_verify_status">Verification Status</string>
diff --git a/OpenKeychain/src/main/res/xml/account_desc.xml b/OpenKeychain/src/main/res/xml/account_desc.xml
index a6989e9ef..d29395202 100644
--- a/OpenKeychain/src/main/res/xml/account_desc.xml
+++ b/OpenKeychain/src/main/res/xml/account_desc.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="org.sufficientlysecure.keychain"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"/>
+ android:accountType="org.sufficientlysecure.keychain.account"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" />
diff --git a/OpenKeychain/src/main/res/xml/adv_preferences.xml b/OpenKeychain/src/main/res/xml/adv_preferences.xml
index 49f241ffe..02fa4ec40 100644
--- a/OpenKeychain/src/main/res/xml/adv_preferences.xml
+++ b/OpenKeychain/src/main/res/xml/adv_preferences.xml
@@ -1,20 +1,3 @@
-<!--
- Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
-
- 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/>.
--->
-
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/section_defaults">
<org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
diff --git a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml b/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
index 5f5f2be80..39dd8bc91 100644
--- a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
+++ b/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
- <ContactsDataKind android:mimeType="vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key"
- android:detailColumn="data1"/>
+ <ContactsDataKind
+ android:mimeType="vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key"
+ android:detailColumn="data1" />
</ContactsSource> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/xml/gen_preferences.xml b/OpenKeychain/src/main/res/xml/gen_preferences.xml
index 10be61b6a..fd3c6c31a 100644
--- a/OpenKeychain/src/main/res/xml/gen_preferences.xml
+++ b/OpenKeychain/src/main/res/xml/gen_preferences.xml
@@ -1,22 +1,5 @@
-<!--
- Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
-
- 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/>.
--->
-
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <PreferenceCategory android:title="@string/section_general" >
+ <PreferenceCategory android:title="@string/section_general">
<org.sufficientlysecure.keychain.ui.widget.IntegerListPreference
android:entries="@array/passphrase_cache_ttl_entries"
android:entryValues="@array/passphrase_cache_ttl_values"
diff --git a/OpenKeychain/src/main/res/xml/preference_headers.xml b/OpenKeychain/src/main/res/xml/preference_headers.xml
index 49c8b7634..e6b68507a 100644
--- a/OpenKeychain/src/main/res/xml/preference_headers.xml
+++ b/OpenKeychain/src/main/res/xml/preference_headers.xml
@@ -1,20 +1,3 @@
-<!--
- Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
-
- 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/>.
--->
-
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="org.sufficientlysecure.keychain.ui.PreferencesActivity$GeneralPrefsFragment"
diff --git a/OpenKeychain/src/main/res/xml/preference_headers_legacy.xml b/OpenKeychain/src/main/res/xml/preference_headers_legacy.xml
index 295b44863..47b0a0920 100644
--- a/OpenKeychain/src/main/res/xml/preference_headers_legacy.xml
+++ b/OpenKeychain/src/main/res/xml/preference_headers_legacy.xml
@@ -1,20 +1,3 @@
-<!--
- Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
-
- 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/>.
--->
-
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:title="@string/section_general" >
diff --git a/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml b/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml
index d8fe60e91..6871e1a5d 100644
--- a/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml
+++ b/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
- android:contentAuthority="com.android.contacts"
- android:accountType="org.sufficientlysecure.keychain"
- android:supportsUploading="false"
- android:userVisible="true"/> \ No newline at end of file
+ android:contentAuthority="com.android.contacts"
+ android:accountType="org.sufficientlysecure.keychain.account"
+ android:supportsUploading="false"
+ android:userVisible="true"
+ android:allowParallelSyncs="false"
+ android:isAlwaysSyncable="true" /> \ No newline at end of file
diff --git a/README.md b/README.md
index 4b8f23063..7338f1071 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,6 @@ For a more detailed description and installation instructions go to http://www.o
### Travis CI Build Status
-Currently, some tests could fail even when everything is okay!
-
[![Build Status](https://travis-ci.org/open-keychain/open-keychain.png?branch=master)](https://travis-ci.org/open-keychain/open-keychain)
## How to help the project?
@@ -107,6 +105,7 @@ see
* Tests in https://github.com/bcgit/bc-java/tree/master/pg/src/test/java/org/bouncycastle/openpgp/test
* Examples in https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples
* Mailinglist Archive at http://bouncy-castle.1462172.n4.nabble.com/Bouncy-Castle-Dev-f1462173.html
+* Commit changelog of pg subpackage: https://github.com/bcgit/bc-java/commits/master/pg
## Notes
diff --git a/Resources/graphics/function.png b/Resources/graphics/function.png
new file mode 100644
index 000000000..9b8983c48
--- /dev/null
+++ b/Resources/graphics/function.png
Binary files differ
diff --git a/Resources/graphics/function.svg b/Resources/graphics/function.svg
new file mode 100644
index 000000000..97bc936ba
--- /dev/null
+++ b/Resources/graphics/function.svg
@@ -0,0 +1,4042 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="500"
+ id="svg2"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:version="0.32"
+ width="1024"
+ version="1.1"
+ sodipodi:docname="function.svg"
+ inkscape:export-filename="/home/schuerm/Projekte/OpenKeychain/Resources/graphics/function.png">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4335">
+ <stop
+ id="stop4337"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ <stop
+ id="stop4339"
+ offset="0.24114749"
+ style="stop-color:#ffffff;stop-opacity:0.71428573;" />
+ <stop
+ id="stop4341"
+ offset="0.88415229"
+ style="stop-color:#ffffff;stop-opacity:0.28078818;" />
+ <stop
+ id="stop4343"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3906">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="0"
+ id="stop3908" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0.3588765"
+ id="stop3910" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.43333334;"
+ offset="0.88415229"
+ id="stop3912" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3914" />
+ </linearGradient>
+ <marker
+ inkscape:stockid="Tail"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Tail"
+ style="overflow:visible">
+ <g
+ id="g4692"
+ transform="scale(-1.2,-1.2)">
+ <path
+ id="path4694"
+ d="M -3.8048674,-3.9585227 0.54352094,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path4696"
+ d="M -1.2866832,-3.9585227 3.0617053,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path4698"
+ d="M 1.3053582,-3.9585227 5.6537466,0"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path4700"
+ d="M -3.8048674,4.1775838 0.54352094,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path4702"
+ d="M -1.2866832,4.1775838 3.0617053,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path4704"
+ d="M 1.3053582,4.1775838 5.6537466,0.21974226"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </marker>
+ <linearGradient
+ id="linearGradient4263">
+ <stop
+ style="stop-color:#bfbfbf;stop-opacity:1;"
+ offset="0"
+ id="stop4265" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop4267" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4158">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop4160" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop4162" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3177">
+ <stop
+ id="stop3187"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ <stop
+ id="stop3200"
+ offset="0.4375"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3191"
+ offset="0.9375"
+ style="stop-color:#ffffff;stop-opacity:0.43333334;" />
+ <stop
+ id="stop3181"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3167">
+ <stop
+ id="stop3169"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <inkscape:perspective
+ id="perspective10"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3167"
+ id="linearGradient3341"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.08737273,0,0,0.08134103,83.682183,966.62592)"
+ x1="337.49271"
+ y1="402.10623"
+ x2="416.38455"
+ y2="645.40979" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3177"
+ id="linearGradient3345"
+ gradientUnits="userSpaceOnUse"
+ x1="356.35681"
+ y1="164.76173"
+ x2="425.96066"
+ y2="646.65405"
+ gradientTransform="matrix(0.08334585,0,0,0.08334585,2.6106401,974.71004)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4263"
+ id="radialGradient4275"
+ cx="33.772423"
+ cy="40.636124"
+ fx="33.772423"
+ fy="40.636124"
+ r="17.497915"
+ gradientTransform="matrix(1,0,0,0.90369811,0,3.9133352)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3167-7"
+ id="linearGradient4134-4"
+ x1="27.397436"
+ y1="1036.7725"
+ x2="55.474358"
+ y2="1036.7725"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,82.871795,2073.5448)" />
+ <linearGradient
+ id="linearGradient3167-7">
+ <stop
+ id="stop3169-0"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171-1"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3167-2"
+ id="linearGradient4134-1"
+ x1="27.397436"
+ y1="1036.7725"
+ x2="55.474358"
+ y2="1036.7725"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,88.205128,2064.1089)" />
+ <linearGradient
+ id="linearGradient3167-2">
+ <stop
+ id="stop3169-5"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171-3"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3167-0"
+ id="linearGradient4134-49"
+ x1="27.397436"
+ y1="1036.7725"
+ x2="55.474358"
+ y2="1036.7725"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,88.205128,2064.1089)" />
+ <linearGradient
+ id="linearGradient3167-0">
+ <stop
+ id="stop3169-1"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171-5"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="1036.7725"
+ x2="55.474358"
+ y1="1036.7725"
+ x1="27.397436"
+ gradientTransform="matrix(-0.56645172,0,0,-0.56645172,86.718419,1593.9001)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4185-1"
+ xlink:href="#linearGradient3167-2-0"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3167-2-0">
+ <stop
+ id="stop3169-5-6"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171-3-4"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3167-74"
+ id="linearGradient4134-5"
+ x1="27.397436"
+ y1="1036.7725"
+ x2="55.474358"
+ y2="1036.7725"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,88.205128,2064.1089)" />
+ <linearGradient
+ id="linearGradient3167-74">
+ <stop
+ id="stop3169-3"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3171-6"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3906-0"
+ id="linearGradient4291-4"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.06012367,0,0,0.06012367,34.965627,929.74274)"
+ x1="266.69391"
+ y1="164.76173"
+ x2="414.93436"
+ y2="619.08826" />
+ <linearGradient
+ id="linearGradient3906-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="0"
+ id="stop3908-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.71428573;"
+ offset="0.3588765"
+ id="stop3910-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.28078818;"
+ offset="0.88415229"
+ id="stop3912-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3914-6" />
+ </linearGradient>
+ <linearGradient
+ y2="619.08826"
+ x2="414.93436"
+ y1="-195.23424"
+ x1="282.12228"
+ gradientTransform="matrix(0.77806845,0,0,0.77806845,-38.502093,494.05939)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4312"
+ xlink:href="#linearGradient4263"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.211835,128.44564)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3643"
+ xlink:href="#linearGradient3225-63-131"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(3.8779407,0,0,3.8779407,16.777433,146.82857)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3639"
+ xlink:href="#linearGradient3160-677-734"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.211835,128.44564)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3636"
+ xlink:href="#linearGradient2890-912-711"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.211835,128.44564)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3633"
+ xlink:href="#linearGradient2890-724-115"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.211835,128.44564)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3630"
+ xlink:href="#linearGradient2917-764-482"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.211835,128.44564)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3627"
+ xlink:href="#linearGradient2930-979-212"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(3.5340916,0,0,3.5340916,19.715902,169.46364)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3624"
+ xlink:href="#linearGradient3092-76-338"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0482945,311.92061)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3621"
+ xlink:href="#linearGradient3146-499-197"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0482945,311.92061)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3618"
+ xlink:href="#linearGradient3146-470-849"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(3.2495166,0.62823028,-0.11505962,0.59514756,42.389829,253.51642)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3615"
+ xlink:href="#linearGradient3146-197-371"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(5.6635815,0,0,0.67404041,-148.31259,401.08137)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3612"
+ xlink:href="#linearGradient3146-699-272"
+ inkscape:collect="always" />
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(3.8779407,0,0,0.01340682,16.777433,388.26567)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3609"
+ xlink:href="#linearGradient3205-564-694"
+ inkscape:collect="always" />
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(3.8779407,0,0,0.03426138,16.232078,404.54243)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3606"
+ xlink:href="#linearGradient3146-26-348"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-26-348">
+ <stop
+ id="stop11130"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop11132" />
+ <stop
+ id="stop11134"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11136"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(3.8779407,0,0,0.03426138,16.2585,376.71078)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9433-557-153"
+ xlink:href="#linearGradient3146-26-348"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3205-564-694"
+ inkscape:collect="always">
+ <stop
+ id="stop11124"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11126"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(3.8779407,0,0,0.01340682,16.803855,360.43402)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9431-484-495"
+ xlink:href="#linearGradient3205-564-694"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-699-272">
+ <stop
+ id="stop11114"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop11116" />
+ <stop
+ id="stop11118"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11120"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(5.6635815,0,0,0.67404041,-148.28617,373.24972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9429-405-674"
+ xlink:href="#linearGradient3146-699-272"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-197-371">
+ <stop
+ id="stop11104"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop11106" />
+ <stop
+ id="stop11108"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11110"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(3.2495166,0.62823028,-0.11505962,0.59514756,42.416251,225.68477)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9427-787-901"
+ xlink:href="#linearGradient3146-197-371"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-470-849">
+ <stop
+ id="stop11094"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop11096" />
+ <stop
+ id="stop11098"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11100"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9425-359-895"
+ xlink:href="#linearGradient3146-470-849"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-499-197">
+ <stop
+ id="stop11084"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop11086" />
+ <stop
+ id="stop11088"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11090"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9423-545-527"
+ xlink:href="#linearGradient3146-499-197"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3092-76-338"
+ inkscape:collect="always">
+ <stop
+ id="stop11078"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop11080"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(3.5340916,0,0,3.5340916,19.742324,141.63199)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9421-598-438"
+ xlink:href="#linearGradient3092-76-338"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2930-979-212">
+ <stop
+ id="stop11066"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop11068" />
+ <stop
+ id="stop11070"
+ offset="0.29486871"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop11072" />
+ <stop
+ id="stop11074"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9419-250-835"
+ xlink:href="#linearGradient2930-979-212"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2917-764-482"
+ inkscape:collect="always">
+ <stop
+ id="stop11060"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11062"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9417-854-322"
+ xlink:href="#linearGradient2917-764-482"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-724-115">
+ <stop
+ id="stop11052"
+ offset="0"
+ style="stop-color:#313230;stop-opacity:1;" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop11054" />
+ <stop
+ id="stop11056"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9415-26-7"
+ xlink:href="#linearGradient2890-724-115"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-912-711">
+ <stop
+ id="stop11044"
+ offset="0"
+ style="stop-color:#313230;stop-opacity:1;" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop11046" />
+ <stop
+ id="stop11048"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9413-12-652"
+ xlink:href="#linearGradient2890-912-711"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-677-734">
+ <stop
+ id="stop11038"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ id="stop11040"
+ offset="1"
+ style="stop-color:#797979;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(3.8779407,0,0,3.8779407,16.803855,118.99692)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9411-315-946"
+ xlink:href="#linearGradient3160-677-734"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3189-338-471"
+ inkscape:collect="always">
+ <stop
+ id="stop11032"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop11034"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9409-380-91"
+ xlink:href="#linearGradient3189-338-471"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3225-63-131">
+ <stop
+ id="stop11026"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop11028"
+ offset="1"
+ style="stop-color:#7f7f7f;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9407-185-406"
+ xlink:href="#linearGradient3225-63-131"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3291-902-436"
+ inkscape:collect="always">
+ <stop
+ id="stop11020"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11022"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.912209"
+ fy="115.7093"
+ fx="63.912209"
+ cy="115.70919"
+ cx="63.912209"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9405-117-542"
+ xlink:href="#linearGradient3291-902-436"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3529-86-282">
+ <stop
+ id="stop11012"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.80219781"
+ id="stop11014" />
+ <stop
+ id="stop11016"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="17.5625"
+ fy="58.75"
+ fx="10.25"
+ cy="58.75"
+ cx="10.25"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9403-685-582"
+ xlink:href="#linearGradient3529-86-282"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3541-845-38">
+ <stop
+ id="stop11004"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#335668;stop-opacity:0.79422385;"
+ offset="0.5"
+ id="stop11006" />
+ <stop
+ id="stop11008"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="41.896976"
+ x2="47.853844"
+ y1="72.396973"
+ x1="45.155617"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9401-82-291"
+ xlink:href="#linearGradient3541-845-38"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-187-642">
+ <stop
+ id="stop10994"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop10996" />
+ <stop
+ id="stop10998"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop11000"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(0.965926,-0.258819,0.00228665,0.0085339,3.472771,75.68491)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9399-429-605"
+ xlink:href="#linearGradient3146-187-642"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3205-337-363"
+ inkscape:collect="always">
+ <stop
+ id="stop10988"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop10990"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(0.965926,-0.258819,8.947905e-4,0.0033394,2.522271,71.59426)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9397-309-349"
+ xlink:href="#linearGradient3205-337-363"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-503-96">
+ <stop
+ id="stop10978"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop10980" />
+ <stop
+ id="stop10982"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop10984"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(1.410697,-0.377995,0.04498637,0.167891,-37.74338,85.8047)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9395-67-109"
+ xlink:href="#linearGradient3146-503-96"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-267-346">
+ <stop
+ id="stop10968"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop10970" />
+ <stop
+ id="stop10972"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop10974"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(0.851326,-0.06039621,0.01106166,0.15592,-0.091478,36.32122)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9393-641-971"
+ xlink:href="#linearGradient3146-267-346"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-507-607">
+ <stop
+ id="stop10958"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop10960" />
+ <stop
+ id="stop10962"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop10964"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9391-502-67"
+ xlink:href="#linearGradient3146-507-607"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-885-515">
+ <stop
+ id="stop10948"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop10950" />
+ <stop
+ id="stop10952"
+ offset="0.75"
+ style="stop-color:#959595;stop-opacity:0.24705882;" />
+ <stop
+ id="stop10954"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9389-453-398"
+ xlink:href="#linearGradient3146-885-515"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-199-324">
+ <stop
+ id="stop10942"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ id="stop10944"
+ offset="1"
+ style="stop-color:#797979;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(0.965926,-0.258819,0.258819,0.965926,-13.59157,11.45659)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9387-409-257"
+ xlink:href="#linearGradient3160-199-324"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-812-595">
+ <stop
+ id="stop10936"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ id="stop10938"
+ offset="1"
+ style="stop-color:#797979;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3160-168-629">
+ <stop
+ id="stop10924"
+ offset="0"
+ style="stop-color:#4a4a4a;stop-opacity:1;" />
+ <stop
+ id="stop10926"
+ offset="1"
+ style="stop-color:#797979;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9385-170-129"
+ xlink:href="#linearGradient3160-168-629"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3134-744-219"
+ inkscape:collect="always">
+ <stop
+ id="stop10918"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop10920"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9383-435-25"
+ xlink:href="#linearGradient3134-744-219"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3092-216-126"
+ inkscape:collect="always">
+ <stop
+ id="stop10912"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop10914"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(0.880279,-0.23587,0.23587,0.880279,-11.34895,16.89844)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9381-884-21"
+ xlink:href="#linearGradient3092-216-126"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2930-16-32">
+ <stop
+ id="stop10900"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop10902" />
+ <stop
+ id="stop10904"
+ offset="0.29486871"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ <stop
+ style="stop-color:#bababa;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop10906" />
+ <stop
+ id="stop10908"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9379-390-804"
+ xlink:href="#linearGradient2930-16-32"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2917-549-212"
+ inkscape:collect="always">
+ <stop
+ id="stop10894"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop10896"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9377-120-159"
+ xlink:href="#linearGradient2917-549-212"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-958-479">
+ <stop
+ id="stop10886"
+ offset="0"
+ style="stop-color:#313230;stop-opacity:1;" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop10888" />
+ <stop
+ id="stop10890"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9375-440-939"
+ xlink:href="#linearGradient2890-958-479"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-40-207">
+ <stop
+ id="stop10878"
+ offset="0"
+ style="stop-color:#313230;stop-opacity:1;" />
+ <stop
+ style="stop-color:#969696;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop10880" />
+ <stop
+ id="stop10882"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9373-355-87"
+ xlink:href="#linearGradient2890-40-207"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3189-669-875"
+ inkscape:collect="always">
+ <stop
+ id="stop10872"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop10874"
+ offset="1"
+ style="stop-color:#bababa;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9371-19-996"
+ xlink:href="#linearGradient3189-669-875"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3225-256-509">
+ <stop
+ id="stop10866"
+ offset="0"
+ style="stop-color:#bababa;stop-opacity:1;" />
+ <stop
+ id="stop10868"
+ offset="1"
+ style="stop-color:#7f7f7f;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9369-160-178"
+ xlink:href="#linearGradient3225-256-509"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-26">
+ <stop
+ id="stop9945"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9947" />
+ <stop
+ id="stop9949"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9951"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(3.8779407,0,0,0.03426138,16.2585,376.71078)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9433-557"
+ xlink:href="#linearGradient3146-26"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3205-564"
+ inkscape:collect="always">
+ <stop
+ id="stop9939"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop9941"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(3.8779407,0,0,0.01340682,16.803855,360.43402)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9431-484"
+ xlink:href="#linearGradient3205-564"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-699">
+ <stop
+ id="stop9929"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9931" />
+ <stop
+ id="stop9933"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9935"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(5.6635815,0,0,0.67404041,-148.28617,373.24972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9429-405"
+ xlink:href="#linearGradient3146-699"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-197">
+ <stop
+ id="stop9919"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9921" />
+ <stop
+ id="stop9923"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9925"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(3.2495166,0.62823028,-0.11505962,0.59514756,42.416251,225.68477)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9427-787"
+ xlink:href="#linearGradient3146-197"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-470">
+ <stop
+ id="stop9909"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9911" />
+ <stop
+ id="stop9913"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9915"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9425-359"
+ xlink:href="#linearGradient3146-470"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-499">
+ <stop
+ id="stop9899"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9901" />
+ <stop
+ id="stop9903"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9905"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9423-545"
+ xlink:href="#linearGradient3146-499"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3092-76"
+ inkscape:collect="always">
+ <stop
+ id="stop9893"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9895"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(3.5340916,0,0,3.5340916,19.742324,141.63199)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9421-598"
+ xlink:href="#linearGradient3092-76"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2930-979">
+ <stop
+ id="stop9881"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop9883" />
+ <stop
+ id="stop9885"
+ offset="0.29486871"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop9887" />
+ <stop
+ id="stop9889"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9419-250"
+ xlink:href="#linearGradient2930-979"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2917-764"
+ inkscape:collect="always">
+ <stop
+ id="stop9875"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop9877"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9417-854"
+ xlink:href="#linearGradient2917-764"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-724">
+ <stop
+ id="stop9867"
+ offset="0"
+ style="stop-color:#363835;stop-opacity:1;" />
+ <stop
+ style="stop-color:#a7a7a7;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop9869" />
+ <stop
+ id="stop9871"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9415-26"
+ xlink:href="#linearGradient2890-724"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-912">
+ <stop
+ id="stop9859"
+ offset="0"
+ style="stop-color:#363835;stop-opacity:1;" />
+ <stop
+ style="stop-color:#a7a7a7;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop9861" />
+ <stop
+ id="stop9863"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9413-12"
+ xlink:href="#linearGradient2890-912"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-677">
+ <stop
+ id="stop9853"
+ offset="0"
+ style="stop-color:#525252;stop-opacity:1;" />
+ <stop
+ id="stop9855"
+ offset="1"
+ style="stop-color:#868686;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(3.8779407,0,0,3.8779407,16.803855,118.99692)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9411-315"
+ xlink:href="#linearGradient3160-677"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3189-338"
+ inkscape:collect="always">
+ <stop
+ id="stop9847"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9849"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9409-380"
+ xlink:href="#linearGradient3189-338"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3225-63">
+ <stop
+ id="stop9841"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9843"
+ offset="1"
+ style="stop-color:#8d8d8d;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9407-185"
+ xlink:href="#linearGradient3225-63"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3291-902"
+ inkscape:collect="always">
+ <stop
+ id="stop9835"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop9837"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.912209"
+ fy="115.7093"
+ fx="63.912209"
+ cy="115.70919"
+ cx="63.912209"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9405-117"
+ xlink:href="#linearGradient3291-902"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3529-86">
+ <stop
+ id="stop9827"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.80219781"
+ id="stop9829" />
+ <stop
+ id="stop9831"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="17.5625"
+ fy="58.75"
+ fx="10.25"
+ cy="58.75"
+ cx="10.25"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9403-685"
+ xlink:href="#linearGradient3529-86"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3541-845">
+ <stop
+ id="stop9819"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#395f74;stop-opacity:0.79422385;"
+ offset="0.5"
+ id="stop9821" />
+ <stop
+ id="stop9823"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="41.896976"
+ x2="47.853844"
+ y1="72.396973"
+ x1="45.155617"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9401-82"
+ xlink:href="#linearGradient3541-845"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-187">
+ <stop
+ id="stop9809"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9811" />
+ <stop
+ id="stop9813"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9815"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(0.965926,-0.258819,0.00228665,0.0085339,3.472771,75.68491)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9399-429"
+ xlink:href="#linearGradient3146-187"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3205-337"
+ inkscape:collect="always">
+ <stop
+ id="stop9803"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop9805"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(0.965926,-0.258819,8.947905e-4,0.0033394,2.522271,71.59426)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9397-309"
+ xlink:href="#linearGradient3205-337"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-503">
+ <stop
+ id="stop9793"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9795" />
+ <stop
+ id="stop9797"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9799"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(1.410697,-0.377995,0.04498637,0.167891,-37.74338,85.8047)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9395-67"
+ xlink:href="#linearGradient3146-503"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-267">
+ <stop
+ id="stop9783"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9785" />
+ <stop
+ id="stop9787"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9789"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(0.851326,-0.06039621,0.01106166,0.15592,-0.091478,36.32122)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9393-641"
+ xlink:href="#linearGradient3146-267"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-507">
+ <stop
+ id="stop9773"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9775" />
+ <stop
+ id="stop9777"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9779"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9391-502"
+ xlink:href="#linearGradient3146-507"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146-885">
+ <stop
+ id="stop9763"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop9765" />
+ <stop
+ id="stop9767"
+ offset="0.75"
+ style="stop-color:#a6a6a6;stop-opacity:0.24705882;" />
+ <stop
+ id="stop9769"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9389-453"
+ xlink:href="#linearGradient3146-885"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-199">
+ <stop
+ id="stop9757"
+ offset="0"
+ style="stop-color:#525252;stop-opacity:1;" />
+ <stop
+ id="stop9759"
+ offset="1"
+ style="stop-color:#868686;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(0.965926,-0.258819,0.258819,0.965926,-13.59157,11.45659)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9387-409"
+ xlink:href="#linearGradient3160-199"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-812">
+ <stop
+ id="stop9751"
+ offset="0"
+ style="stop-color:#525252;stop-opacity:1;" />
+ <stop
+ id="stop9753"
+ offset="1"
+ style="stop-color:#868686;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9385-296"
+ xlink:href="#linearGradient3160-812"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3134-138"
+ inkscape:collect="always">
+ <stop
+ id="stop9745"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9747"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9383-903"
+ xlink:href="#linearGradient3134-138"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160-168">
+ <stop
+ id="stop9739"
+ offset="0"
+ style="stop-color:#525252;stop-opacity:1;" />
+ <stop
+ id="stop9741"
+ offset="1"
+ style="stop-color:#868686;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9385-170"
+ xlink:href="#linearGradient3160-168"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3134-744"
+ inkscape:collect="always">
+ <stop
+ id="stop9733"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9735"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9383-435"
+ xlink:href="#linearGradient3134-744"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3092-216"
+ inkscape:collect="always">
+ <stop
+ id="stop9727"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9729"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(0.880279,-0.23587,0.23587,0.880279,-11.34895,16.89844)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9381-884"
+ xlink:href="#linearGradient3092-216"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2930-16">
+ <stop
+ id="stop9715"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop9717" />
+ <stop
+ id="stop9719"
+ offset="0.29486871"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ <stop
+ style="stop-color:#cfcfcf;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop9721" />
+ <stop
+ id="stop9723"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9379-390"
+ xlink:href="#linearGradient2930-16"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2917-549"
+ inkscape:collect="always">
+ <stop
+ id="stop9709"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop9711"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9377-120"
+ xlink:href="#linearGradient2917-549"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-958">
+ <stop
+ id="stop9701"
+ offset="0"
+ style="stop-color:#363835;stop-opacity:1;" />
+ <stop
+ style="stop-color:#a7a7a7;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop9703" />
+ <stop
+ id="stop9705"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9375-440"
+ xlink:href="#linearGradient2890-958"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890-40">
+ <stop
+ id="stop9693"
+ offset="0"
+ style="stop-color:#363835;stop-opacity:1;" />
+ <stop
+ style="stop-color:#a7a7a7;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop9695" />
+ <stop
+ id="stop9697"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9373-355"
+ xlink:href="#linearGradient2890-40"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3189-669"
+ inkscape:collect="always">
+ <stop
+ id="stop9687"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9689"
+ offset="1"
+ style="stop-color:#cfcfcf;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9371-19"
+ xlink:href="#linearGradient3189-669"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3225-256">
+ <stop
+ id="stop9681"
+ offset="0"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop9683"
+ offset="1"
+ style="stop-color:#8d8d8d;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9369-160"
+ xlink:href="#linearGradient3225-256"
+ inkscape:collect="always" />
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(3.8779407,0,0,0.03426138,16.2585,376.71078)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9433"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(3.8779407,0,0,0.01340682,16.803855,360.43402)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9431"
+ xlink:href="#linearGradient3205"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(5.6635815,0,0,0.67404041,-148.28617,373.24972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9429"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(3.2495166,0.62823028,-0.11505962,0.59514756,42.416251,225.68477)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9427"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9425"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9423"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(3.5340916,0,0,3.5340916,19.742324,141.63199)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9421"
+ xlink:href="#linearGradient3092"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9419"
+ xlink:href="#linearGradient2930"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9417"
+ xlink:href="#linearGradient2917"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9415"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9413"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(3.8779407,0,0,3.8779407,16.803855,118.99692)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9411"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9409"
+ xlink:href="#linearGradient3189"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9407"
+ xlink:href="#linearGradient3225"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.912209"
+ fy="115.7093"
+ fx="63.912209"
+ cy="115.70919"
+ cx="63.912209"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9405"
+ xlink:href="#linearGradient3291"
+ inkscape:collect="always" />
+ <radialGradient
+ r="17.5625"
+ fy="58.75"
+ fx="10.25"
+ cy="58.75"
+ cx="10.25"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9403"
+ xlink:href="#linearGradient3529"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="41.896976"
+ x2="47.853844"
+ y1="72.396973"
+ x1="45.155617"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9401"
+ xlink:href="#linearGradient3541"
+ inkscape:collect="always" />
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(0.965926,-0.258819,0.00228665,0.0085339,3.472771,75.68491)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9399"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(0.965926,-0.258819,8.947905e-4,0.0033394,2.522271,71.59426)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9397"
+ xlink:href="#linearGradient3205"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(1.410697,-0.377995,0.04498637,0.167891,-37.74338,85.8047)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9395"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(0.851326,-0.06039621,0.01106166,0.15592,-0.091478,36.32122)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9393"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9391"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9389"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(0.965926,-0.258819,0.258819,0.965926,-13.59157,11.45659)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9387"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9385"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9383"
+ xlink:href="#linearGradient3134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(0.880279,-0.23587,0.23587,0.880279,-11.34895,16.89844)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9381"
+ xlink:href="#linearGradient3092"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9379"
+ xlink:href="#linearGradient2930"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9377"
+ xlink:href="#linearGradient2917"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9375"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9373"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9371"
+ xlink:href="#linearGradient3189"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9369"
+ xlink:href="#linearGradient3225"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3541"
+ id="linearGradient8909"
+ gradientUnits="userSpaceOnUse"
+ x1="45.155617"
+ y1="72.396973"
+ x2="47.853844"
+ y2="41.896976" />
+ <linearGradient
+ id="linearGradient8864">
+ <stop
+ id="stop8866"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8868" />
+ <stop
+ id="stop8870"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8872"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(3.8779407,0,0,0.03426138,16.2585,376.71078)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3553"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(3.8779407,0,0,0.01340682,16.803855,360.43402)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3556"
+ xlink:href="#linearGradient3205"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8846">
+ <stop
+ id="stop8848"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8850" />
+ <stop
+ id="stop8852"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8854"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(5.6635815,0,0,0.67404041,-148.28617,373.24972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3559"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8835">
+ <stop
+ id="stop8837"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8839" />
+ <stop
+ id="stop8841"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8843"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(3.2495166,0.62823028,-0.11505962,0.59514756,42.416251,225.68477)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3562"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8824">
+ <stop
+ id="stop8826"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8828" />
+ <stop
+ id="stop8830"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8832"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3565"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8813">
+ <stop
+ id="stop8815"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8817" />
+ <stop
+ id="stop8819"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8821"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(3.6038982,0,5.1275102e-7,0.60616867,6.0747166,284.08896)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3568"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(3.5340916,0,0,3.5340916,19.742324,141.63199)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3574"
+ xlink:href="#linearGradient3092"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8793">
+ <stop
+ id="stop8795"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop8797" />
+ <stop
+ id="stop8799"
+ offset="0.29486871"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop8801" />
+ <stop
+ id="stop8803"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3577"
+ xlink:href="#linearGradient2930"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3580"
+ xlink:href="#linearGradient2917"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8777">
+ <stop
+ id="stop8779"
+ offset="0"
+ style="stop-color:#3c3e3b;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b9bab9;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop8781" />
+ <stop
+ id="stop8783"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3583"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8768">
+ <stop
+ id="stop8770"
+ offset="0"
+ style="stop-color:#3c3e3b;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b9bab9;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop8772" />
+ <stop
+ id="stop8774"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3586"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8761">
+ <stop
+ id="stop8763"
+ offset="0"
+ style="stop-color:#5b5b5b;stop-opacity:1;" />
+ <stop
+ id="stop8765"
+ offset="1"
+ style="stop-color:#959595;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(3.8779407,0,0,3.8779407,16.803855,118.99692)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3378"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3394"
+ xlink:href="#linearGradient3189"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8747">
+ <stop
+ id="stop8749"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ id="stop8751"
+ offset="1"
+ style="stop-color:#9d9d9d;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(4.2214605,0,0,4.2214605,-26.185413,100.61399)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3396"
+ xlink:href="#linearGradient3225"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3291"
+ inkscape:collect="always">
+ <stop
+ id="stop3293"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop3295"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ r="63.912209"
+ fy="115.7093"
+ fx="63.912209"
+ cy="115.70919"
+ cx="63.912209"
+ id="radialGradient3297"
+ xlink:href="#linearGradient3291"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3529">
+ <stop
+ id="stop3531"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.80219781"
+ id="stop3537" />
+ <stop
+ id="stop3533"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ r="17.5625"
+ fy="58.75"
+ fx="10.25"
+ cy="58.75"
+ cx="10.25"
+ id="radialGradient3535"
+ xlink:href="#linearGradient3529"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3541">
+ <stop
+ id="stop3543"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#3f6981;stop-opacity:0.79422385;"
+ offset="0.5"
+ id="stop3588" />
+ <stop
+ id="stop3545"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="41.896976"
+ x2="47.853844"
+ y1="72.396973"
+ x1="45.155617"
+ id="linearGradient3547"
+ xlink:href="#linearGradient3541"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8722">
+ <stop
+ id="stop8724"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8726" />
+ <stop
+ id="stop8728"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8730"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="31.649858"
+ fy="66.806999"
+ fx="96.350143"
+ cy="66.806999"
+ cx="96.350143"
+ gradientTransform="matrix(0.965926,-0.258819,0.00228665,0.0085339,3.472771,75.68491)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3510"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3205"
+ inkscape:collect="always">
+ <stop
+ id="stop3207"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop3210"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="30.94986"
+ fy="62.475086"
+ fx="96.094643"
+ cy="62.475086"
+ cx="96.094643"
+ gradientTransform="matrix(0.965926,-0.258819,8.947905e-4,0.0033394,2.522271,71.59426)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3508"
+ xlink:href="#linearGradient3205"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8707">
+ <stop
+ id="stop8709"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8711" />
+ <stop
+ id="stop8713"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8715"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29.344931"
+ fy="64.119919"
+ fx="109.07122"
+ cy="71.239235"
+ cx="92.454208"
+ gradientTransform="matrix(1.410697,-0.377995,0.04498637,0.167891,-37.74338,85.8047)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3506"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8696">
+ <stop
+ id="stop8698"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8700" />
+ <stop
+ id="stop8702"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8704"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="3.6800315"
+ fx="40.082912"
+ cy="3.6800315"
+ cx="40.082912"
+ gradientTransform="matrix(0.851326,-0.06039621,0.01106166,0.15592,-0.091478,36.32122)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3504"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8685">
+ <stop
+ id="stop8687"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop8689" />
+ <stop
+ id="stop8691"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop8693"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3502"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3146">
+ <stop
+ id="stop3148"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop3183" />
+ <stop
+ id="stop3185"
+ offset="0.75"
+ style="stop-color:#b8b8b8;stop-opacity:0.24705882;" />
+ <stop
+ id="stop3150"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="63.893539"
+ fy="44.293781"
+ fx="98.227898"
+ cy="44.293781"
+ cx="98.227898"
+ gradientTransform="matrix(0.897667,-0.240529,0.04045665,0.150986,-5.245533,53.29415)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3500"
+ xlink:href="#linearGradient3146"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8672">
+ <stop
+ id="stop8674"
+ offset="0"
+ style="stop-color:#5b5b5b;stop-opacity:1;" />
+ <stop
+ id="stop8676"
+ offset="1"
+ style="stop-color:#959595;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="6.8746934"
+ x2="34.981007"
+ y1="89.296867"
+ x1="34.981007"
+ gradientTransform="matrix(0.965926,-0.258819,0.258819,0.965926,-13.59157,11.45659)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3498"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8665">
+ <stop
+ id="stop8667"
+ offset="0"
+ style="stop-color:#5b5b5b;stop-opacity:1;" />
+ <stop
+ id="stop8669"
+ offset="1"
+ style="stop-color:#959595;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient8663"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient8655"
+ xlink:href="#linearGradient3134"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3160">
+ <stop
+ id="stop3162"
+ offset="0"
+ style="stop-color:#5b5b5b;stop-opacity:1;" />
+ <stop
+ id="stop3164"
+ offset="1"
+ style="stop-color:#959595;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="68.636307"
+ x2="31.868282"
+ y1="68.636307"
+ x1="13.012782"
+ gradientTransform="translate(-16.09364,7.548466)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3496"
+ xlink:href="#linearGradient3160"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3134"
+ inkscape:collect="always">
+ <stop
+ id="stop3136"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ id="stop3138"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="75.174103"
+ x2="55.263794"
+ y1="50.778923"
+ x1="26.241974"
+ gradientTransform="matrix(1.113305,0,0,1.113305,-43.84526,0.955735)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3494"
+ xlink:href="#linearGradient3134"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3092"
+ inkscape:collect="always">
+ <stop
+ id="stop3094"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ id="stop3096"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="85.991692"
+ x2="27.73057"
+ y1="35.675571"
+ x1="34.760506"
+ gradientTransform="matrix(0.880279,-0.23587,0.23587,0.880279,-11.34895,16.89844)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3492"
+ xlink:href="#linearGradient3092"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2930">
+ <stop
+ id="stop2932"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.50180507;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0.13736264"
+ id="stop2938" />
+ <stop
+ id="stop2940"
+ offset="0.29486871"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0.79061371;"
+ offset="0.58544481"
+ id="stop2942" />
+ <stop
+ id="stop2934"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="50.607132"
+ x2="94.15625"
+ y1="58.84375"
+ x1="94.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3490"
+ xlink:href="#linearGradient2930"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2917"
+ inkscape:collect="always">
+ <stop
+ id="stop2919"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop2921"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="64.642754"
+ x2="94.478127"
+ y1="67.146591"
+ x1="94.478127"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3488"
+ xlink:href="#linearGradient2917"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient8624">
+ <stop
+ id="stop8626"
+ offset="0"
+ style="stop-color:#3c3e3b;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b9bab9;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop8628" />
+ <stop
+ id="stop8630"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="63.796875"
+ x2="127.31514"
+ y1="63.796875"
+ x1="64.15625"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3486"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2890">
+ <stop
+ id="stop2892"
+ offset="0"
+ style="stop-color:#3c3e3b;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b9bab9;stop-opacity:1;"
+ offset="0.07692308"
+ id="stop2898" />
+ <stop
+ id="stop2894"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="49.15625"
+ x2="124.625"
+ y1="49.15625"
+ x1="63.498344"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3484"
+ xlink:href="#linearGradient2890"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3189"
+ inkscape:collect="always">
+ <stop
+ id="stop3191-9"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ id="stop3193"
+ offset="1"
+ style="stop-color:#e6e6e6;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ r="29"
+ fy="89.5"
+ fx="39"
+ cy="89.5"
+ cx="39"
+ gradientTransform="matrix(1,0,0,0.534483,0,41.66379)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3482"
+ xlink:href="#linearGradient3189"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3225">
+ <stop
+ id="stop3227"
+ offset="0"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ id="stop3229"
+ offset="1"
+ style="stop-color:#9d9d9d;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="91.103127"
+ x2="-20.653816"
+ y1="22.707912"
+ x1="132.77945"
+ gradientTransform="matrix(1.05149,-0.281746,0.281746,1.05149,-25.52633,9.74688)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3480"
+ xlink:href="#linearGradient3225"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient6956"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <filter
+ y="-.25"
+ x="-.25"
+ height="1.5"
+ width="1.5"
+ inkscape:label="Drop shadow"
+ id="filter5214">
+ <feGaussianBlur
+ result="blur"
+ stdDeviation="2"
+ in="SourceAlpha"
+ id="feGaussianBlur5216" />
+ <feColorMatrix
+ values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 "
+ type="matrix"
+ result="bluralpha"
+ id="feColorMatrix5218" />
+ <feOffset
+ result="offsetBlur"
+ dy="6"
+ dx="0"
+ in="bluralpha"
+ id="feOffset5220" />
+ <feMerge
+ id="feMerge5222">
+ <feMergeNode
+ in="offsetBlur"
+ id="feMergeNode5224" />
+ <feMergeNode
+ in="SourceGraphic"
+ id="feMergeNode5226" />
+ </feMerge>
+ </filter>
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5154"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5151"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5148"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5140"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5137"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(-8.0847263,-100.8597)"
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5091"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5088"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5085"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5082"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5079"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5075"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5073"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5071"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5069"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5067"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5065"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="535.43298"
+ x2="262.43457"
+ y1="232.44435"
+ x1="265.73489"
+ id="linearGradient4955"
+ xlink:href="#linearGradient4957"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(1,0,0,0.93617,296.44,-189.045)"
+ gradientUnits="userSpaceOnUse"
+ y2="591.70483"
+ x2="253.32147"
+ y1="285.6604"
+ x1="320.69421"
+ id="linearGradient2199"
+ xlink:href="#linearGradient2201"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2191">
+ <stop
+ id="stop2193"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop2195"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2201">
+ <stop
+ style="stop-color:#c0c0c0;stop-opacity:1;"
+ offset="0"
+ id="stop2203" />
+ <stop
+ id="stop2207"
+ offset="0.22727273"
+ style="stop-color:#e6e6e6;stop-opacity:1;" />
+ <stop
+ style="stop-color:#bcbcbc;stop-opacity:1;"
+ offset="0.87706614"
+ id="stop3082" />
+ <stop
+ style="stop-color:#9e9e9e;stop-opacity:1;"
+ offset="1"
+ id="stop2205" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3849">
+ <stop
+ id="stop3851"
+ offset="0"
+ style="stop-color:#006c8b;stop-opacity:1;" />
+ <stop
+ id="stop3853"
+ offset="1"
+ style="stop-color:#486c8b;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3861">
+ <stop
+ id="stop3863"
+ offset="0"
+ style="stop-color:#6995b9;stop-opacity:1;" />
+ <stop
+ id="stop3865"
+ offset="1"
+ style="stop-color:#6995b9;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4905">
+ <stop
+ id="stop4907"
+ offset="0"
+ style="stop-color:#00afcf;stop-opacity:1;" />
+ <stop
+ id="stop4909"
+ offset="1"
+ style="stop-color:#007292;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4957">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop4959" />
+ <stop
+ style="stop-color:#a4a19b;stop-opacity:1;"
+ offset="1"
+ id="stop4961" />
+ </linearGradient>
+ <linearGradient
+ osb:paint="solid"
+ id="linearGradient5479">
+ <stop
+ id="stop5481"
+ offset="0"
+ style="stop-color:#a1a1a1;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient7008">
+ <stop
+ id="stop7010"
+ offset="0"
+ style="stop-color:#5c5c5c;stop-opacity:1;" />
+ <stop
+ id="stop7012"
+ offset="1"
+ style="stop-color:#bdc1bb;stop-opacity:1;" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="1.0"
+ id="base"
+ inkscape:current-layer="layer1"
+ inkscape:cx="94.604748"
+ inkscape:cy="148.47211"
+ inkscape:document-units="px"
+ inkscape:guide-bbox="true"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:window-height="1419"
+ inkscape:window-width="2558"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:zoom="1.0387645"
+ pagecolor="#ffffff"
+ showgrid="false"
+ showguides="true"
+ inkscape:window-maximized="1"
+ inkscape:showpageshadow="false"
+ showborder="true" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
+ <dc:title />
+ <dc:date />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Dominik Schürmann</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:publisher>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Ebene 1"
+ transform="translate(0,-552.36215)">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.34680134000000001;fill:url(#linearGradient4312);fill-opacity:1.0;fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="csssssc"
+ id="path3175-1"
+ d="m 1016.1241,812.26999 c 0,47.10609 -466.4501,176.53979 -475.78279,177.01889 -17.91449,0.9184 -52.72559,-59.36239 -143.07783,-62.98629 C 283.48897,921.78647 64.560268,1036.855 12.663853,992.58198 1.1984848,982.8011 -80.717605,585.54933 9.3150198,522.64979 122.0588,443.88292 958.43286,441.78693 1019.0591,527.10032 c 60.7996,85.55794 11.8501,143.89279 -2.935,285.16967 z" />
+ <rect
+ y="574.71844"
+ x="248.6223"
+ width="193.63591"
+ style="fill:none;stroke:none"
+ id="rect2383"
+ height="193.63591" />
+ <g
+ transform="matrix(0.70341159,0,0,0.70341159,326.23974,460.30412)"
+ id="layer1-0"
+ inkscape:label="Layer 1">
+ <g
+ transform="translate(-1.3638622,6.7536828)"
+ id="g4431">
+ <g
+ transform="matrix(3.8779408,0,0,3.8779408,15.807953,70.239303)"
+ id="g3462">
+ <path
+ sodipodi:nodetypes="cssssscccccccccccccsssccsccccccccccccccscccsssc"
+ id="path3398"
+ d="M 24.181711,34.829499 C 8.3491555,39.071819 -1.0696913,55.385741 3.1726293,71.218296 7.4149504,87.05085 23.719868,96.4361 39.552423,92.19378 c 7.139562,-1.91304 12.970506,-6.2726 16.829626,-11.92921 0.02791,-0.04092 0.04609,-0.08679 0.0738,-0.127838 0.04438,-0.08645 0.103958,-0.168818 0.147605,-0.255654 0.982551,-1.954801 1.764428,-3.990666 2.361504,-6.10751 L 114.58176,58.871092 c 0.44818,-0.12009 0.88922,-0.274388 1.27459,-0.485595 1.2698,-0.347821 2.43319,-1.213112 3.18156,-2.509333 l 6.55941,-11.410429 c 1.42099,-2.461247 0.78707,-5.482553 -1.45585,-6.777501 l -8.42774,-4.837355 c -0.19377,0.335622 -0.48546,0.598313 -0.89111,0.707007 l -1.27699,0.342169 -3.66445,-2.115667 c -0.72741,-0.419968 -1.66357,-0.169123 -2.08354,0.558283 l -1.50723,2.709017 -4.04793,-2.337077 c -0.20325,-0.117339 -0.44281,-0.165733 -0.66134,-0.182974 -0.0746,-0.0103 -0.14303,-0.01426 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10071,0.0061 -0.17642,0.01125 -0.27784,0.03843 l -3.831004,1.026515 c -0.05689,0.01525 -0.10553,0.05759 -0.159019,0.07863 -0.431007,0.07151 -0.831501,0.308563 -1.068135,0.718423 l -2.844687,4.976346 -6.922696,1.854931 -4.985351,-2.878294 c -0.727392,-0.41996 -1.663564,-0.169113 -2.083529,0.55828 L 77.473785,41.764576 73.6389,39.550505 c -0.727393,-0.419959 -1.663575,-0.169111 -2.08353,0.55828 l -3.410506,5.956373 -3.427743,0.91846 c -0.811293,0.21739 -1.62384,-0.28014 -1.841227,-1.091439 L 62.245557,43.539808 C 61.89324,42.224935 60.867705,42.000045 59.920026,42.253975 L 53.4342,43.991847 c -1.020929,-1.373074 -2.138582,-2.665496 -3.339338,-3.859613 -0.0411,-0.04087 -0.09554,-0.06675 -0.136832,-0.107408 -7.075365,-5.443729 -16.493832,-7.682563 -25.776319,-5.195327 z m -5.308547,10.715083 c 4.491338,-1.203447 9.099126,1.428453 10.302575,5.919788 1.20345,4.491335 -1.453052,9.141735 -5.944389,10.345185 -4.491335,1.203446 -9.117134,-1.495664 -10.320584,-5.986999 -1.203448,-4.491332 1.471063,-9.074525 5.962398,-10.277974 z"
+ style="fill:url(#linearGradient9369-160-178);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(0.728608,-0.19523,0.19523,0.728608,-7.441788,31.19368)"
+ d="m 68,65.25 c 0,16.016258 -12.983742,29 -29,29 -16.016258,0 -29,-12.983742 -29,-29 0,-16.016258 12.983742,-29 29,-29 16.016258,0 29,12.983742 29,29 z"
+ sodipodi:ry="29"
+ sodipodi:rx="29"
+ sodipodi:cy="65.25"
+ sodipodi:cx="39"
+ id="path3400"
+ style="opacity:0.41393445;fill:url(#radialGradient9371-19-996);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ style="fill:url(#linearGradient9373-355-87);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 55.322941,43.481722 c 0.0061,0.100715 0.01921,0.20312 0.04638,0.304536 l 2.25397,8.411927 c 0.217391,0.811316 1.03069,1.308651 1.842005,1.091259 L 122.09473,36.507937 115.729,32.860453 c -0.19377,0.335622 -0.49854,0.59142 -0.90418,0.700111 l -1.28151,0.343381 -3.6664,-2.1168 c -0.7274,-0.419969 -1.65016,-0.172716 -2.07011,0.554686 l -1.53069,2.699333 -4.04138,-2.333288 c -0.20324,-0.117342 -0.42813,-0.16167 -0.64666,-0.178911 -0.0746,-0.0103 -0.13814,-0.01396 -0.21474,-0.01289 -0.0239,0.0017 -0.042,0.01482 -0.0657,0.01762 -0.10071,0.0061 -0.2031,0.0192 -0.30453,0.04638 l -3.811645,1.021328 c -0.0569,0.01525 -0.10201,0.05585 -0.155499,0.07689 -0.431007,0.07151 -0.840633,0.30141 -1.077267,0.711271 l -2.853687,4.990835 -6.900411,1.84896 -4.999639,-2.886543 c -0.727393,-0.419961 -1.650158,-0.172704 -2.070123,0.554688 L 77.475028,41.77228 73.64197,39.559265 c -0.72739,-0.41996 -1.650167,-0.172704 -2.070122,0.554687 l -3.439798,5.957903 -3.417345,0.915675 c -0.811297,0.217388 -1.624619,-0.279958 -1.842006,-1.091258 L 62.23877,43.530417 c -0.352319,-1.314873 -1.367875,-1.535265 -2.315555,-1.281335 l -4.600274,1.23264 z"
+ id="path3402"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path3404"
+ d="m 64.294339,55.270805 c -0.811315,0.217392 -4.962468,1.332335 -4.481761,3.126357 l 0.159724,0.596098 c 0.450205,1.680187 4.579365,0.822187 5.39068,0.604796 L 125.99908,43.350662 c 0.49401,-1.574706 0.22433,-3.219095 -0.66053,-4.436605 L 64.294339,55.270805 z"
+ style="fill:url(#linearGradient9375-440-939);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient9377-120-159);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 64.857832,57.373787 c -0.811316,0.217391 -5.342172,-0.08474 -4.954414,1.362394 l 0.06888,0.257079 c 0.444491,1.658864 4.579365,0.822187 5.39068,0.604796 L 126.10423,43.322487 c 0.49401,-1.574707 0.22433,-3.219095 -0.66052,-4.436605 L 64.857832,57.373787 z"
+ id="path3406"
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3408"
+ d="m 55.322941,43.481722 c 0.0061,0.100715 0.01921,0.20312 0.04638,0.304536 l 2.25397,8.411927 c 0.217391,0.811316 1.03069,1.308651 1.842005,1.091259 L 122.09473,36.507937 115.729,32.860453 c -0.19377,0.335622 -0.49854,0.59142 -0.90418,0.700111 l -1.28151,0.343381 -3.6664,-2.1168 c -0.7274,-0.419969 -1.65016,-0.172716 -2.07011,0.554686 l -1.53069,2.699333 -4.04138,-2.333288 c -0.20324,-0.117342 -0.42813,-0.16167 -0.64666,-0.178911 -0.0746,-0.0103 -0.13814,-0.01396 -0.21474,-0.01289 -0.0239,0.0017 -0.042,0.01482 -0.0657,0.01762 -0.10071,0.0061 -0.2031,0.0192 -0.30453,0.04638 l -3.811645,1.021328 c -0.0569,0.01525 -0.10201,0.05585 -0.155499,0.07689 -0.431007,0.07151 -0.840633,0.30141 -1.077267,0.711271 l -2.853687,4.990835 -6.900411,1.84896 -4.999639,-2.886543 c -0.727393,-0.419961 -1.650158,-0.172704 -2.070123,0.554688 L 77.475028,41.77228 73.64197,39.559265 c -0.72739,-0.41996 -1.650167,-0.172704 -2.070122,0.554687 l -3.439798,5.957903 -3.417345,0.915675 c -0.811297,0.217388 -1.624619,-0.279958 -1.842006,-1.091258 L 62.23877,43.530417 c -0.352319,-1.314873 -1.367875,-1.535265 -2.315555,-1.281335 l -4.600274,1.23264 z"
+ style="fill:url(#linearGradient9379-390-804);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3410"
+ d="m 24.453487,40.951785 c -0.278503,0.0893 -0.539938,0.227781 -0.81312,0.325928 l 0.1981,0.739317 1.195316,-1.184717 -0.009,-0.03361 c -0.188236,0.05559 -0.385377,0.09346 -0.571291,0.153077 z m 1.814688,-0.486244 -0.539453,0.540744 0.522263,1.949109 1.428138,-1.391176 -0.351176,-1.310607 c -0.353713,0.06954 -0.70601,0.126491 -1.059772,0.21193 z m 1.682677,-0.306801 0.234117,0.873739 1.078904,-1.081489 c -0.444796,0.05158 -0.866983,0.13148 -1.313021,0.20775 z m -4.897371,1.348266 c -0.284754,0.110431 -0.566288,0.210126 -0.846725,0.334933 0.333398,0.03079 0.654403,0.111242 0.981793,0.169147 l -0.135068,-0.50408 z m 7.196364,-1.640116 -0.17462,0.154843 0.432217,1.613055 1.419136,-1.42478 -0.108054,-0.403263 c -0.521384,0.0068 -1.043367,0.01983 -1.568679,0.06014 z m -5.026967,1.671134 -0.772277,0.747203 C 24.813169,42.390423 25.17,42.509101 25.520027,42.647 l -0.297149,-1.108976 z m 4.346501,-0.984552 -1.204319,1.151112 0.441221,1.646661 1.186311,-1.218322 -0.423213,-1.579451 z m 3.649798,-0.76185 -0.597659,0.592358 0.531267,1.982714 1.161709,-1.175713 -0.36018,-1.344213 c -0.249836,-0.01881 -0.48382,-0.04396 -0.735137,-0.05515 z m 1.394059,0.0947 0.207104,0.772923 0.655864,-0.643973 c -0.283232,-0.03902 -0.577362,-0.09978 -0.862968,-0.12895 z m -2.497563,1.029401 -1.419136,1.42478 0.522262,1.949109 1.419136,-1.424781 -0.522262,-1.949108 z m -4.256459,1.320605 -1.020695,1.029874 c 0.434477,0.233862 0.850384,0.49579 1.253693,0.780634 l 0.199219,-0.197453 -0.432217,-1.613055 z m 8.403743,-2.107704 -1.253522,1.236332 0.432217,1.613055 1.419135,-1.42478 -0.369186,-1.377818 c -0.08434,-0.01531 -0.144054,-0.03236 -0.228644,-0.04679 z m 0.914582,0.187155 0.198099,0.739317 0.564051,-0.583354 c -0.249905,-0.06107 -0.509667,-0.102698 -0.76215,-0.155963 z m -6.995853,2.522859 -1.195314,1.184717 0.234117,0.873738 c 0.239867,0.215264 0.463772,0.445851 0.686583,0.680464 l 0.805881,-0.756206 -0.531267,-1.982713 z m 8.48655,-2.201928 -1.112508,1.090493 0.522262,1.949108 1.204319,-1.151112 -0.495249,-1.848292 c -0.04572,-0.01294 -0.07301,-0.02753 -0.118824,-0.0402 z m -4.173651,1.22638 -1.16171,1.175713 0.432217,1.613056 1.16171,-1.175713 -0.432217,-1.613056 z m 5.005426,-0.945001 0.288145,1.075371 0.73867,-0.738198 c -0.331899,-0.121338 -0.688782,-0.230193 -1.026815,-0.337173 z m -2.450129,1.340854 -1.42814,1.391175 0.531267,1.982713 1.419135,-1.42478 -0.522262,-1.949108 z m -4.222852,1.3116 -1.428141,1.391174 0.441222,1.646662 1.410131,-1.458387 -0.423212,-1.579449 z m 8.31193,-2.047085 -1.170714,1.142107 0.441222,1.646661 1.41013,-1.458385 -0.324163,-1.209792 c -0.118639,-0.04937 -0.236932,-0.07308 -0.356475,-0.120591 z m 1.096438,0.46259 0.09905,0.369659 0.22382,-0.240063 c -0.11157,-0.05308 -0.210394,-0.07821 -0.32287,-0.129596 z m -7.119502,2.195809 -1.161709,1.175713 0.522262,1.949108 1.16171,-1.175712 -0.522263,-1.949109 z m -4.222853,1.311601 -0.573056,0.549749 c 0.314089,0.36607 0.584652,0.770104 0.855256,1.175539 l 0.141013,-0.145838 -0.423213,-1.57945 z m 8.569356,-2.296152 -1.195314,1.184717 0.432217,1.613054 1.18631,-1.218321 -0.423213,-1.57945 z m 3.683403,-0.770856 -0.622259,0.634968 0.522262,1.949108 1.18631,-1.218322 -0.252126,-0.940949 C 43.714301,42.702794 43.417501,42.564812 43.145802,42.42645 z m -9.706465,3.429255 -1.419136,1.42478 0.522262,1.949108 1.42814,-1.391174 -0.531266,-1.982714 z m 8.569356,-2.296152 -1.419135,1.42478 0.522262,1.949108 1.428139,-1.391174 -0.531266,-1.982714 z m -4.256459,1.320605 -1.419135,1.424779 0.432217,1.613057 1.419135,-1.424782 -0.432217,-1.613054 z m 7.524058,-1.223668 -0.340231,0.34329 0.432217,1.613057 1.137109,-1.133103 C 46.107003,44.18387 45.693405,43.926727 45.276292,43.656487 z m -5.192581,1.859582 -1.204319,1.151112 0.531267,1.982714 1.195314,-1.184717 -0.522262,-1.949109 z m 4.337499,-1.018157 -1.195315,1.184719 0.441221,1.646659 1.186311,-1.218322 -0.432217,-1.613056 z m -8.593956,2.338763 -1.170714,1.142108 0.441221,1.646659 1.152705,-1.209318 -0.423212,-1.579449 z m 11.140248,-1.976516 -1.41013,1.458385 0.522262,1.949109 1.41013,-1.458386 -0.522262,-1.949108 z m -8.593956,2.338763 -1.419135,1.424779 0.522262,1.949109 1.419135,-1.42478 -0.522262,-1.949108 z m -4.222852,1.3116 -1.419136,1.424779 0.432217,1.613056 1.419135,-1.424781 -0.432216,-1.613054 z m 8.569355,-2.296152 -1.419134,1.424779 0.432217,1.613056 1.419134,-1.424781 -0.432217,-1.613054 z m 5.059454,-0.74337 0.234117,0.873738 0.331227,-0.376895 C 48.159743,45.798299 47.970076,45.634344 47.779503,45.471 z m -11.339943,3.650835 -1.161709,1.175714 0.522262,1.949108 1.170714,-1.142108 -0.531267,-1.982714 z m 8.602962,-2.305156 -1.195315,1.184718 0.522262,1.949108 1.195315,-1.184717 -0.522262,-1.949109 z M 8.7331833,56.617773 c -0.080856,0.257998 -0.185146,0.528328 -0.2567787,0.789166 L 8.8412374,57.021037 8.7331833,56.617773 z m 32.0528797,-8.480489 -1.195313,1.184718 0.432216,1.613055 1.195314,-1.184717 -0.432217,-1.613056 z m 8.005304,-1.712797 -0.597656,0.592359 0.432217,1.613054 1.195314,-1.184717 c -0.32357,-0.356241 -0.684705,-0.686305 -1.029875,-1.020696 z M 9.0303324,57.726749 8.1998504,58.525565 c -0.1251137,0.570603 -0.2112478,1.15432 -0.2915036,1.73494 l 0.2251128,0.840132 1.419135,-1.424779 -0.5222622,-1.949109 z m 25.7416726,-6.89746 -1.42814,1.391175 0.531267,1.982713 1.419135,-1.42478 -0.522262,-1.949108 z m 8.569356,-2.296152 -1.428139,1.391174 0.531266,1.982714 1.419135,-1.42478 -0.522262,-1.949108 z m 4.337498,-1.018157 -1.419134,1.42478 0.441221,1.64666 1.41013,-1.458386 -0.432217,-1.613054 z m -8.593956,2.338762 -1.42814,1.391174 0.441222,1.64666 1.41013,-1.458385 -0.423212,-1.579449 z m -29.1435218,8.853506 0.1170588,0.43687 0.05821,-0.05161 C 10.05758,58.966431 9.9963541,58.836017 9.9413812,58.707248 z m 40.0599508,-10.589959 -1.186309,1.218323 0.522261,1.949107 1.18631,-1.218321 -0.522262,-1.949109 z m -8.593957,2.338762 -1.195314,1.184718 0.522262,1.949107 1.195314,-1.184716 -0.522262,-1.949109 z m 4.337499,-1.018158 -1.18631,1.218323 0.432217,1.613056 1.18631,-1.218323 -0.432217,-1.613056 z m -8.593956,2.338763 -1.16171,1.175712 0.432217,1.613056 1.152705,-1.209318 -0.423212,-1.57945 z m 13.635401,-3.149341 0.261131,0.974553 0.248421,-0.282672 C 51.124502,49.08394 50.966383,48.85514 50.786319,48.627315 z m -40.364165,11.067671 -0.174619,0.154843 0.432217,1.613056 0.505846,-0.531741 c -0.279386,-0.394934 -0.53067,-0.804288 -0.763444,-1.236158 z m 29.275056,-7.556083 -1.419135,1.42478 0.522262,1.949108 1.428139,-1.391174 -0.531266,-1.982714 z m 8.602961,-2.305157 -1.41013,1.458385 0.513257,1.915503 1.419135,-1.424779 -0.522262,-1.949109 z M 9.7326848,60.347964 8.3135497,61.772743 8.7457669,63.385799 10.173906,61.994625 9.7326848,60.347964 z m 25.7416732,-6.897461 -1.419136,1.42478 0.432217,1.613056 1.419135,-1.424781 -0.432216,-1.613055 z m 8.569355,-2.296152 -1.419134,1.424779 0.432217,1.613057 1.428139,-1.391175 -0.441222,-1.646661 z m -10.827504,3.009276 c -0.0046,0.245127 -0.0022,0.483366 -0.02154,0.726133 l 0.165613,-0.188448 -0.144072,-0.537685 z m 18.458971,-4.369778 -0.44764,0.480125 0.432217,1.613056 0.787871,-0.823417 C 52.194092,50.635328 51.955417,50.201646 51.67518,49.793849 z m -13.902951,4.301574 -1.161709,1.175712 0.522262,1.949108 1.161709,-1.175712 -0.522262,-1.949108 z m 8.602962,-2.305156 -1.195316,1.184716 0.522262,1.949108 1.186311,-1.218322 -0.513257,-1.915502 z m 4.337498,-1.018158 -1.195314,1.184718 0.441221,1.646659 1.18631,-1.218322 -0.432217,-1.613055 z m -42.9049849,11.532375 -0.125417,0.06962 c -0.027907,0.674826 0.00787,1.360371 0.042783,2.041566 L 8.2399208,63.917539 7.8077041,62.304484 z m 25.7416719,-6.89746 -0.456644,0.44652 c -0.10047,0.621903 -0.256883,1.220038 -0.450526,1.813566 l 0.144072,0.537685 1.18631,-1.218322 -0.423212,-1.579449 z m 8.569356,-2.296152 -1.204318,1.151112 0.441221,1.646659 1.195314,-1.184717 -0.432217,-1.613054 z m -30.54482,8.328532 -0.705065,0.729192 0.522261,1.949108 1.16171,-1.175712 -0.153077,-0.57129 c -0.284683,-0.293438 -0.570662,-0.608229 -0.825829,-0.931298 z m -1.219916,1.227326 -1.4191343,1.424781 0.5222619,1.949108 1.4191354,-1.42478 -0.522263,-1.949109 z m 25.741673,-6.89746 -1.419135,1.42478 0.522262,1.949108 1.419135,-1.424779 -0.522262,-1.949109 z m 8.569356,-2.296152 -1.41013,1.458386 0.513257,1.915502 1.419135,-1.424779 -0.522262,-1.949109 z m 4.337498,-1.018157 -1.41013,1.458385 0.432217,1.613056 1.419135,-1.42478 -0.441222,-1.646661 z m -8.593956,2.338762 -1.419135,1.424779 0.432217,1.613057 1.419134,-1.424781 -0.432216,-1.613055 z m 12.378174,-3.136631 -0.928885,0.969255 0.513258,1.915502 1.25352,-1.23633 c -0.249728,-0.558508 -0.545759,-1.118305 -0.837893,-1.648427 z m -39.520973,11.526083 0.414208,1.545844 0.714071,-0.695587 c -0.390445,-0.258687 -0.769263,-0.547599 -1.128279,-0.850257 z m -4.8457568,1.40647 -0.646859,0.677579 c 0.064396,0.720367 0.1518557,1.433511 0.2894373,2.155565 l 0.8886882,-0.85043 -0.5312665,-1.982714 z m 25.7416718,-6.89746 -1.195315,1.184718 0.522262,1.949107 1.20432,-1.151112 -0.531267,-1.982713 z m 8.569356,-2.296152 -1.186309,1.218322 0.513257,1.915503 1.204319,-1.151112 -0.531267,-1.982713 z m 8.602962,-2.305157 -1.18631,1.218322 0.513258,1.915504 1.204318,-1.151112 -0.531266,-1.982714 z m -38.601093,10.523222 -1.161709,1.175713 0.432217,1.613055 1.170714,-1.142108 -0.441222,-1.64666 z m 25.741674,-6.89746 -1.16171,1.175713 0.432217,1.613054 1.170714,-1.142107 -0.441221,-1.64666 z m 8.602961,-2.305157 -1.195315,1.184718 0.432217,1.613054 1.195315,-1.184717 -0.432217,-1.613055 z m -14.824125,4.224238 c -0.01593,0.03765 -0.02389,0.08134 -0.0402,0.118826 l 0.05821,-0.05161 -0.01801,-0.06721 z m 0.207104,0.772923 -1.25352,1.236332 c -0.04927,0.07437 -0.105705,0.14876 -0.15661,0.222053 l 0.513258,1.915503 1.419135,-1.424779 -0.522263,-1.949109 z m 8.569356,-2.296152 -1.419135,1.424779 0.522263,1.949109 1.419134,-1.424779 -0.522262,-1.949109 z m 8.602962,-2.305157 -1.419135,1.424779 0.522262,1.949109 1.419135,-1.424779 -0.522262,-1.949109 z m -38.567487,10.514217 -1.428139,1.391175 0.441221,1.64666 1.419135,-1.424779 -0.432217,-1.613056 z m 25.741673,-6.89746 -1.42814,1.391175 0.441221,1.64666 1.419136,-1.42478 -0.432217,-1.613055 z m 8.569356,-2.296152 -1.428139,1.391175 0.441221,1.64666 1.419135,-1.424779 -0.432217,-1.613056 z m 8.477545,-2.235534 -1.302723,1.321552 0.441221,1.64666 1.419135,-1.424779 -0.144072,-0.537686 c -0.122462,-0.344034 -0.2754,-0.671033 -0.413561,-1.005747 z m -38.939559,10.469843 -1.054302,1.038878 0.531266,1.982713 1.419136,-1.424779 -0.342171,-1.277002 c -0.189223,-0.09925 -0.370192,-0.210796 -0.553929,-0.31981 z m 1.302896,0.695413 0.09905,0.369659 0.257425,-0.249068 c -0.116016,-0.04678 -0.242034,-0.0703 -0.356475,-0.120591 z m -2.863044,0.875205 -1.161709,1.175713 0.522262,1.949109 1.161709,-1.175714 -0.522262,-1.949108 z m 25.741673,-6.89746 -1.152705,1.209317 0.513258,1.915504 1.161709,-1.175714 -0.522262,-1.949107 z m 8.602962,-2.305157 -1.186311,1.218322 0.513258,1.915504 1.195315,-1.184718 -0.522262,-1.949108 z m 4.337498,-1.018157 -1.186309,1.218323 0.441221,1.64666 1.186309,-1.218323 -0.441221,-1.64666 z M 9.1313681,67.244465 8.2180792,68.137505 c 0.06532,0.289689 0.1475965,0.550838 0.2251128,0.840133 0.068354,0.255102 0.1303727,0.522294 0.2071039,0.772922 L 9.5635848,68.85752 9.1313681,67.244465 z M 30.571561,61.499583 c -0.356828,0.448638 -0.75809,0.855854 -1.177307,1.251928 l 0.459231,1.713872 1.195315,-1.184719 -0.477239,-1.781081 z m 4.301479,-1.152578 -1.195315,1.184718 0.432217,1.613054 1.195315,-1.184717 -0.432217,-1.613055 z m 8.569356,-2.296152 -1.195314,1.184717 0.432217,1.613055 1.195314,-1.184717 -0.432217,-1.613055 z m -26.222918,7.386591 -0.714069,0.695587 0.432217,1.613054 1.195315,-1.184717 -0.252127,-0.940949 c -0.22098,-0.06106 -0.444699,-0.109715 -0.661336,-0.182975 z m -5.541818,2.169268 -1.419134,1.42478 0.522262,1.949109 1.428139,-1.391175 -0.531267,-1.982714 z m 25.741673,-6.897461 -1.410131,1.458386 0.513258,1.915504 1.42814,-1.391175 -0.531267,-1.982715 z m 17.172317,-4.601308 -1.410129,1.458385 0.513257,1.915504 1.428139,-1.391175 -0.531267,-1.982714 z m -36.015895,9.686448 0.07204,0.268842 0.19922,-0.197453 c -0.09261,-0.0175 -0.179227,-0.05176 -0.271256,-0.07139 z m 27.421939,-7.347686 -1.419135,1.42478 0.513258,1.915503 1.428139,-1.391174 -0.522262,-1.949109 z m -30.007136,8.18446 -1.419135,1.42478 0.432217,1.613056 1.42814,-1.391175 -0.441222,-1.646661 z m 17.172317,-4.601309 -1.419135,1.424781 0.432217,1.613055 1.428139,-1.391175 -0.441221,-1.646661 z m 8.569356,-2.296152 -1.419135,1.424781 0.432217,1.613055 1.428139,-1.391175 -0.441221,-1.646661 z m 8.602961,-2.305156 -1.419135,1.42478 0.441222,1.64666 1.419134,-1.424779 -0.441221,-1.646661 z m -21.455788,5.821097 c -0.362299,0.303527 -0.742129,0.584795 -1.141935,0.846252 l -0.340232,0.343291 0.522262,1.949109 1.42814,-1.391175 -0.468235,-1.747477 z m -9.312852,2.747497 -0.738671,0.738198 0.522263,1.949109 1.428139,-1.391175 -0.333167,-1.243397 c -0.285691,-0.01577 -0.596661,-0.01699 -0.878564,-0.05273 z m 1.528482,0.05868 0.189095,0.705712 0.738671,-0.738199 c -0.313681,0.0242 -0.616551,0.03276 -0.927766,0.03249 z m 4.810386,-1.000795 c -0.140151,0.06034 -0.266567,0.162508 -0.409855,0.217874 l 0.04502,0.168027 0.364833,-0.385901 z m -2.695018,0.830182 0.396199,1.478634 1.42814,-1.391175 -0.144072,-0.537685 c -0.218378,0.07192 -0.43826,0.153449 -0.663103,0.213696 -0.346732,0.09291 -0.670138,0.175199 -1.017164,0.23653 z m -13.4577222,3.678022 -0.8886882,0.85043 c 0.2083439,0.613006 0.4397248,1.210458 0.6968803,1.794265 L 10.274942,71.51234 9.7526798,69.563232 z m 8.5693562,-2.296152 -1.195315,1.184718 0.513257,1.915502 0.06721,-0.01801 1.13711,-1.133103 -0.522262,-1.949108 z m 8.569356,-2.296152 -1.16171,1.175713 0.513257,1.915502 0.06721,-0.01801 1.103503,-1.124099 -0.522261,-1.949108 z m 8.60296,-2.305156 -1.195315,1.184717 0.513257,1.915503 0.06721,-0.01801 1.137109,-1.133103 -0.522262,-1.949108 z m 17.172317,-4.601309 -1.195314,1.184718 0.522262,1.949107 1.195314,-1.184717 -0.522262,-1.949108 z m -8.593957,2.338762 -1.204318,1.151112 0.513257,1.915503 0.06721,-0.01801 1.137109,-1.133103 -0.513258,-1.915503 z m 4.328495,-1.051762 -1.195315,1.184717 0.450226,1.680266 1.18631,-1.218323 -0.441221,-1.64666 z m -34.33563,9.236222 -1.170714,1.142108 0.441222,1.646661 1.161709,-1.175714 -0.432217,-1.613055 z m 8.602961,-2.305156 -1.204319,1.151112 0.441221,1.646661 1.195315,-1.184719 -0.432217,-1.613054 z m 8.569357,-2.296153 -1.20432,1.151113 0.441221,1.646661 1.195316,-1.184719 -0.432217,-1.613055 z m 8.569355,-2.296151 -1.170714,1.142107 0.441222,1.646661 1.161709,-1.175714 -0.432217,-1.613054 z m -23.19538,7.259706 -1.419135,1.424781 0.162081,0.604895 c 0.100985,-0.05316 0.220969,-0.05921 0.336053,-0.09005 l 1.344213,-0.360181 -0.423212,-1.57945 z m 8.602961,-2.305156 -1.419135,1.42478 0.162081,0.604896 1.680267,-0.450226 -0.423213,-1.57945 z m 8.569355,-2.296152 -1.41013,1.458386 0.153077,0.57129 1.680266,-0.450226 -0.423213,-1.57945 z m 17.172318,-4.601309 -1.41013,1.458386 0.153076,0.57129 0.806528,-0.216108 c 0.342878,-0.09187 0.651309,-0.05658 0.954779,0.06833 l -0.504253,-1.881898 z m -8.593957,2.338763 -1.419135,1.42478 0.153077,0.57129 1.680266,-0.450226 -0.414208,-1.545844 z m -29.97353,8.175455 -1.419134,1.424781 0.432217,1.613055 1.419134,-1.424781 -0.432217,-1.613055 z m 8.569356,-2.296152 -1.419134,1.424781 0.117058,0.436868 1.680266,-0.450226 -0.37819,-1.411423 z m 8.569356,-2.296152 -1.419135,1.424781 0.117059,0.436868 1.680266,-0.450226 -0.37819,-1.411423 z m 8.602961,-2.305157 -1.419135,1.424782 0.117058,0.436868 1.680267,-0.450226 -0.37819,-1.411424 z m 8.569356,-2.296152 -1.419134,1.424782 0.117058,0.436867 1.680266,-0.450225 -0.37819,-1.411424 z m 8.544755,-2.253542 -1.360928,1.373167 0.441221,1.646659 1.152705,-1.209317 c -0.04622,-0.610934 -0.134328,-1.197792 -0.232998,-1.810509 z m -40.566917,12.058469 -1.161709,1.175713 0.522262,1.949109 0.68947,-0.652978 -0.153077,-0.57129 c -0.126204,-0.471001 7.12e-4,-0.930958 0.265136,-1.295657 l -0.162082,-0.604897 z m 8.602962,-2.305156 -0.398439,0.394905 0.470475,-0.126063 -0.07204,-0.268842 z m 8.569356,-2.296152 -0.364833,0.385901 0.436869,-0.117059 -0.07204,-0.268842 z m 17.172317,-4.601309 -0.364833,0.385901 0.436869,-0.117058 -0.07204,-0.268843 z m -8.593957,2.338762 -0.340233,0.343292 0.403264,-0.108055 -0.06303,-0.235237 z m -29.97353,8.175456 -0.622258,0.634969 c 0.217477,0.456 0.434455,0.894051 0.680637,1.330382 l 0.382842,-0.318691 -0.441221,-1.64666 z m 8.569356,-2.296152 -0.141013,0.145838 0.168026,-0.04502 -0.02701,-0.100815 z m 8.569356,-2.296152 -0.141013,0.145838 0.168026,-0.04502 -0.02701,-0.100815 z m 8.60296,-2.305157 -0.141013,0.145839 0.168027,-0.04502 -0.02701,-0.100816 z m 8.569356,-2.296152 -0.141012,0.145838 0.168026,-0.04502 -0.02701,-0.100816 z m 8.602961,-2.305156 -1.195313,1.184717 0.207103,0.772922 0.234118,0.873738 1.195314,-1.184717 -0.441222,-1.64666 z m -40.358692,11.89462 -1.428139,1.391175 0.531265,1.982709 1.419136,-1.424775 -0.522262,-1.949109 z m 42.515552,-11.103862 -1.020696,1.029875 0.52226,1.949102 0.456646,-0.446513 c 0.06462,-0.834666 0.07352,-1.686628 0.04179,-2.532464 z M 11.076344,74.503212 10.843519,74.70967 c 0.139763,0.231452 0.319261,0.441865 0.466942,0.66728 l -0.234117,-0.873738 z m 42.913989,-11.498768 -1.186309,1.218321 0.522261,1.949106 1.186309,-1.218322 -0.522261,-1.949105 z m -39.082336,11.012351 -0.680465,0.686583 0.432217,1.613057 0.680466,-0.686582 -0.432218,-1.613058 z m -1.195315,1.184719 -1.419136,1.424777 0.06303,0.235242 c 0.255635,0.328728 0.485738,0.636179 0.758618,0.949302 l 1.038707,-0.962659 -0.441222,-1.646662 z m 41.644872,-10.186223 -0.141013,0.145836 0.09005,0.336055 c 0.0241,-0.16474 0.03055,-0.31645 0.05097,-0.481891 z m -0.655864,0.643973 -1.195314,1.184718 0.441222,1.646662 0.987089,-1.020873 c 0.03721,-0.155386 0.09327,-0.310064 0.127183,-0.466296 l -0.36018,-1.344211 z m -39.172382,10.676294 -0.680466,0.686582 0.522263,1.949113 1.103504,-1.1241 C 16.102003,77.653875 15.80009,77.34613 15.682386,76.906856 l -0.153078,-0.571297 z m -1.195315,1.184719 -0.763272,0.780804 c 0.39765,0.431059 0.798073,0.82161 1.227328,1.219922 l 0.05821,-0.05161 -0.522263,-1.949113 z m 38.864634,-9.405244 c -0.200355,0.259912 -0.449818,0.444695 -0.792696,0.536568 l -0.806528,0.216109 0.414209,1.545848 1.410128,-1.458391 -0.225113,-0.840134 z m -35.943858,9.955294 0.405204,1.512244 1.419134,-1.424788 -0.144072,-0.537682 -1.344213,0.360181 c -0.115084,0.03084 -0.222019,0.08559 -0.336053,0.09005 z m 2.285162,-0.612307 0.05403,0.201637 0.282025,-0.291683 -0.336053,0.09005 z m 2.016319,-0.540272 0.450226,1.680267 1.419135,-1.424777 -0.189096,-0.705715 -1.680265,0.450225 z m 2.285161,-0.612307 0.09905,0.36966 0.539451,-0.540746 -0.638501,0.171086 z m 2.016319,-0.540271 0.405205,1.512244 1.419133,-1.424787 -0.144071,-0.537683 -1.680267,0.450226 z m 2.285162,-0.612307 0.05403,0.201637 0.282025,-0.291682 -0.336054,0.09004 z m 1.982714,-0.531267 0.450226,1.680267 1.419135,-1.424777 -0.189096,-0.705715 -1.680265,0.450225 z m 2.285161,-0.612307 0.09905,0.36966 0.539452,-0.540746 -0.638502,0.171086 z m 2.016319,-0.540271 0.414209,1.545849 1.419132,-1.424787 -0.153075,-0.571287 -1.680266,0.450225 z m 2.285161,-0.612307 0.06303,0.235242 0.340232,-0.343296 -0.403265,0.108054 z m 2.016319,-0.540271 0.450226,1.680267 1.419137,-1.424778 -0.189096,-0.705715 -1.680267,0.450226 z m 2.285162,-0.612307 0.09905,0.36966 0.53945,-0.540746 -0.6385,0.171086 z m 1.982714,-0.531267 0.414209,1.545849 1.419132,-1.424787 -0.153076,-0.571287 -1.680265,0.450225 z m 2.285162,-0.612307 0.06303,0.235242 0.340229,-0.343296 -0.403262,0.108054 z m 2.016319,-0.540271 0.45923,1.713871 1.419136,-1.424777 -0.1981,-0.73932 -1.680266,0.450226 z m 2.285161,-0.612307 0.09905,0.36966 0.539451,-0.540746 -0.638501,0.171086 z m -28.604717,7.772662 -1.195314,1.184719 0.513258,1.915508 1.204319,-1.151114 -0.522263,-1.949113 z m 8.569356,-2.296152 -1.161709,1.175714 0.513259,1.915509 1.170713,-1.14211 -0.522263,-1.949113 z m 8.60296,-2.305156 -1.195314,1.184719 0.513259,1.915508 1.204319,-1.151114 -0.522264,-1.949113 z m 8.569356,-2.296152 -1.186309,1.218323 0.513259,1.915508 1.195314,-1.184718 -0.522264,-1.949113 z m -30.007133,8.184467 -1.161709,1.175714 0.189093,0.705705 c 0.214273,0.178473 0.387276,0.35082 0.607956,0.52145 l 0.805882,-0.756207 -0.441222,-1.646662 z m 8.602961,-2.305157 -1.195314,1.184719 0.432214,1.613048 1.204322,-1.151105 -0.441222,-1.646662 z m 8.569357,-2.296152 -1.195316,1.184719 0.44122,1.646652 1.204322,-1.151104 -0.450226,-1.680267 z m 8.569355,-2.296152 -1.161709,1.175714 0.441219,1.646653 1.170716,-1.1421 -0.450226,-1.680267 z m 8.602961,-2.305156 -1.18631,1.218323 0.432215,1.613048 1.195317,-1.184709 -0.441222,-1.646662 z m 3.517786,-0.582416 -0.447639,0.480128 0.144074,0.537692 c 0.116139,-0.330894 0.202775,-0.681866 0.303565,-1.01782 z m -0.96249,0.978265 -1.419135,1.424777 0.522263,1.949113 0.141014,-0.145837 c 0.382886,-0.719825 0.730277,-1.432221 1.034997,-2.186293 l -0.279139,-1.04176 z m -34.335629,9.236221 -1.428141,1.391173 0.522264,1.949113 1.419136,-1.42478 -0.513259,-1.915506 z m 8.602961,-2.305157 -1.42814,1.391174 0.522263,1.949112 1.419136,-1.424777 -0.513259,-1.915509 z m 8.569355,-2.296151 -1.428139,1.391173 0.522263,1.949112 1.419135,-1.424777 -0.513259,-1.915508 z m 8.569356,-2.296152 -1.419135,1.424777 0.513259,1.915508 1.428139,-1.391172 -0.522263,-1.949113 z m -21.404175,5.8793 -1.428137,1.391183 0.44122,1.646653 1.419135,-1.424778 -0.432218,-1.613058 z m 8.569356,-2.296152 -1.428137,1.391183 0.450226,1.680266 1.419133,-1.424787 -0.441222,-1.646662 z m 8.602962,-2.305156 -1.428138,1.391182 0.450226,1.680267 1.419133,-1.424787 -0.441221,-1.646662 z m 8.578362,-2.262538 -1.428139,1.391173 0.441222,1.646662 1.419132,-1.424787 -0.432215,-1.613048 z m 2.313467,0.568699 -1.18631,1.218323 0.522263,1.949112 1.18631,-1.218323 -0.522263,-1.949112 z m -34.33563,9.236223 -0.456643,0.44652 c 0.235943,0.17204 0.466314,0.33126 0.708769,0.49443 l -0.252126,-0.94095 z m 8.602961,-2.305158 -1.195314,1.184718 0.513258,1.91551 1.195315,-1.18472 -0.513259,-1.915508 z m 8.569357,-2.296153 -1.195316,1.184719 0.513259,1.915508 1.195316,-1.184718 -0.513259,-1.915509 z m 8.569355,-2.296151 -1.152705,1.209318 0.513259,1.915508 1.161709,-1.175714 -0.522263,-1.949112 z m -21.404175,5.8793 -1.195314,1.184722 0.432217,1.61305 1.195315,-1.18471 -0.432218,-1.613062 z m 8.569356,-2.296152 -1.161709,1.175714 0.441222,1.646662 1.161709,-1.175714 -0.441222,-1.646662 z m 8.602961,-2.305156 -1.195315,1.184718 0.441222,1.646662 1.195314,-1.184718 -0.441221,-1.646662 z m 8.578362,-2.262538 -1.195316,1.184709 0.432217,1.613057 1.195314,-1.184718 -0.432215,-1.613048 z m -23.19538,7.259705 -1.419136,1.424773 0.513259,1.91551 1.428137,-1.39118 -0.52226,-1.949103 z m 8.569356,-2.296152 -1.419136,1.424777 0.513259,1.915508 1.428137,-1.391182 -0.52226,-1.949103 z m 8.602961,-2.305157 -1.410132,1.458382 0.513259,1.915509 1.419134,-1.424788 -0.522261,-1.949103 z m 8.569356,-2.296152 -1.419136,1.424778 0.522264,1.949112 1.419132,-1.424787 -0.52226,-1.949103 z M 19.970555,81.48471 18.934262,82.5908 c 0.429888,0.24941 0.856871,0.47298 1.302895,0.69542 l 0.17462,-0.15484 -0.441222,-1.64667 z m 8.602961,-2.305153 -1.419136,1.424777 0.441222,1.646666 1.42814,-1.39118 -0.450226,-1.680263 z m 8.569355,-2.296152 -1.419135,1.424777 0.441221,1.646662 1.42814,-1.391173 -0.450226,-1.680266 z m 8.57836,-2.262548 -1.419135,1.424778 0.432217,1.613057 1.42814,-1.391173 -0.441222,-1.646662 z m -23.410194,7.533383 -1.204319,1.15111 0.117059,0.43687 c 0.444778,0.19669 0.91894,0.39769 1.376697,0.56758 l 0.223819,-0.24007 -0.513256,-1.91549 z m 8.569356,-2.296157 -1.170714,1.142107 0.522261,1.94911 1.161709,-1.17572 -0.513256,-1.915497 z m 8.60296,-2.305156 -1.195315,1.184718 0.513257,1.915499 1.204321,-1.151104 -0.522263,-1.949113 z m 8.569356,-2.296152 -1.204318,1.151114 0.522261,1.949103 1.20432,-1.151104 -0.522263,-1.949113 z m -21.404175,5.879305 -1.204319,1.15111 0.450226,1.68027 1.195315,-1.18472 -0.441222,-1.64666 z m 8.569357,-2.296157 -1.20432,1.151114 0.450226,1.680263 1.195316,-1.184715 -0.441222,-1.646662 z m 8.578359,-2.262547 -1.170713,1.142109 0.441222,1.646662 1.161709,-1.175714 -0.432218,-1.613057 z m 7.74788,-1.463724 -0.349237,0.309681 0.02701,0.100814 c 0.09969,-0.140033 0.225699,-0.268515 0.322224,-0.410495 z m -22.340296,6.418278 -1.419137,1.42478 0.513257,1.9155 1.419136,-1.42478 -0.513256,-1.9155 z m 8.569355,-2.296148 -1.419136,1.424777 0.522261,1.949101 1.419135,-1.42478 -0.52226,-1.949098 z m 8.569355,-2.296152 -1.419135,1.424777 0.522261,1.949103 1.419135,-1.424777 -0.522261,-1.949103 z m -21.404174,5.8793 -1.419136,1.42478 0.117059,0.43687 c 0.394597,0.12628 0.776933,0.26212 1.179247,0.36837 l 0.564052,-0.58336 -0.441222,-1.64666 z m 8.569356,-2.296152 -1.419136,1.424782 0.441222,1.64666 1.419135,-1.42478 -0.441221,-1.646662 z m 8.611965,-2.271552 -1.419136,1.424778 0.432217,1.613056 1.419137,-1.424776 -0.432218,-1.613058 z m 8.569356,-2.296152 -1.419135,1.424778 0.117059,0.436869 c 0.477746,-0.522483 0.928752,-1.10114 1.356102,-1.660019 l -0.05403,-0.201628 z m -23.419199,7.499776 -1.195315,1.18472 0.189093,0.7057 c 0.438297,0.08759 0.884162,0.19249 1.329264,0.25614 l 0.199218,-0.19746 -0.52226,-1.9491 z m 8.569356,-2.29615 -1.186311,1.21832 0.513256,1.9155 1.195316,-1.18472 -0.522261,-1.9491 z m 8.569355,-2.296156 -1.161709,1.175714 0.522261,1.949102 1.161709,-1.17571 -0.522261,-1.949106 z m -12.834819,3.583146 -1.161709,1.17572 0.441222,1.64666 1.170714,-1.14211 -0.450227,-1.68027 z m 8.611965,-2.27155 -1.195314,1.18472 0.432217,1.61306 1.204319,-1.15112 -0.441222,-1.64666 z m 8.569356,-2.296152 -1.195314,1.184719 0.108055,0.403264 c 0.406645,-0.365398 0.834514,-0.728004 1.213322,-1.117509 l -0.126063,-0.470474 z m -23.186376,7.293312 -0.05821,0.05161 c 0.02091,0.0049 0.04628,-0.02281 0.06721,-0.01801 l -0.009,-0.0336 z m 17.172317,-4.601311 -1.428138,1.391181 0.396198,1.47863 c 0.421481,-0.19782 0.832645,-0.40094 1.23857,-0.62002 l 0.315633,-0.30068 -0.522263,-1.949111 z m -8.593957,2.338761 -1.428137,1.39118 0.387193,1.44503 c 0.232467,-0.01947 0.466108,-0.05312 0.69912,-0.07928 l 0.855083,-0.84142 -0.513259,-1.91551 z m -4.240859,1.2444 -1.428141,1.39117 0.04502,0.16802 c 0.598027,0.06253 1.183809,0.07812 1.790735,0.09647 l 0.03361,-0.009 -0.441222,-1.64666 z m 8.578359,-2.26255 -1.42814,1.39117 0.441222,1.64666 1.419135,-1.42477 -0.432217,-1.61306 z m 8.569356,-2.296152 -1.42814,1.391172 0.03602,0.13442 c 0.512616,-0.370138 1.012852,-0.750913 1.491173,-1.155932 l -0.09905,-0.36966 z m -6.246885,2.898452 -1.195315,1.18472 0.153079,0.5713 c 0.462149,-0.17092 0.920198,-0.35074 1.366399,-0.54622 l -0.324163,-1.2098 z m -8.593954,2.33877 -1.029702,0.99627 c 0.424597,-0.0025 0.854389,-0.03061 1.281828,-0.05532 l -0.252126,-0.94095 z m 4.337499,-1.01816 -1.195316,1.18472 0.117059,0.43687 c 0.476116,-0.08601 0.943997,-0.22979 1.420428,-0.34458 l -0.342171,-1.27701 z m 2.54629,0.36225 -0.456643,0.44652 c 0.172308,-0.05482 0.367383,-0.08585 0.537685,-0.14407 l -0.08104,-0.30245 z"
+ style="fill:url(#linearGradient9381-884-21);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:url(#linearGradient9387-409-257);stroke-width:0.98900002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ d="M 24.181711,34.829499 C 8.3491555,39.071819 -1.0696913,55.385741 3.1726293,71.218296 7.4149504,87.05085 23.719868,96.4361 39.552423,92.19378 c 7.139562,-1.91304 13.40581,-5.99898 16.829626,-11.92921 1.221572,-2.115832 1.910004,-4.262321 2.58291,-6.491002 L 114.58176,58.871092 c 0.44818,-0.12009 0.88922,-0.274388 1.27459,-0.485595 1.2698,-0.347821 2.43319,-1.213112 3.18156,-2.509333 l 6.55941,-11.410429 c 1.42099,-2.461247 0.78707,-5.482553 -1.45585,-6.777501 l -8.42774,-4.837355 c -0.19377,0.335622 -0.48546,0.598313 -0.89111,0.707007 l -1.27699,0.342169 -3.66445,-2.115667 c -0.72741,-0.419968 -1.66357,-0.169123 -2.08354,0.558283 l -1.50723,2.709017 -4.04793,-2.337077 c -0.20325,-0.117339 -0.44281,-0.165733 -0.66134,-0.182974 -0.0746,-0.0103 -0.14303,-0.01426 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10071,0.0061 -0.17642,0.01125 -0.27784,0.03843 l -3.831004,1.026515 c -0.05689,0.01525 -0.10553,0.05759 -0.159019,0.07863 -0.431007,0.07151 -0.831501,0.308563 -1.068135,0.718423 l -2.844687,4.976346 -6.922696,1.854931 -4.985351,-2.878294 c -0.727392,-0.41996 -1.663564,-0.169113 -2.083529,0.55828 L 77.473785,41.764576 73.6389,39.550505 c -0.727393,-0.419959 -1.663575,-0.169111 -2.08353,0.55828 l -3.410506,5.956373 -3.427743,0.91846 c -0.811293,0.21739 -1.62384,-0.28014 -1.841227,-1.091439 L 62.245557,43.539808 C 61.89324,42.224935 60.867705,42.000045 59.920026,42.253975 L 53.4342,43.991847 c -1.020929,-1.373074 -2.138582,-2.665496 -3.339338,-3.859613 -0.0411,-0.04087 -0.09554,-0.06675 -0.136832,-0.107408 -7.075365,-5.443729 -16.493832,-7.682563 -25.776319,-5.195327 z m -5.308547,10.715083 c 4.491338,-1.203447 9.099126,1.428453 10.302575,5.919788 1.20345,4.491335 -1.453052,9.141735 -5.944389,10.345185 -4.491335,1.203446 -9.117134,-1.495664 -10.320584,-5.986999 -1.203448,-4.491332 1.471063,-9.074525 5.962398,-10.277974 z"
+ id="path3416"
+ sodipodi:nodetypes="cssscccccccccccccsssccsccccccccccccccscccsssc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:0.65163933;fill:none;stroke:url(#radialGradient9389-453-398);stroke-width:1.48899996;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ d="M 24.181711,34.829499 C 8.3491555,39.071819 -1.0696913,55.385741 3.1726293,71.218296 L 125.59732,44.465735 c 1.42099,-2.461247 0.91648,-4.99959 -1.32644,-6.294538 l -8.42774,-4.837355 c -0.19377,0.335622 -0.48546,0.598313 -0.89111,0.707007 l -1.27699,0.342169 -3.66445,-2.115668 c -0.72741,-0.419967 -1.66357,-0.169122 -2.08354,0.558283 l -1.50723,2.709017 -4.04793,-2.337076 c -0.20326,-0.117339 -0.44281,-0.165733 -0.66134,-0.182974 -0.0746,-0.0103 -0.14304,-0.01425 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10071,0.0061 -0.17642,0.01125 -0.27784,0.03843 l -3.831005,1.026515 c -0.05689,0.01525 -0.105529,0.05759 -0.159018,0.07863 -0.431007,0.07152 -0.831501,0.308563 -1.068136,0.718423 l -2.844687,4.976346 -6.922696,1.854931 -4.98535,-2.878294 c -0.727392,-0.41996 -1.663565,-0.169113 -2.08353,0.55828 l -1.648274,2.85486 -3.834884,-2.214071 c -0.727394,-0.419959 -1.663575,-0.169111 -2.08353,0.55828 l -3.410507,5.956372 -3.427742,0.918461 c -0.811294,0.21739 -1.623841,-0.28014 -1.841228,-1.091439 L 62.374967,44.022771 C 62.02265,42.707898 60.997115,42.483008 60.049435,42.736938 L 53.4342,43.991847 c -1.020929,-1.373074 -2.138582,-2.665496 -3.339338,-3.859613 -0.0411,-0.04087 -0.09554,-0.06675 -0.136832,-0.107408 -7.075365,-5.443729 -16.493832,-7.682563 -25.776319,-5.195327 z m -5.308547,10.715083 c 4.491338,-1.203447 9.099126,1.428453 10.302575,5.919788 1.20345,4.491335 -1.453052,9.141735 -5.944389,10.345185 -4.491335,1.203446 -9.117134,-1.495664 -10.320584,-5.986999 -1.203448,-4.491332 1.471063,-9.074525 5.962398,-10.277974 z"
+ id="path3418"
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ id="path3420"
+ d="M 24.181711,34.829499 C 8.3491555,39.071819 -1.0696913,55.385741 3.1726293,71.218296 L 125.59732,44.465735 c 1.42099,-2.461247 0.78707,-5.482553 -1.45585,-6.777501 l -8.42774,-4.837355 c -0.19377,0.335622 -0.48546,0.598313 -0.89111,0.707007 l -1.27699,0.342169 -3.66445,-2.115667 c -0.72741,-0.419968 -1.66357,-0.169123 -2.08354,0.558283 l -1.50723,2.709017 -4.04793,-2.337077 c -0.20325,-0.117339 -0.44281,-0.165733 -0.66134,-0.182974 -0.0746,-0.0103 -0.14303,-0.01426 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10071,0.0061 -0.17642,0.01125 -0.27784,0.03843 l -3.831004,1.026515 c -0.05689,0.01525 -0.10553,0.05759 -0.159019,0.07863 -0.431007,0.07151 -0.831501,0.308563 -1.068135,0.718423 l -2.844687,4.976346 -6.922696,1.854931 -4.985351,-2.878294 c -0.727392,-0.41996 -1.663564,-0.169113 -2.083529,0.55828 L 77.473785,41.764576 73.6389,39.550505 c -0.727393,-0.419959 -1.663575,-0.169111 -2.08353,0.55828 l -3.410506,5.956373 -3.427743,0.91846 c -0.811293,0.21739 -1.62384,-0.28014 -1.841227,-1.091439 L 62.245557,43.539808 C 61.89324,42.224935 60.867705,42.000045 59.920026,42.253975 L 53.4342,43.991847 c -1.020929,-1.373074 -2.138582,-2.665496 -3.339338,-3.859613 -0.0411,-0.04087 -0.09554,-0.06675 -0.136832,-0.107408 -7.075365,-5.443729 -16.493832,-7.682563 -25.776319,-5.195327 z m -5.308547,10.715083 c 4.491338,-1.203447 9.099126,1.428453 10.302575,5.919788 1.20345,4.491335 -1.453052,9.141735 -5.944389,10.345185 -4.491335,1.203446 -9.117134,-1.495664 -10.320584,-5.986999 -1.203448,-4.491332 1.471063,-9.074525 5.962398,-10.277974 z"
+ style="opacity:0.84836067;fill:none;stroke:url(#radialGradient9391-502-67);stroke-width:0.58899999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ id="path3422"
+ d="M 24.207593,34.926091 C 8.3750374,39.168412 -1.0438094,55.482333 3.1985112,71.314889 L 125.6232,44.562328 c 1.421,-2.461247 0.78707,-5.482554 -1.45585,-6.777502 l -8.42774,-4.837354 c -0.19376,0.335621 -0.48545,0.598313 -0.8911,0.707007 l -1.277,0.342169 -3.66444,-2.115668 c -0.72742,-0.419967 -1.66358,-0.169122 -2.08355,0.558283 l -1.50723,2.709017 -4.04793,-2.337077 c -0.20325,-0.117338 -0.44281,-0.165732 -0.66134,-0.182973 -0.0746,-0.0103 -0.14303,-0.01425 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10072,0.0061 -0.17642,0.01125 -0.27785,0.03843 L 97.211317,33.698 c -0.05689,0.01524 -0.105529,0.05759 -0.159018,0.07863 -0.431007,0.07152 -0.831501,0.308562 -1.068135,0.718422 l -2.844687,4.976347 -6.922696,1.85493 -4.985351,-2.878293 c -0.727392,-0.41996 -1.663564,-0.169114 -2.083529,0.558279 l -1.648254,2.854859 -3.834885,-2.214072 c -0.727393,-0.419958 -1.663575,-0.16911 -2.08353,0.558281 l -3.410506,5.956372 -3.427743,0.918461 c -0.811293,0.21739 -1.62384,-0.280141 -1.841227,-1.091439 l -0.630317,-2.352373 c -0.352317,-1.314873 -1.377852,-1.539763 -2.325531,-1.285833 l -6.485826,1.737872 C 52.439153,42.715369 51.3215,41.422947 50.120744,40.22883 50.079644,40.18796 50.025204,40.16208 49.983912,40.121422 42.908547,34.677692 33.49008,32.438858 24.207593,34.926094 z m -5.308548,10.715083 c 4.491339,-1.203446 9.099127,1.428453 10.302576,5.919788 1.20345,4.491336 -1.453052,9.141736 -5.944389,10.345186 -4.491335,1.203445 -9.117134,-1.495665 -10.320584,-5.986999 -1.203449,-4.491332 1.471063,-9.074525 5.962397,-10.277975 z"
+ style="fill:none;stroke:url(#radialGradient9393-641-971);stroke-width:0.78899997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3424"
+ d="M 91.298643,57.955932 C 75.567573,62.171059 63.30463,68.559534 62.055745,72.941419 L 114.57796,58.868133 c 0.44818,-0.120089 0.91043,-0.26541 1.2958,-0.476617 1.2698,-0.347811 2.42308,-1.235901 3.17145,-2.532113 l 0.70711,-1.224744 c -6.01448,-0.956253 -16.69278,0.169949 -28.453677,3.321273 z"
+ style="opacity:0.63934428;fill:url(#radialGradient9395-67-109);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3426"
+ d="M 65.606555,54.914486 125.19038,38.949047"
+ style="fill:none;stroke:url(#radialGradient9397-309-349);stroke-width:0.214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:url(#radialGradient9399-429-605);stroke-width:0.65574688;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 66.900716,59.300518 126.48455,43.335079"
+ id="path3428"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:0.20901639;fill:url(#linearGradient9401-82-291);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="M 24.181711,34.829499 C 8.3491555,39.071819 -1.0696913,55.385741 3.1726293,71.218296 7.4149504,87.05085 23.719868,96.4361 39.552423,92.19378 c 7.139562,-1.91304 12.970506,-6.2726 16.829626,-11.92921 0.02791,-0.04092 0.04609,-0.08679 0.0738,-0.127838 0.04438,-0.08645 0.103958,-0.168818 0.147605,-0.255654 0.982551,-1.954801 1.764428,-3.990666 2.361504,-6.10751 L 114.58176,58.871092 c 0.44818,-0.12009 0.88922,-0.274388 1.27459,-0.485595 1.2698,-0.347821 2.43319,-1.213112 3.18156,-2.509333 l 6.55941,-11.410429 c 1.42099,-2.461247 0.78707,-5.482553 -1.45585,-6.777501 l -8.42774,-4.837355 c -0.19377,0.335622 -0.48546,0.598313 -0.89111,0.707007 l -1.27699,0.342169 -3.66445,-2.115667 c -0.72741,-0.419968 -1.66357,-0.169123 -2.08354,0.558283 l -1.50723,2.709017 -4.04793,-2.337077 c -0.20325,-0.117339 -0.44281,-0.165733 -0.66134,-0.182974 -0.0746,-0.0103 -0.14303,-0.01426 -0.21964,-0.01319 -0.0239,0.0017 -0.0435,0.01522 -0.0672,0.01801 -0.10071,0.0061 -0.17642,0.01125 -0.27784,0.03843 l -3.831004,1.026515 c -0.05689,0.01525 -0.10553,0.05759 -0.159019,0.07863 -0.431007,0.07151 -0.831501,0.308563 -1.068135,0.718423 l -2.844687,4.976346 -6.922696,1.854931 -4.985351,-2.878294 c -0.727392,-0.41996 -1.663564,-0.169113 -2.083529,0.55828 L 77.473785,41.764576 73.6389,39.550505 c -0.727393,-0.419959 -1.663575,-0.169111 -2.08353,0.55828 l -3.410506,5.956373 -3.427743,0.91846 c -0.811293,0.21739 -1.62384,-0.28014 -1.841227,-1.091439 L 62.245557,43.539808 C 61.89324,42.224935 60.867705,42.000045 59.920026,42.253975 L 53.4342,43.991847 c -1.020929,-1.373074 -2.138582,-2.665496 -3.339338,-3.859613 -0.0411,-0.04087 -0.09554,-0.06675 -0.136832,-0.107408 -7.075365,-5.443729 -16.493832,-7.682563 -25.776319,-5.195327 z m -5.308547,10.715083 c 4.491338,-1.203447 9.099126,1.428453 10.302575,5.919788 1.20345,4.491335 -1.453052,9.141735 -5.944389,10.345185 -4.491335,1.203446 -9.117134,-1.495664 -10.320584,-5.986999 -1.203448,-4.491332 1.471063,-9.074525 5.962398,-10.277974 z"
+ id="path3539"
+ sodipodi:nodetypes="cssssscccccccccccccsssccsccccccccccccccscccsssc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ transform="matrix(6.6950206,0,0,6.196426,74.186626,-7.802551)"
+ d="m 27.75,58.75 c 0,9.664983 -7.835017,17.5 -17.5,17.5 -9.66498312,0 -17.5,-7.835017 -17.5,-17.5 0,-9.664983 7.83501688,-17.5 17.5,-17.5 9.664983,0 17.5,7.835017 17.5,17.5 z"
+ sodipodi:ry="17.5"
+ sodipodi:rx="17.5"
+ sodipodi:cy="58.75"
+ sodipodi:cx="10.25"
+ id="path3527"
+ style="opacity:0.32786889;fill:url(#radialGradient9403-685-582);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ style="fill:#cfcfcf;fill-opacity:0.75688076;fill-rule:nonzero;stroke:none"
+ d="m 214.13666,113.01803 0,-10.83772 0,10.83772 z"
+ id="path2276"
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cssssscccccccccccccsssccsccccccccccccccscccsssc"
+ id="path1969"
+ d="m 134.80965,272.29143 c -63.563591,0 -115.218772,51.65518 -115.218772,115.21877 0,63.56361 51.655181,115.08388 115.218772,115.08388 28.6635,0 54.88066,-10.47761 75.01365,-27.79281 0.14542,-0.12527 0.25983,-0.27883 0.40475,-0.40478 0.25284,-0.27922 0.55885,-0.52803 0.80948,-0.80949 5.64244,-6.33613 10.61458,-13.17732 14.97575,-20.50732 l 223.28695,0 c 1.79933,0 3.60625,-0.13535 5.26175,-0.53966 5.10554,-0.0271 10.33184,-2.10192 14.4361,-6.20617 l 36.02273,-36.15766 c 7.79308,-7.79311 8.45097,-19.74659 1.34914,-26.84838 l -26.71347,-26.57859 c -1.06266,1.06271 -2.41894,1.75391 -4.04752,1.75391 l -5.12679,0 -11.60284,-11.6028 c -2.30322,-2.30322 -6.06169,-2.30322 -8.36487,0 l -8.3648,8.63463 -12.81706,-12.81706 c -0.64359,-0.64355 -1.49235,-1.06523 -2.29361,-1.34917 -0.26913,-0.11363 -0.52147,-0.19701 -0.80948,-0.26991 -0.0911,-0.0194 -0.17839,0.0116 -0.26991,0 -0.38352,-0.0779 -0.67212,-0.13496 -1.0793,-0.13496 l -15.3805,0 c -0.22841,0 -0.45309,0.10975 -0.67457,0.13496 -1.68624,-0.16481 -3.42433,0.32109 -4.72209,1.619 l -15.65032,15.78524 -27.79281,0 -15.78524,-15.78524 c -2.30315,-2.30315 -6.06165,-2.30315 -8.36484,0 l -9.0394,9.03941 -12.14249,-12.1425 c -2.30314,-2.30315 -6.06169,-2.30315 -8.36484,0 l -18.75341,18.88833 -13.76149,0 c -3.25713,3e-5 -5.8014,-2.67915 -5.8014,-5.93631 l 0,-9.44419 c 0,-5.27885 -3.61571,-7.15058 -7.42041,-7.15058 l -26.03893,0 c -2.44605,-6.16794 -5.33539,-12.13085 -8.63467,-17.80897 -0.11284,-0.19429 -0.29083,-0.34592 -0.40474,-0.53966 -21.03906,-27.49258 -54.07172,-45.332 -91.3385,-45.332 z m -30.63933,34.80848 c 18.03154,3e-5 32.64982,14.48337 32.64982,32.5149 0,18.03157 -14.61828,32.78473 -32.64982,32.78473 -18.031537,0 -32.649817,-14.7532 -32.649817,-32.78473 0,-18.03153 14.61828,-32.5149 32.649817,-32.5149 z"
+ style="fill:url(#linearGradient3643);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(2.9251696,0,0,2.9251696,20.00345,226.93235)"
+ d="m 68,65.25 c 0,16.016258 -12.983742,29 -29,29 -16.016258,0 -29,-12.983742 -29,-29 0,-16.016258 12.983742,-29 29,-29 16.016258,0 29,12.983742 29,29 z"
+ sodipodi:ry="29"
+ sodipodi:rx="29"
+ sodipodi:cy="65.25"
+ sodipodi:cx="39"
+ id="path3187"
+ style="opacity:0.41393445;fill:url(#radialGradient9409-380-91);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ style="fill:none;stroke:url(#linearGradient3639);stroke-width:3.83528376;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ d="m 134.80965,272.29143 c -63.563591,0 -115.218772,51.65518 -115.218772,115.21877 0,63.56361 51.655181,115.08388 115.218772,115.08388 28.6635,0 56.23662,-9.01579 75.01365,-27.79281 6.69938,-6.69943 11.43253,-14.04878 16.18998,-21.72159 l 223.28695,0 c 1.79933,0 3.60625,-0.13535 5.26175,-0.53966 5.10554,-0.0271 10.33184,-2.10192 14.4361,-6.20617 l 36.02273,-36.15766 c 7.79308,-7.79311 8.45097,-19.74659 1.34914,-26.84838 l -26.71347,-26.57859 c -1.06266,1.06271 -2.41894,1.75391 -4.04752,1.75391 l -5.12679,0 -11.60284,-11.6028 c -2.30322,-2.30322 -6.06169,-2.30322 -8.36487,0 l -8.3648,8.63463 -12.81706,-12.81706 c -0.64359,-0.64355 -1.49235,-1.06523 -2.29361,-1.34917 -0.26913,-0.11363 -0.52147,-0.19701 -0.80948,-0.26991 -0.0911,-0.0194 -0.17839,0.0116 -0.26991,0 -0.38352,-0.0779 -0.67212,-0.13496 -1.0793,-0.13496 l -15.3805,0 c -0.22841,0 -0.45309,0.10975 -0.67457,0.13496 -1.68624,-0.16481 -3.42433,0.32109 -4.72209,1.619 l -15.65032,15.78524 -27.79281,0 -15.78524,-15.78524 c -2.30315,-2.30315 -6.06165,-2.30315 -8.36484,0 l -9.0394,9.03941 -12.14249,-12.1425 c -2.30314,-2.30315 -6.06169,-2.30315 -8.36484,0 l -18.75341,18.88833 -13.76149,0 c -3.25713,3e-5 -5.8014,-2.67915 -5.8014,-5.93631 l 0,-9.44419 c 0,-5.27885 -3.61571,-7.15058 -7.42041,-7.15058 l -26.03893,0 c -2.44605,-6.16794 -5.33539,-12.13085 -8.63467,-17.80897 -0.11284,-0.19429 -0.29083,-0.34592 -0.40474,-0.53966 -21.03906,-27.49258 -54.07172,-45.332 -91.3385,-45.332 z m -30.63933,34.80848 c 18.03154,3e-5 32.64982,14.48337 32.64982,32.5149 0,18.03157 -14.61828,32.78473 -32.64982,32.78473 -18.031537,0 -32.649817,-14.7532 -32.649817,-32.78473 0,-18.03153 14.61828,-32.5149 32.649817,-32.5149 z"
+ id="path3142"
+ sodipodi:nodetypes="cssscccccccccccccsssccsccccccccccccccscccsssc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3636);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 242.77448,335.95694 c -0.0779,0.38353 -0.13185,0.78012 -0.13185,1.18727 l 0,33.7717 c 0,3.25725 2.54726,5.93643 5.8045,5.93643 l 251.44088,0 -20.18386,-20.05193 c -1.06268,1.06271 -2.46102,1.71498 -4.08957,1.71498 l -5.14494,0 -11.60901,-11.60905 c -2.30318,-2.30318 -6.00782,-2.30318 -8.31096,0 l -8.44294,8.57487 -12.79631,-12.79631 c -0.64355,-0.64355 -1.44144,-1.0353 -2.24269,-1.3192 -0.26913,-0.11363 -0.50344,-0.1908 -0.79145,-0.2637 -0.0911,-0.0194 -0.17218,0.0116 -0.26409,0 -0.38353,-0.0779 -0.78004,-0.13185 -1.18723,-0.13185 l -15.30279,0 c -0.2284,0 -0.43816,0.10664 -0.65963,0.13185 -1.68625,-0.16481 -3.45136,0.28542 -4.74912,1.58305 l -15.69856,15.83046 -27.70335,0 -15.8305,-15.83046 c -2.30315,-2.30319 -6.00782,-2.30319 -8.311,0 l -9.10255,9.1025 -12.13667,-12.13668 c -2.30319,-2.30318 -6.00785,-2.30318 -8.31101,0 l -18.86466,18.86464 -13.71978,0 c -3.25711,3e-5 -5.8045,-2.67927 -5.8045,-5.93644 l 0,-9.49828 c 0,-5.27888 -3.58287,-7.12369 -7.38755,-7.12369 l -18.46889,0 z"
+ id="path2944"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path2900"
+ d="m 264.54702,389.12099 c -3.2572,0 -19.92567,0.0116 -19.92567,7.21243 l 0,2.39319 c 0,6.74552 16.32818,7.676 19.58542,7.676 l 243.43813,0 c 3.43097,-5.40271 4.07126,-11.83295 1.97876,-17.28162 l -245.07664,0 z"
+ style="fill:url(#linearGradient3633);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:url(#linearGradient3630);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 264.54702,397.56393 c -3.2572,0 -19.92567,-5.67929 -19.92567,0.13068 l 0,1.03207 c 0,6.65994 16.32818,7.676 19.58542,7.676 l 243.86029,0 c 3.43096,-5.4027 4.07125,-11.83291 1.97875,-17.28161 L 264.54702,397.564 z"
+ id="path2915"
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path2927"
+ d="m 242.77448,335.95694 c -0.0779,0.38353 -0.13185,0.78012 -0.13185,1.18727 l 0,33.7717 c 0,3.25725 2.54726,5.93643 5.8045,5.93643 l 251.44088,0 -20.18386,-20.05193 c -1.06268,1.06271 -2.46102,1.71498 -4.08957,1.71498 l -5.14494,0 -11.60901,-11.60905 c -2.30318,-2.30318 -6.00782,-2.30318 -8.31096,0 l -8.44294,8.57487 -12.79631,-12.79631 c -0.64355,-0.64355 -1.44144,-1.0353 -2.24269,-1.3192 -0.26913,-0.11363 -0.50344,-0.1908 -0.79145,-0.2637 -0.0911,-0.0194 -0.17218,0.0116 -0.26409,0 -0.38353,-0.0779 -0.78004,-0.13185 -1.18723,-0.13185 l -15.30279,0 c -0.2284,0 -0.43816,0.10664 -0.65963,0.13185 -1.68625,-0.16481 -3.45136,0.28542 -4.74912,1.58305 l -15.69856,15.83046 -27.70335,0 -15.8305,-15.83046 c -2.30315,-2.30319 -6.00782,-2.30319 -8.311,0 l -9.10255,9.1025 -12.13667,-12.13668 c -2.30319,-2.30318 -6.00785,-2.30318 -8.31101,0 l -18.86466,18.86464 -13.71978,0 c -3.25711,3e-5 -5.8045,-2.67927 -5.8045,-5.93644 l 0,-9.49828 c 0,-5.27888 -3.58287,-7.12369 -7.38755,-7.12369 l -18.46889,0 z"
+ style="fill:url(#linearGradient3627);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path2967"
+ d="m 129.68283,295.49711 c -1.13283,0.055 -2.25111,0.31139 -3.37292,0.40474 l 0,2.96817 5.66652,-3.238 0,-0.13495 c -0.76088,0.0194 -1.53736,-0.0388 -2.2936,0 z m 7.28548,0 -2.56339,1.48404 0,7.82519 6.74583,-3.77767 0,-5.26174 c -1.39474,-0.0947 -2.77153,-0.235 -4.18244,-0.26991 z m 6.61092,0.53965 0,3.50783 5.12684,-2.96818 c -1.7179,-0.25323 -3.37952,-0.37771 -5.12684,-0.53965 z m -19.6978,0.13495 c -1.17751,0.12797 -2.33211,0.21872 -3.50783,0.40474 1.21794,0.44996 2.3396,1.0735 3.50783,1.619 l 0,-2.02374 z m 28.60229,1.07931 -0.80948,0.40478 0,6.47596 6.74584,-3.91257 0,-1.619 c -1.95988,-0.49769 -3.92816,-0.97293 -5.93636,-1.34917 z m -20.50729,1.21426 -3.64278,2.02374 c 1.25254,0.75795 2.47005,1.56064 3.64278,2.42853 l 0,-4.45227 z m 17.26929,0.67457 -5.66649,3.10309 0,6.61092 5.66649,-3.37292 0,-6.34109 z m 14.4361,0.80952 -2.83326,1.619 0,7.9601 5.53157,-3.23801 0,-5.39666 c -0.91694,-0.32109 -1.76815,-0.65029 -2.69831,-0.94443 z m 5.12683,1.75391 0,3.10309 3.10309,-1.75391 c -1.02179,-0.43041 -2.06256,-0.95328 -3.10309,-1.34918 z m -10.38857,1.34918 -6.74584,3.91257 0,7.82518 6.74584,-3.91261 0,-7.82514 z m -17.26933,0.67456 -4.857,2.83327 c 1.39272,1.31206 2.68776,2.71064 3.91257,4.18239 l 0.94443,-0.53965 0,-6.47601 z m 33.59421,0.5397 -5.93631,3.37287 0,6.47602 6.74583,-3.91258 0,-5.53157 c -0.30054,-0.14194 -0.50712,-0.26564 -0.80952,-0.40474 z m 3.238,1.61896 0,2.96818 2.69836,-1.61901 c -0.87482,-0.47958 -1.80604,-0.89623 -2.69836,-1.34917 z m -28.73724,2.42853 -5.66649,3.238 0,3.50783 c 0.68244,1.04707 1.28973,2.13554 1.88883,3.238 l 3.77766,-2.02379 0,-7.96004 z m 33.99899,0.2699 -5.26175,2.96817 0,7.82515 5.66649,-3.10309 0,-7.42041 c -0.15822,-0.0943 -0.24586,-0.17644 -0.40474,-0.2699 z m -16.86458,0.40474 -5.53157,3.238 0,6.476 5.53157,-3.238 0,-6.476 z m 19.69785,1.48409 0,4.31731 3.50783,-2.02374 c -1.12147,-0.78761 -2.34903,-1.55359 -3.50783,-2.29357 z m -10.5235,2.5634 -6.74583,3.77769 0,7.96005 6.74583,-3.91257 0,-7.82517 z m -17.1344,0.6746 -6.74584,3.77766 0,6.61092 6.74584,-4.04753 0,-6.34105 z m 33.18947,0.67457 -5.53157,3.10309 0,6.61092 6.74583,-4.04753 0,-4.85696 c -0.39485,-0.30403 -0.81417,-0.51154 -1.21426,-0.80952 z m 3.64274,2.83326 0,1.48408 1.07935,-0.6746 c -0.36453,-0.31063 -0.70962,-0.50409 -1.07935,-0.80948 z m -28.87216,1.0793 -5.53157,3.23801 0,7.82518 5.53157,-3.238 0,-7.82519 z m -17.13441,0.67461 -2.69831,1.48409 c 0.8091,1.68648 1.41704,3.47146 2.02374,5.26175 l 0.67457,-0.40475 0,-6.34109 z m 34.40373,0 -5.66649,3.238 0,6.47598 5.66649,-3.37289 0,-6.34109 z m 14.57102,0.80949 -2.96818,1.75391 0,7.82518 5.66649,-3.37291 0,-3.77767 c -0.84621,-0.82278 -1.81945,-1.63753 -2.69831,-2.42851 z m -39.80039,3.10309 -6.74584,3.91257 0,7.82517 6.74584,-3.77765 0,-7.96009 z m 34.40373,0 -6.74583,3.91257 0,7.82517 6.74583,-3.77765 0,-7.96009 z m -17.26933,0.6746 -6.74583,3.91257 0,6.47601 6.74583,-3.91261 0,-6.47597 z m 29.41182,2.96814 -1.61901,0.94443 0,6.47601 5.39667,-3.10309 c -1.1953,-1.50809 -2.4865,-2.88639 -3.77766,-4.31731 z m -21.31685,1.75392 -5.66649,3.10308 0,7.9601 5.66649,-3.238 0,-7.82518 z m 17.26933,0.53968 -5.66649,3.238 0,6.61089 5.66649,-3.37291 0,-6.47598 z m -34.53865,0.13496 -5.53157,3.10304 0,6.61093 5.53157,-3.37291 0,-6.34106 z m 43.71301,3.77766 -6.74585,4.04748 0,7.82518 6.74585,-4.04752 0,-7.82514 z m -34.53866,0.13495 -6.74583,3.91257 0,7.82514 6.74583,-3.91257 0,-7.82514 z m -17.1344,0.67457 -6.74584,3.91257 0,6.476 6.74584,-3.91256 0,-6.47601 z m 34.40373,0 -6.74583,3.91257 0,6.476 6.74583,-3.91256 0,-6.47601 z m 19.69781,2.29356 0,3.50784 1.619,-1.07931 c -0.52318,-0.82084 -1.06907,-1.62537 -1.619,-2.42849 z m -46.14149,2.29361 -5.53157,3.23801 0,7.82514 5.53157,-3.10309 0,-7.96006 z m 34.53865,0 -5.66649,3.23801 0,7.82514 5.66649,-3.238 0,-7.82515 z m -145.844824,0.2699 c -0.561833,0.88526 -1.223799,1.79317 -1.753909,2.69832 l 1.753909,-1.07931 0,-1.61901 z m 128.575494,0.40475 -5.66649,3.23801 0,6.476 5.66649,-3.238 0,-6.47601 z m 31.70542,1.619 -2.83325,1.61901 0,6.476 5.66652,-3.238 c -0.8545,-1.65914 -1.87595,-3.25798 -2.83327,-4.85697 z m -160.280914,2.42853 -3.912609,2.15865 c -1.041339,2.01179 -1.949863,4.11186 -2.833223,6.20617 l 0,3.37293 6.745832,-3.91258 0,-7.82517 z m 103.346124,0 -6.74584,3.77765 0,7.9601 6.74584,-3.91258 0,-7.82517 z m 34.40373,0 -6.74583,3.77765 0,7.9601 6.74583,-3.91258 0,-7.82517 z m 17.26933,0.53965 -6.74585,3.91261 0,6.61091 6.74585,-4.04752 0,-6.476 z m -34.53866,0.13495 -6.74583,3.7777 0,6.61087 6.74583,-4.04748 0,-6.34109 z m -118.05204,3.91261 0,1.75391 0.26991,-0.13494 c -0.09457,-0.53156 -0.193118,-1.08149 -0.26991,-1.61901 z m 160.6857,0.53965 -5.66652,3.37292 0,7.82514 5.66652,-3.37287 0,-7.82519 z m -34.53869,0.13496 -5.66649,3.238 0,7.82515 5.66649,-3.23798 0,-7.82517 z m 17.26937,0.53965 -5.66653,3.37291 0,6.47601 5.66653,-3.37292 0,-6.476 z m -34.53869,0.13495 -5.53157,3.23801 0,6.476 5.53157,-3.37291 0,-6.3411 z m 54.23649,1.88884 0,3.91261 1.21426,-0.80953 c -0.40578,-1.05321 -0.76844,-2.06896 -1.21426,-3.10305 z m -162.304661,0.94443 -0.809519,0.40474 0,6.476 2.428484,-1.48409 c -0.650095,-1.75973 -1.180522,-3.54533 -1.618965,-5.39665 z m 117.242521,1.0793 -6.74583,3.91261 0,7.82515 6.74583,-3.77766 0,-7.9601 z m 34.53866,0 -6.74585,4.04752 0,7.69024 6.74585,-3.91257 0,-7.82519 z m -155.019184,0.67461 -6.745832,3.91257 0,6.47601 6.745832,-3.77766 0,-6.61092 z m 103.346124,0 -6.74584,3.91257 0,6.47601 6.74584,-3.91258 0,-6.476 z m 34.40373,0 -6.74583,3.91257 0,6.47601 6.74583,-3.77766 0,-6.61092 z m -43.57809,0.40436 c -0.26331,0.91356 -0.49319,1.80843 -0.80948,2.69834 l 0.80948,-0.5397 0,-2.15864 z m 73.52956,2.15864 -2.15866,1.34918 0,6.47601 3.77766,-2.29357 c -0.51983,-1.85878 -0.97859,-3.72278 -1.619,-5.53162 z m -56.39515,2.1587 -5.53157,3.23796 0,7.82519 5.53157,-3.238 0,-7.82515 z m 34.53869,0 -5.66653,3.23796 0,7.82519 5.66653,-3.37291 0,-7.69024 z m 17.26932,0.53966 -5.66652,3.238 0,6.61092 5.66652,-3.37292 0,-6.476 z m -172.288531,0.13495 -0.539662,0.13496 c -0.781824,2.49975 -1.335908,5.10355 -1.888822,7.69022 l 2.428484,-1.34913 0,-6.47601 z m 103.346111,0 -2.15866,1.21426 c -1.00051,2.22865 -2.18676,4.31219 -3.50783,6.34106 l 0,2.15865 5.66649,-3.37292 0,-6.34105 z m 34.40373,0 -5.66649,3.10309 0,6.61088 5.66649,-3.23796 0,-6.47601 z m -122.774094,0.53965 -3.372916,2.02375 0,7.82517 5.531574,-3.238 0,-2.29357 c -0.77183,-1.38489 -1.527097,-2.85106 -2.158658,-4.31731 z m -5.8014,3.37292 -6.745832,3.91258 0,7.82517 6.745832,-3.91257 0,-7.82518 z m 103.346124,0 -6.74584,3.91258 0,7.82517 6.74584,-3.91257 0,-7.82518 z m 34.40373,0 -6.74583,4.04749 0,7.69026 6.74583,-3.91257 0,-7.82518 z m 17.26933,0.53966 -6.74585,4.04752 0,6.47601 6.74585,-3.91261 0,-6.61092 z m -34.53866,0.13494 -6.74583,3.91261 0,6.47598 6.74583,-3.91258 0,-6.47601 z m 49.5144,0.67461 -4.45226,2.69831 0,7.69027 5.93632,-3.37291 c -0.375,-2.34271 -0.92186,-4.73672 -1.48409,-7.01567 z m -159.60634,3.50783 0,6.20615 3.372916,-1.88883 c -1.202904,-1.36085 -2.331883,-2.82326 -3.372916,-4.31728 z m -19.562931,0.40478 -3.103058,1.88883 c -0.481826,2.763 -0.869971,5.52208 -1.079345,8.36484 l 4.182403,-2.29361 0,-7.96006 z m 103.346111,0 -5.66649,3.238 0,7.82515 5.66649,-3.10309 0,-7.96006 z m 34.40373,0 -5.66649,3.37292 0,7.69023 5.66649,-3.10309 0,-7.96006 z m 34.53869,0 -5.66652,3.37292 0,7.69023 5.66652,-3.10309 0,-7.96006 z m -155.154126,0.67457 -5.531574,3.23801 0,6.476 5.531574,-3.10309 0,-6.61092 z m 103.346116,0 -5.53157,3.23801 0,6.476 5.53157,-3.10309 0,-6.61092 z m 34.53869,0 -5.66653,3.23801 0,6.476 5.66653,-3.238 0,-6.47601 z m -59.76807,0.94444 c -0.0973,0.12525 -0.17101,0.28075 -0.2699,0.40473 l 0.2699,-0.13495 0,-0.2699 z m 0,3.10304 -5.93635,3.37292 c -0.25905,0.22918 -0.54524,0.45116 -0.80948,0.67461 l 0,7.69023 6.74583,-3.91257 0,-7.82519 z m 34.40373,0 -6.74583,3.91261 0,7.82515 6.74583,-3.91257 0,-7.82519 z m 34.53866,0 -6.74585,3.91261 0,7.82515 6.74585,-3.91257 0,-7.82519 z m -155.019184,0.67461 -6.745832,3.77766 0,6.61092 6.745832,-3.91257 0,-6.47601 z m 103.346124,0 -6.74584,3.77766 0,6.61092 6.74584,-3.91257 0,-6.47601 z m 34.40373,0 -6.74583,3.77766 0,6.61092 6.74583,-3.91257 0,-6.47601 z m 33.99899,0.13496 -6.20618,3.64274 0,6.61092 6.74583,-3.91257 0,-2.1587 c -0.11323,-1.41156 -0.35792,-2.78995 -0.53965,-4.18239 z m -156.368348,0.13495 -4.991912,2.83322 0,7.96009 6.745831,-3.91256 0,-5.12684 c -0.609189,-0.56167 -1.175092,-1.16117 -1.753919,-1.75391 z m 4.182403,3.91257 0,1.48408 1.214258,-0.67456 c -0.387797,-0.29162 -0.836044,-0.50631 -1.214258,-0.80952 z m -11.602841,0.40474 -5.531574,3.238 0,7.82519 5.531574,-3.23801 0,-7.82518 z m 103.346116,0 -5.53157,3.37291 0,7.69028 5.53157,-3.23801 0,-7.82518 z m 34.53869,0 -5.66653,3.37291 0,7.69028 5.66653,-3.23801 0,-7.82518 z m 17.26932,0.53969 -5.66652,3.37292 0,6.61088 5.66652,-3.37291 0,-6.61089 z m -172.288531,0.13495 -4.317316,2.42849 c -0.04618,1.15066 0,2.21147 0,3.37291 0,1.02417 -0.0349,2.08727 0,3.10309 l 4.317316,-2.42852 0,-6.47597 z m 86.076821,0 c -1.78692,1.32234 -3.69866,2.44497 -5.66652,3.50783 l 0,6.88075 5.66652,-3.238 0,-7.15058 z m 17.26929,0 -5.66649,3.23801 0,6.47596 5.66649,-3.238 0,-6.47597 z m 34.40373,0 -5.66649,3.23801 0,6.47596 5.66649,-3.238 0,-6.47597 z m -105.639679,1.34914 -3.372916,1.88887 0,6.47596 5.666487,-3.238 0,-3.77766 c -0.766442,-0.4505 -1.555636,-0.85729 -2.293571,-1.34917 z m -22.935815,2.56343 -6.745832,3.91258 0,7.82518 6.745832,-3.77766 0,-7.9601 z m 103.346124,0 -6.74584,4.04749 0,7.69027 6.74584,-3.77766 0,-7.9601 z m 68.94237,0 -6.74583,4.04749 0,7.69027 6.74583,-3.77766 0,-7.9601 z m -144.630593,0.13496 0,1.07931 0.944401,-0.53966 c -0.329244,-0.1586 -0.619385,-0.37383 -0.944401,-0.53965 z m 110.091953,0 -6.74583,3.91256 0,7.69028 6.74583,-3.7777 0,-7.82514 z m -120.615439,0.53965 -6.745831,3.91258 0,6.476 6.745831,-3.77766 0,-6.61092 z m 68.942379,0 -6.74583,3.91258 0,6.476 6.74583,-3.77766 0,-6.61092 z m 34.40373,0 -6.74583,3.91258 0,6.476 6.74583,-3.77766 0,-6.61092 z m 34.53866,0 -6.74585,3.91258 0,6.61091 6.74585,-3.91257 0,-6.61092 z m -86.21171,0.26991 c -1.66174,0.77334 -3.36683,1.44565 -5.12684,2.02374 l -1.61899,0.94444 0,7.82513 6.74583,-3.77765 0,-7.01566 z m -37.641733,0.94443 -3.50784,2.02375 0,7.82513 6.745843,-3.77765 0,-4.99192 c -1.054338,-0.34592 -2.21795,-0.66247 -3.238003,-1.07931 z m 5.666476,1.75392 0,2.83322 3.507839,-2.02374 c -1.199256,-0.22415 -2.342362,-0.49611 -3.507839,-0.80948 z m 19.023247,1.0793 c -0.58553,0.0853 -1.1616,0.34126 -1.75392,0.40478 l 0,0.67457 1.75392,-1.07935 z m -10.92823,0.40478 0,5.93632 6.74582,-3.77766 0,-2.15866 c -0.89018,0.0501 -1.79563,0.13496 -2.69834,0.13496 -1.39203,0 -2.68605,-0.0155 -4.04748,-0.13496 z m -54.101581,0.2699 -4.182403,2.29357 c 0.165201,2.50531 0.432202,4.97548 0.809487,7.42041 l 3.372916,-1.88883 0,-7.82515 z m 34.403733,0 -5.666487,3.23797 0,7.69027 0.2699,0 5.396661,-3.10309 0,-7.82515 z m 34.403728,0 -5.53157,3.23797 0,7.69027 0.26991,0 5.26174,-3.10309 0,-7.82515 z m 34.53865,0 -5.66649,3.23797 0,7.69027 0.26991,0 5.39665,-3.10309 0,-7.82515 z m 68.94242,0 -5.66652,3.23797 0,7.82518 5.66652,-3.238 0,-7.82515 z m -34.53869,0.13496 -5.66649,3.10305 0,7.69027 0.26991,0 5.39667,-3.10309 0,-7.69023 z m 17.26937,0.40474 -5.66653,3.238 0,6.74584 5.66653,-3.37291 0,-6.61093 z m -137.884806,0.13495 -5.531574,3.10309 0,6.61089 5.531574,-3.238 0,-6.47598 z m 34.538646,0 -5.666487,3.10309 0,6.61089 5.666487,-3.238 0,-6.47598 z m 34.40377,0 -5.66652,3.10309 0,6.61089 5.66652,-3.238 0,-6.47598 z m 34.4037,0 -5.53157,3.10309 0,6.61089 5.53157,-3.238 0,-6.47598 z m -94.171759,3.91258 -6.745831,3.91257 0,2.42851 c 0.431611,-0.0977 0.887112,0 1.34917,0 l 5.396661,0 0,-6.34108 z m 34.538639,0 -6.74582,3.91257 0,2.42851 6.74582,0 0,-6.34108 z m 34.40374,0 -6.74583,4.04748 0,2.2936 6.74583,0 0,-6.34108 z m 68.94239,0 -6.74585,4.04748 0,2.2936 3.23801,0 c 1.37656,0 2.49647,0.44174 3.50784,1.21423 l 0,-7.55531 z m -34.53866,0.13494 -6.74583,3.91258 0,2.2936 6.74583,0 0,-6.20618 z m -120.480524,0.53967 -6.745832,3.9126 0,6.47597 6.745832,-3.91257 0,-6.476 z m 34.403744,0 -6.745843,3.9126 0,1.75391 6.745843,0 0,-5.66651 z m 34.40373,0 -6.74583,3.9126 0,1.75391 6.74583,0 0,-5.66651 z m 34.53865,0 -6.74584,3.9126 0,1.75391 6.74584,0 0,-5.66651 z m 34.40373,0 -6.74583,3.9126 0,1.75391 6.74583,0 0,-5.66651 z m 34.26882,0.13494 -6.47601,3.7777 0,6.61088 5.53158,-3.37291 c 0.44006,-2.33484 0.69903,-4.6215 0.94443,-7.01567 z m -164.058616,4.45227 -5.531574,3.238 0,7.82514 3.238003,-1.75391 0,-2.29357 c 0,-1.89096 0.937073,-3.48646 2.293571,-4.58717 l 0,-2.42849 z m 34.538646,0 -1.888822,1.0793 1.888822,0 0,-1.0793 z m 34.40377,0 -1.75395,1.0793 1.75395,0 0,-1.0793 z m 68.94239,0 -1.75392,1.0793 1.75392,0 0,-1.0793 z m -34.53869,0.13495 -1.619,0.9444 1.619,0 0,-0.9444 z m -120.480521,0.53966 -2.968146,1.75391 c 0.356781,1.92637 0.730029,3.78499 1.214226,5.66648 l 1.75392,-0.80947 0,-6.61092 z m 34.403733,0 -0.674575,0.40474 0.674575,0 0,-0.40474 z m 34.403728,0 -0.67456,0.40474 0.67456,0 0,-0.40474 z m 34.53865,0 -0.67457,0.40474 0.67457,0 0,-0.40474 z m 34.40373,0 -0.67456,0.40474 0.67456,0 0,-0.40474 z m 34.53869,0 -5.66652,3.238 0,3.10309 0,3.50783 5.66652,-3.238 0,-6.61092 z m -163.114184,4.04748 -6.745832,3.77769 0,7.96006 6.745832,-3.91258 0,-7.82517 z m 170.399674,1.07934 -4.85701,2.83327 0,7.82514 2.15866,-1.21422 c 1.07981,-3.06164 1.96825,-6.24399 2.69835,-9.44419 z m -179.574021,4.18248 -1.079313,0.53965 c 0.291237,1.00727 0.7524,1.97559 1.079313,2.96818 l 0,-3.50783 z m 172.288491,0 -5.66648,3.37292 0,7.82514 5.66648,-3.37292 0,-7.82514 z m -157.447657,2.02374 -3.238003,1.88883 0,6.476 3.238003,-1.88882 0,-6.47601 z m -5.666487,3.23801 -6.745832,3.91257 0,0.94443 c 0.627608,1.48793 1.180954,2.87053 1.888833,4.31731 l 4.856999,-2.56339 0,-6.61092 z m 166.217234,3.64274 -0.67457,0.40474 0,1.34918 c 0.25556,-0.5929 0.43209,-1.1547 0.67457,-1.75392 z m -3.10309,1.75392 -5.66648,3.238 0,6.61092 4.72209,-2.83326 c 0.29549,-0.5447 0.66056,-1.06784 0.94439,-1.61901 l 0,-5.39665 z m -157.447657,0.67456 -3.238003,1.88884 0,7.82517 5.261748,-3.10309 c -1.201691,-1.09796 -2.023745,-2.55374 -2.023745,-4.3173 l 0,-2.29362 z m -5.666487,3.23801 -3.642741,2.15865 c 1.056857,2.01378 2.164783,3.8786 3.372915,5.80144 l 0.26991,-0.13495 0,-7.82519 z m 155.019184,3.77765 c -1.01137,0.77249 -2.13128,1.21427 -3.50784,1.21427 l -3.23801,0 0,6.20617 6.74585,-4.04752 0,-3.37292 z m -144.6306,1.21427 0,6.07126 6.745831,-3.91261 0,-2.15865 -5.396703,0 c -0.462016,0 -0.917517,0.0977 -1.349128,0 z m 9.174315,0 0,0.80952 1.349171,-0.80952 -1.349171,0 z m 8.095002,0 0,6.74583 6.745843,-3.91258 0,-2.83325 -6.745843,0 z m 9.174316,0 0,1.48408 2.563439,-1.48408 -2.563439,0 z m 8.095017,0 0,6.07126 6.74582,-3.91261 0,-2.15865 -6.74582,0 z m 9.17431,0 0,0.80952 1.34917,-0.80952 -1.34917,0 z m 7.9601,0 0,6.74583 6.74583,-3.91258 0,-2.83325 -6.74583,0 z m 9.17431,0 0,1.48408 2.56343,-1.48408 -2.56343,0 z m 8.09501,0 0,6.20617 6.74583,-3.91261 0,-2.29356 -6.74583,0 z m 9.17431,0 0,0.94443 1.61901,-0.94443 -1.61901,0 z m 8.09501,0 0,6.74583 6.74584,-3.91258 0,-2.83325 -6.74584,0 z m 9.17432,0 0,1.48408 2.56343,-1.48408 -2.56343,0 z m 7.96009,0 0,6.20617 6.74583,-3.91261 0,-2.29356 -6.74583,0 z m 9.17431,0 0,0.94443 1.61901,-0.94443 -1.61901,0 z m 8.09502,0 0,6.88074 6.74583,-3.91257 0,-2.96817 -6.74583,0 z m 9.17431,0 0,1.48408 2.56344,-1.48408 -2.56344,0 z m -114.948948,0.40474 -5.666487,3.238 0,7.69026 5.666487,-3.10309 0,-7.82517 z m 34.403728,0 -5.53157,3.238 0,7.69026 5.53157,-3.10309 0,-7.82517 z m 34.53865,0 -5.66649,3.238 0,7.69026 5.66649,-3.10309 0,-7.82517 z m 34.40373,0 -5.66649,3.37291 0,7.69027 5.66649,-3.23801 0,-7.82517 z m -120.615436,0.53969 -5.531574,3.238 0,2.83323 c 0.623496,0.88359 1.098543,1.70279 1.75392,2.56343 l 3.777654,-2.02374 0,-6.61092 z m 34.538646,0 -5.666487,3.238 0,6.47597 5.666487,-3.10305 0,-6.61092 z m 34.40374,0 -5.66649,3.238 0,6.61088 5.66649,-3.10305 0,-6.74583 z m 34.40373,0 -5.53157,3.238 0,6.61088 5.53157,-3.10305 0,-6.74583 z m 34.53865,0 -5.66649,3.37292 0,6.47596 5.66649,-3.23796 0,-6.61092 z m 13.76149,1.34913 -2.15865,1.34918 0,2.15869 c 0.76717,-1.1229 1.44395,-2.35061 2.15865,-3.50787 z m -4.58713,2.69835 -6.74585,3.91258 0,7.82518 0.67458,-0.40474 c 2.15672,-2.31203 4.17297,-4.63186 6.07127,-7.15062 l 0,-4.1824 z m -137.884769,0.13496 -6.745831,3.77765 0,7.82519 6.745831,-3.91258 0,-7.69026 z m 34.538639,0 -6.74582,3.77765 0,7.82519 6.74582,-3.91258 0,-7.69026 z m 34.40374,0 -6.74583,3.77765 0,7.82519 6.74583,-3.91258 0,-7.69026 z m 34.40373,0 -6.74583,3.91256 0,7.69028 6.74583,-3.77767 0,-7.82517 z m -86.07678,0.53965 -6.745843,3.77769 0,6.61089 6.745843,-3.91258 0,-6.476 z m 34.40373,0 -6.74583,3.77769 0,6.74584 6.74583,-3.91261 0,-6.61092 z m 34.53865,0 -6.74584,3.77769 0,6.74584 6.74584,-3.91261 0,-6.61092 z m 34.40373,0.13495 -6.74583,3.77766 0,6.61092 6.74583,-3.91261 0,-6.47597 z m 8.09497,4.45223 -5.66649,3.37292 0,7.82517 5.66649,-3.37291 0,-7.82518 z m -137.884766,0.13495 -2.158658,1.21426 c 0.711136,0.88122 1.414249,1.70885 2.158658,2.5634 l 0,-3.77766 z m 34.538646,0 -5.666487,3.238 0,7.69027 5.666487,-3.238 0,-7.69027 z m 34.40374,0 -5.66649,3.238 0,7.69027 5.66649,-3.238 0,-7.69027 z m 34.40373,0 -5.53157,3.37291 0,7.69028 5.53157,-3.23801 0,-7.82518 z m -86.076788,0.53966 -5.666487,3.238 0,6.47601 5.666487,-3.23801 0,-6.476 z m 34.403728,0 -5.53157,3.238 0,6.61092 5.53157,-3.238 0,-6.61092 z m 34.53865,0 -5.66649,3.238 0,6.61092 5.66649,-3.238 0,-6.61092 z m 34.40373,0.13494 -5.66649,3.23797 0,6.47601 5.66649,-3.238 0,-6.47598 z m -94.17175,3.91258 -6.745843,3.91257 0,7.69026 6.745843,-3.7777 0,-7.82513 z m 34.40373,0 -6.74583,3.91257 0,7.69026 6.74583,-3.7777 0,-7.82513 z m 34.53865,0 -6.74584,4.04748 0,7.69026 6.74584,-3.91261 0,-7.82513 z m 34.40373,0 -6.74583,3.91257 0,7.82517 6.74583,-3.91261 0,-7.82513 z m -120.615439,0.53965 -4.991922,3.10309 c 1.359955,1.36569 2.734955,2.63169 4.182403,3.91257 l 0.809519,-0.40474 0,-6.61092 z m 34.538639,0 -6.74582,3.91257 0,6.61092 6.74582,-3.77766 0,-6.74583 z m 34.40374,0 -6.74583,3.91257 0,6.61092 6.74583,-3.77766 0,-6.74583 z m 34.40373,0.13496 -6.74583,3.91256 0,6.47601 6.74583,-3.77766 0,-6.61091 z m -95.251138,4.72208 -5.666487,3.10309 0,1.75392 c 1.468649,1.1832 3.043019,2.412 4.587174,3.50783 l 1.079313,-0.67461 0,-7.69023 z m 34.403728,0 -5.53157,3.10309 0,7.82515 5.53157,-3.23801 0,-7.69023 z m 34.53865,0 -5.66649,3.23801 0,7.69023 5.66649,-3.10305 0,-7.82519 z m 34.40373,0 -5.66649,3.10309 0,7.82515 5.66649,-3.10305 0,-7.82519 z m -86.07679,0.53965 -5.666487,3.10309 0,6.74585 5.666487,-3.23801 0,-6.61093 z m 34.40374,0 -5.66649,3.10309 0,6.74585 5.66649,-3.23801 0,-6.61093 z m 34.40373,0.13496 -5.53157,3.10309 0,6.61092 5.53157,-3.23801 0,-6.476 z m 30.49116,2.29361 -1.619,0.80948 0,0.40474 c 0.51398,-0.42448 1.11495,-0.77928 1.619,-1.21422 z m -90.12428,1.619 -6.74582,3.91258 0,7.69022 6.74582,-3.91257 0,-7.69023 z m 34.40374,0 -6.74583,3.91258 0,7.82513 6.74583,-3.91257 0,-7.82514 z m 34.40373,0 -6.74583,3.91258 0,7.82513 6.74583,-3.91257 0,-7.82514 z m -86.07678,0.53965 -6.745843,3.91258 0,1.75391 c 1.351311,0.86908 2.647126,1.76168 4.047491,2.56344 l 2.698352,-1.619 0,-6.61093 z m 34.40373,0 -6.74583,3.91258 0,6.61092 6.74583,-3.91257 0,-6.61093 z m 34.53865,0.13495 -6.74584,3.91258 0,6.47601 6.74584,-3.91258 0,-6.47601 z m 34.40373,0 -6.74583,3.91258 0,1.75391 c 2.31393,-1.47761 4.58411,-3.19247 6.74583,-4.857 l 0,-0.80949 z m -95.25115,4.58719 -5.666487,3.238 0,2.83322 c 1.553854,0.76799 3.118682,1.60846 4.722097,2.29361 l 0.94439,-0.5397 0,-7.82513 z m 34.40374,0 -5.66649,3.37291 0,7.69023 5.66649,-3.23801 0,-7.82513 z m 34.40373,0 -5.53157,3.238 0,7.82514 5.53157,-3.23801 0,-7.82513 z m -51.67306,0.53965 -5.53157,3.238 0,6.61092 5.53157,-3.10309 0,-6.74583 z m 34.53865,0.13495 -5.66649,3.23801 0,6.476 5.66649,-3.10309 0,-6.61092 z m 34.40373,0 -5.66649,3.23801 0,1.61899 c 1.88997,-0.96056 3.85662,-1.88937 5.66649,-2.96817 l 0,-1.88883 z m -94.17175,4.04749 -0.26991,0.13495 c 0.07327,0.0391 0.196228,-0.0391 0.26991,0 l 0,-0.13495 z m 68.94238,0 -6.74584,3.77769 0,5.93631 c 1.77734,-0.31799 3.52133,-0.66615 5.26174,-1.07934 l 1.4841,-0.80949 0,-7.82517 z m -34.53865,0.13495 -6.74583,3.7777 0,5.8014 c 0.89029,0.16054 1.79924,0.26874 2.69831,0.40473 l 4.04752,-2.29357 0,-7.69026 z m -17.13442,0.40478 -6.74582,3.77766 0,0.67456 c 2.17731,0.83446 4.3559,1.48079 6.61091,2.1587 l 0.13496,0 0,-6.61092 z m 34.40374,0.13495 -6.74583,3.77766 0,6.61092 6.74583,-3.91258 0,-6.476 z m 34.40373,0 -6.74583,3.77766 0,0.53965 c 2.29163,-0.87195 4.54763,-1.79618 6.74583,-2.83322 l 0,-1.48409 z m -26.30876,4.58714 -5.66649,3.238 0,2.29361 c 1.90268,-0.17645 3.79891,-0.3902 5.66649,-0.6746 l 0,-4.85701 z m -34.53865,0.13495 -4.85696,2.69831 c 1.59297,0.41668 3.23106,0.7429 4.85696,1.07935 l 0,-3.77766 z m 17.26933,0.53965 -5.66649,3.23801 0,1.75392 c 1.86974,0.15589 3.76668,0.0869 5.66649,0.13494 l 0,-5.12682 z m 9.17435,3.91258 -2.15865,1.21426 c 0.70043,-0.031 1.46229,0.0473 2.15865,0 l 0,-1.21426 z"
+ style="fill:url(#linearGradient3624);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:0.65163933;fill:none;stroke:url(#radialGradient3621);stroke-width:5.77425385;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ d="m 134.80965,272.29143 c -63.563591,0 -115.218772,51.65518 -115.218772,115.21877 l 485.429932,22.66599 c 7.79308,-7.79311 8.45097,-17.80762 1.34914,-24.90941 l -26.71347,-26.57859 c -1.06266,1.06271 -2.41894,1.75392 -4.04752,1.75392 l -5.12679,0 -11.60284,-11.6028 c -2.30322,-2.30323 -6.06169,-2.30323 -8.36487,0 l -8.3648,8.63462 -12.81706,-12.81706 c -0.64359,-0.64355 -1.49235,-1.06524 -2.29361,-1.34918 -0.26913,-0.11362 -0.52147,-0.197 -0.80948,-0.2699 -0.0911,-0.0194 -0.17839,0.0116 -0.26991,0 -0.38352,-0.0779 -0.67212,-0.13495 -1.0793,-0.13495 l -15.3805,0 c -0.22841,0 -0.45309,0.10974 -0.67457,0.13495 -1.68624,-0.16481 -3.42433,0.32109 -4.72209,1.619 l -15.65032,15.78524 -27.79281,0 -15.78524,-15.78524 c -2.30315,-2.30315 -6.06165,-2.30315 -8.36484,0 l -9.0394,9.0394 -12.14249,-12.14249 c -2.30314,-2.30315 -6.06169,-2.30315 -8.36484,0 l -18.75341,18.88833 -13.76149,0 c -3.25713,3e-5 -5.8014,-2.67915 -5.8014,-5.93632 l 0,-9.44417 c 0,-5.27885 -3.61571,-7.15058 -7.42041,-7.15058 l -26.03893,-1.93898 c -2.44605,-6.16794 -5.33539,-12.13085 -8.63467,-17.80897 -0.11284,-0.19429 -0.29083,-0.34592 -0.40474,-0.53966 -21.03906,-27.49258 -54.07172,-45.332 -91.3385,-45.332 z m -30.63933,34.80848 c 18.03154,3e-5 32.64982,14.48337 32.64982,32.5149 0,18.03157 -14.61828,32.78473 -32.64982,32.78473 -18.031537,0 -32.649817,-14.7532 -32.649817,-32.78473 0,-18.03153 14.61828,-32.5149 32.649817,-32.5149 z"
+ id="path3154"
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ id="path3158"
+ d="m 134.80965,272.29143 c -63.563591,0 -115.218772,51.65518 -115.218772,115.21877 l 485.429932,22.66599 c 7.79308,-7.79311 8.45097,-19.74659 1.34914,-26.84838 l -26.71347,-26.57859 c -1.06266,1.06271 -2.41894,1.75391 -4.04752,1.75391 l -5.12679,0 -11.60284,-11.6028 c -2.30322,-2.30322 -6.06169,-2.30322 -8.36487,0 l -8.3648,8.63463 -12.81706,-12.81706 c -0.64359,-0.64355 -1.49235,-1.06523 -2.29361,-1.34917 -0.26913,-0.11363 -0.52147,-0.19701 -0.80948,-0.26991 -0.0911,-0.0194 -0.17839,0.0116 -0.26991,0 -0.38352,-0.0779 -0.67212,-0.13496 -1.0793,-0.13496 l -15.3805,0 c -0.22841,0 -0.45309,0.10975 -0.67457,0.13496 -1.68624,-0.16481 -3.42433,0.32109 -4.72209,1.619 l -15.65032,15.78524 -27.79281,0 -15.78524,-15.78524 c -2.30315,-2.30315 -6.06165,-2.30315 -8.36484,0 l -9.0394,9.03941 -12.14249,-12.1425 c -2.30314,-2.30315 -6.06169,-2.30315 -8.36484,0 l -18.75341,18.88833 -13.76149,0 c -3.25713,3e-5 -5.8014,-2.67915 -5.8014,-5.93631 l 0,-9.44419 c 0,-5.27885 -3.61571,-7.15058 -7.42041,-7.15058 l -26.03893,0 c -2.44605,-6.16794 -5.33539,-12.13085 -8.63467,-17.80897 -0.11284,-0.19429 -0.29083,-0.34592 -0.40474,-0.53966 -21.03906,-27.49258 -54.07172,-45.332 -91.3385,-45.332 z m -30.63933,34.80848 c 18.03154,3e-5 32.64982,14.48337 32.64982,32.5149 0,18.03157 -14.61828,32.78473 -32.64982,32.78473 -18.031537,0 -32.649817,-14.7532 -32.649817,-32.78473 0,-18.03153 14.61828,-32.5149 32.649817,-32.5149 z"
+ style="opacity:0.84836067;fill:none;stroke:url(#radialGradient3618);stroke-width:2.28410721;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cscccccccccsssccsccccccccccccccscccsssc"
+ id="path3144"
+ d="m 134.80965,272.67922 c -63.563591,0 -115.218772,51.65518 -115.218772,115.21878 l 485.429932,22.66599 c 7.79308,-7.79312 8.45097,-19.74659 1.34914,-26.84838 l -26.71347,-26.5786 c -1.06266,1.06272 -2.41894,1.75392 -4.04752,1.75392 l -5.12679,0 -11.60284,-11.6028 c -2.30322,-2.30323 -6.06169,-2.30323 -8.36487,0 l -8.3648,8.63462 -12.81706,-12.81706 c -0.64359,-0.64354 -1.49235,-1.06523 -2.29361,-1.34918 -0.26913,-0.11361 -0.52147,-0.19699 -0.80948,-0.2699 -0.0911,-0.0194 -0.17839,0.0116 -0.26991,0 -0.38352,-0.0779 -0.67212,-0.13495 -1.0793,-0.13495 l -15.3805,0 c -0.22841,0 -0.45309,0.10975 -0.67457,0.13495 -1.68624,-0.16481 -3.42433,0.3211 -4.72209,1.619 l -15.65032,15.78525 -27.79281,0 -15.78524,-15.78525 c -2.30315,-2.30314 -6.06165,-2.30314 -8.36484,0 l -9.0394,9.0394 -12.14249,-12.14249 c -2.30314,-2.30314 -6.06169,-2.30314 -8.36484,0 l -18.75341,18.88834 -13.76149,0 c -3.25713,3e-5 -5.8014,-2.67916 -5.8014,-5.93633 l 0,-9.44417 c 0,-5.27885 -3.61571,-7.15058 -7.42041,-7.15058 l -26.03893,0 c -2.44605,-6.16794 -5.33539,-12.13085 -8.63467,-17.80898 -0.11284,-0.19428 -0.29083,-0.34591 -0.40474,-0.53965 -21.03906,-27.49259 -54.07172,-45.332 -91.3385,-45.332 z m -30.63933,34.80847 c 18.03154,5e-5 32.64982,14.48338 32.64982,32.51491 0,18.03158 -14.61828,32.78473 -32.64982,32.78473 -18.031537,0 -32.649817,-14.75319 -32.649817,-32.78473 0,-18.03153 14.61828,-32.51491 32.649817,-32.51491 z"
+ style="fill:none;stroke:url(#radialGradient3615);stroke-width:3.05969524;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:4"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3168"
+ d="m 363.00484,426.28275 c -63.15619,0 -115.50277,11.62184 -124.57885,26.78203 l 210.863,0 c 1.79933,0 3.67667,-0.0802 5.33216,-0.48473 5.10555,-0.0271 10.31684,-2.19745 14.4211,-6.30167 l 3.87794,-3.87793 c -21.56926,-9.61858 -62.69843,-16.1177 -109.91535,-16.1177 z"
+ style="opacity:0.63934428;fill:url(#radialGradient3612);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3203"
+ d="m 269.81998,389.10335 239.21353,0"
+ style="fill:none;stroke:url(#radialGradient3609);stroke-width:0.82987934;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:url(#radialGradient3606);stroke-width:2.54294777;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 270.26543,406.83147 239.21358,0"
+ id="path3214"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:56.11684418px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="511.39062"
+ y="887.47369"
+ id="text3057-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3059-5"
+ x="511.39062"
+ y="887.47369"
+ style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Manage Keys.</tspan><tspan
+ sodipodi:role="line"
+ x="511.39062"
+ y="947.47369"
+ style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ id="tspan12274">Encrypt your Files and Communications.</tspan><tspan
+ sodipodi:role="line"
+ x="511.39062"
+ y="995.5127"
+ style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ id="tspan12276">Compatible with the OpenPGP Standard.</tspan></text>
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot11197"
+ style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Sans;font-style:normal;font-weight:normal;font-size:40px;line-height:125%;letter-spacing:0px;word-spacing:0px"><flowRegion
+ id="flowRegion11199"><rect
+ id="rect11201"
+ width="277.05264"
+ height="69.433342"
+ x="203.53499"
+ y="291.69998" /></flowRegion><flowPara
+ id="flowPara11203" /></flowRoot> <path
+ sodipodi:type="arc"
+ style="opacity:0.6;fill:#9933cc;fill-opacity:1;stroke:none"
+ id="path4501"
+ sodipodi:cx="227.53687"
+ sodipodi:cy="246.58241"
+ sodipodi:rx="225.51656"
+ sodipodi:ry="225.51656"
+ d="m 453.05342,246.58241 c 0,124.54936 -100.9672,225.51656 -225.51655,225.51656 -124.54936,0 -225.5165606,-100.9672 -225.5165606,-225.51656 0,-124.54935 100.9672006,-225.516553 225.5165606,-225.516553 124.54935,0 225.51655,100.967203 225.51655,225.516553 z"
+ transform="translate(-824.39975,263.78972)" />
+ </g>
+</svg>
diff --git a/extern/KeybaseLib b/extern/KeybaseLib
-Subproject e214906a52233bb6f230bc6759ac7be803d24bf
+Subproject 2e8f38f6e38fe77b828826d3c6e8cb89a8a9aee
diff --git a/extern/StickyListHeaders b/extern/StickyListHeaders
-Subproject 706c0e447229226b6edc82ab10630d39fd0f6c3
+Subproject 911f8ddfd007ce65aededae7e7b79e5a8d903a4
diff --git a/extern/spongycastle b/extern/spongycastle
-Subproject 918340cbc6d5396764bfe94fdba07aca11cd816
+Subproject 526d23382e53ce46a17a5efd9c23d884125e32c