diff options
16 files changed, 813 insertions, 559 deletions
diff --git a/org_apg/res/layout/import_from_qr_code.xml b/org_apg/res/layout/import_from_qr_code.xml new file mode 100644 index 000000000..54f4355b3 --- /dev/null +++ b/org_apg/res/layout/import_from_qr_code.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" > + + <LinearLayout + android:id="@+id/import_from_qr_code_footer" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:orientation="vertical" + android:paddingLeft="10dp" + android:paddingRight="10dp" > + + + <Button + android:id="@+id/import_from_qr_code_import" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/import_from_qr_code_import" /> + + <Button + android:id="@+id/import_from_qr_code_import_sign_and_upload" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/import_from_qr_code_import_sign_and_upload" /> + + <Button + android:id="@+id/import_from_qr_code_scan_again" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/import_from_qr_code_scan_again" /> + + <Button + android:id="@+id/import_from_qr_code_finish" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/import_from_qr_code_finish" /> + </LinearLayout> + + <ScrollView + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:layout_above="@id/import_from_qr_code_footer" + android:fillViewport="true" > + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="10dp" + android:paddingRight="10dp" > + + <TextView + android:id="@+id/import_from_qr_code_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="" /> + </LinearLayout> + </ScrollView> + +</RelativeLayout>
\ No newline at end of file diff --git a/org_apg/res/values/strings.xml b/org_apg/res/values/strings.xml index 25cf6d190..46cb781f7 100644 --- a/org_apg/res/values/strings.xml +++ b/org_apg/res/values/strings.xml @@ -34,7 +34,7 @@ <string name="title_keyServerPreference">Key Server Preference</string> <string name="title_changePassPhrase">Change Passphrase</string> <string name="title_setPassPhrase">Set Passphrase</string> - <string name="title_sendEmail">"Send Mail..."</string> + <string name="title_sendEmail">"Send Mail…"</string> <string name="title_encryptToFile">Encrypt To File</string> <string name="title_decryptToFile">Decrypt To File</string> <string name="title_importKeys">Import Keys</string> @@ -100,7 +100,7 @@ <string name="menu_keyServer">Key Server</string> <string name="menu_updateKey">Update</string> <string name="menu_exportKeyToServer">Export To Server</string> - <string name="menu_share">Share with QR Code</string> + <string name="menu_share">Share public key with QR Code</string> <string name="menu_scanQRCode">Scan QR Code</string> <string name="menu_signKey">Sign Key</string> @@ -173,10 +173,10 @@ <string name="dsa">DSA</string> <string name="elgamal">ElGamal</string> <string name="rsa">RSA</string> - <string name="filemanager_titleOpen">Open...</string> - <string name="filemanager_titleSave">Save As...</string> - <string name="filemanager_titleEncrypt">Select File To Encrypt...</string> - <string name="filemanager_titleDecrypt">Select File To Decrypt...</string> + <string name="filemanager_titleOpen">Open…</string> + <string name="filemanager_titleSave">Save As…</string> + <string name="filemanager_titleEncrypt">Select File To Encrypt…</string> + <string name="filemanager_titleDecrypt">Select File To Decrypt…</string> <string name="filemanager_btnOpen">Open</string> <string name="filemanager_btnSave">Save</string> <string name="warning">Warning</string> @@ -260,41 +260,41 @@ <string name="error_savingKeys">error saving some key(s)</string> <string name="error_couldNotExtractPrivateKey">could not extract private key</string> - <!-- progress_lowerCase: lowercase, phrases, usually ending in '...' --> + <!-- progress_lowerCase: lowercase, phrases, usually ending in '…' --> <string name="progress_done">done.</string> - <string name="progress_initializing">initializing...</string> - <string name="progress_saving">saving...</string> - <string name="progress_importing">importing...</string> - <string name="progress_exporting">exporting...</string> - <string name="progress_generating">generating key, this can take a while...</string> - <string name="progress_buildingKey">building key...</string> - <string name="progress_preparingMasterKey">preparing master key...</string> - <string name="progress_certifyingMasterKey">certifying master key...</string> - <string name="progress_buildingMasterKeyRing">building master key ring...</string> - <string name="progress_addingSubKeys">adding sub keys...</string> - <string name="progress_savingKeyRing">saving key ring...</string> - <string name="progress_importingSecretKeys">importing secret keys...</string> - <string name="progress_importingPublicKeys">importing public keys...</string> - <string name="progress_reloadingKeys">reloading keys...</string> - <string name="progress_exportingKey">exporting key...</string> - <string name="progress_exportingKeys">exporting keys...</string> - <string name="progress_extractingSignatureKey">extracting signature key...</string> - <string name="progress_extractingKey">extracting key...</string> - <string name="progress_preparingStreams">preparing streams...</string> - <string name="progress_encrypting">encrypting data...</string> - <string name="progress_decrypting">decrypting data...</string> - <string name="progress_preparingSignature">preparing signature...</string> - <string name="progress_generatingSignature">generating signature...</string> - <string name="progress_processingSignature">processing signature...</string> - <string name="progress_verifyingSignature">verifying signature...</string> - <string name="progress_signing">signing...</string> - <string name="progress_readingData">reading data...</string> - <string name="progress_findingKey">finding key...</string> - <string name="progress_decompressingData">decompressing data...</string> - <string name="progress_verifyingIntegrity">verifying integrity...</string> - <string name="progress_deletingSecurely">deleting \'%s\' securely...</string> - <string name="progress_querying">querying...</string> - <string name="progress_queryingServer">querying %s...</string> + <string name="progress_initializing">initializing…</string> + <string name="progress_saving">saving…</string> + <string name="progress_importing">importing…</string> + <string name="progress_exporting">exporting…</string> + <string name="progress_generating">generating key, this can take a while…</string> + <string name="progress_buildingKey">building key…</string> + <string name="progress_preparingMasterKey">preparing master key…</string> + <string name="progress_certifyingMasterKey">certifying master key…</string> + <string name="progress_buildingMasterKeyRing">building master key ring…</string> + <string name="progress_addingSubKeys">adding sub keys…</string> + <string name="progress_savingKeyRing">saving key ring…</string> + <string name="progress_importingSecretKeys">importing secret keys…</string> + <string name="progress_importingPublicKeys">importing public keys…</string> + <string name="progress_reloadingKeys">reloading keys…</string> + <string name="progress_exportingKey">exporting key…</string> + <string name="progress_exportingKeys">exporting keys…</string> + <string name="progress_extractingSignatureKey">extracting signature key…</string> + <string name="progress_extractingKey">extracting key…</string> + <string name="progress_preparingStreams">preparing streams…</string> + <string name="progress_encrypting">encrypting data…</string> + <string name="progress_decrypting">decrypting data…</string> + <string name="progress_preparingSignature">preparing signature…</string> + <string name="progress_generatingSignature">generating signature…</string> + <string name="progress_processingSignature">processing signature…</string> + <string name="progress_verifyingSignature">verifying signature…</string> + <string name="progress_signing">signing…</string> + <string name="progress_readingData">reading data…</string> + <string name="progress_findingKey">finding key…</string> + <string name="progress_decompressingData">decompressing data…</string> + <string name="progress_verifyingIntegrity">verifying integrity…</string> + <string name="progress_deletingSecurely">deleting \'%s\' securely…</string> + <string name="progress_querying">querying…</string> + <string name="progress_queryingServer">querying %s…</string> <!-- permission strings --> <string name="permission_read_key_details_label">Read key details from APG.</string> @@ -316,7 +316,7 @@ <string name="slow">slow</string> <string name="very_slow">very slow</string> - <!-- APG Fork --> + <!-- APG 2.0 --> <!-- Dashboard --> @@ -333,4 +333,11 @@ <string name="help_tab_about">About</string> <string name="help_about_version">Version:</string> + <!-- Import from QR Code --> + + <string name="import_from_qr_code_import">Import key (only locally)</string> + <string name="import_from_qr_code_import_sign_and_upload">Import, Sign, and upload key</string> + <string name="import_from_qr_code_scan_again">Scan qr code again</string> + <string name="import_from_qr_code_finish">Finish</string> + </resources>
\ No newline at end of file diff --git a/org_apg/src/org/thialfihar/android/apg/ApgApplication.java b/org_apg/src/org/thialfihar/android/apg/ApgApplication.java index 9a77efb74..ba9c9f08d 100644 --- a/org_apg/src/org/thialfihar/android/apg/ApgApplication.java +++ b/org_apg/src/org/thialfihar/android/apg/ApgApplication.java @@ -16,6 +16,9 @@ package org.thialfihar.android.apg; +import java.security.Security; + +import org.spongycastle.jce.provider.BouncyCastleProvider; import org.thialfihar.android.apg.helper.PGPMain; import org.thialfihar.android.apg.service.PassphraseCacheService; @@ -23,6 +26,10 @@ import android.app.Application; public class ApgApplication extends Application { + static { + Security.addProvider(new BouncyCastleProvider()); + } + @Override public void onCreate() { super.onCreate(); diff --git a/org_apg/src/org/thialfihar/android/apg/Id.java b/org_apg/src/org/thialfihar/android/apg/Id.java index bc40f59e6..4c83437a1 100644 --- a/org_apg/src/org/thialfihar/android/apg/Id.java +++ b/org_apg/src/org/thialfihar/android/apg/Id.java @@ -35,7 +35,7 @@ public final class Id { public static final int edit = 0x21070003; public static final int update = 0x21070004; public static final int exportToServer = 0x21070005; - public static final int share = 0x21070006; + public static final int share_qr_code = 0x21070006; public static final int signKey = 0x21070007; public static final class option { diff --git a/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java index 67b4d9c9f..516d7fccb 100644 --- a/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java +++ b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java @@ -86,22 +86,26 @@ public class OtherHelper { */ public static void logDebugBundle(Bundle bundle, String bundleName) { if (Constants.DEBUG) { - Set<String> ks = bundle.keySet(); - Iterator<String> iterator = ks.iterator(); + if (bundle != null) { + Set<String> ks = bundle.keySet(); + Iterator<String> iterator = ks.iterator(); - Log.d(Constants.TAG, "Bundle " + bundleName + ":"); - Log.d(Constants.TAG, "------------------------------"); - while (iterator.hasNext()) { - String key = iterator.next(); - Object value = bundle.get(key); + Log.d(Constants.TAG, "Bundle " + bundleName + ":"); + Log.d(Constants.TAG, "------------------------------"); + while (iterator.hasNext()) { + String key = iterator.next(); + Object value = bundle.get(key); - if (value != null) { - Log.d(Constants.TAG, key + " : " + value.toString()); - } else { - Log.d(Constants.TAG, key + " : null"); + if (value != null) { + Log.d(Constants.TAG, key + " : " + value.toString()); + } else { + Log.d(Constants.TAG, key + " : null"); + } } + Log.d(Constants.TAG, "------------------------------"); + } else { + Log.d(Constants.TAG, "Bundle " + bundleName + ": null"); } - Log.d(Constants.TAG, "------------------------------"); } } } diff --git a/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java index 0b6191f67..6d5a07f56 100644 --- a/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java +++ b/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java @@ -17,6 +17,7 @@ package org.thialfihar.android.apg.helper; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Calendar; @@ -24,6 +25,7 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.Vector; +import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; @@ -34,8 +36,10 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; +import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.R; import org.thialfihar.android.apg.util.IterableIterator; +import org.thialfihar.android.apg.util.Log; import android.content.Context; @@ -186,7 +190,7 @@ public class PGPHelper { } public static PGPPublicKey getEncryptPublicKey(long masterKeyId) { - //TODO: externalize getSecretKeyRing from PGPWrapper into a DatabaseHelper + // TODO: externalize getSecretKeyRing from PGPWrapper into a DatabaseHelper PGPPublicKeyRing keyRing = PGPMain.getPublicKeyRing(masterKeyId); if (keyRing == null) { return null; @@ -199,7 +203,7 @@ public class PGPHelper { } public static PGPSecretKey getSigningKey(long masterKeyId) { - //TODO: externalize getSecretKeyRing from PGPWrapper into a DatabaseHelper + // TODO: externalize getSecretKeyRing from PGPWrapper into a DatabaseHelper PGPSecretKeyRing keyRing = PGPMain.getSecretKeyRing(masterKeyId); if (keyRing == null) { return null; @@ -380,12 +384,42 @@ public class PGPHelper { } + public static String getPubkeyAsArmoredString(long keyId) { + PGPPublicKey key = PGPMain.getPublicKey(keyId); + // if it is no public key get it from your own keys... + if (key == null) { + PGPSecretKey secretKey = PGPMain.getSecretKey(keyId); + if (secretKey == null) { + Log.e(Constants.TAG, "Key could not be found!"); + return null; + } + key = secretKey.getPublicKey(); + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ArmoredOutputStream aos = new ArmoredOutputStream(bos); + String armouredKey = null; + try { + aos.write(key.getEncoded()); + aos.close(); + + armouredKey = bos.toString("UTF-8"); + } catch (IOException e) { + Log.e(Constants.TAG, "Problems while encoding key as armored string", e); + } + + Log.d(Constants.TAG, "key:" + armouredKey); + + return armouredKey; + } + public static String getFingerPrint(long keyId) { PGPPublicKey key = PGPMain.getPublicKey(keyId); if (key == null) { PGPSecretKey secretKey = PGPMain.getSecretKey(keyId); if (secretKey == null) { - return ""; + Log.e(Constants.TAG, "Key could not be found!"); + return null; } key = secretKey.getPublicKey(); } diff --git a/org_apg/src/org/thialfihar/android/apg/helper/PGPMain.java b/org_apg/src/org/thialfihar/android/apg/helper/PGPMain.java index 00e9e707d..3fcbeb7a7 100644 --- a/org_apg/src/org/thialfihar/android/apg/helper/PGPMain.java +++ b/org_apg/src/org/thialfihar/android/apg/helper/PGPMain.java @@ -662,7 +662,7 @@ public class PGPMain { } } - public static Bundle importKeyRings(Activity context, int type, InputData data, + public static Bundle importKeyRings(Context context, int type, InputData data, ProgressDialogUpdater progress) throws GeneralException, FileNotFoundException, PGPException, IOException { Bundle returnData = new Bundle(); @@ -733,7 +733,7 @@ public class PGPMain { return returnData; } - public static Bundle exportKeyRings(Activity context, Vector<Integer> keyRingIds, + public static Bundle exportKeyRings(Context context, Vector<Integer> keyRingIds, OutputStream outStream, ProgressDialogUpdater progress) throws GeneralException, FileNotFoundException, PGPException, IOException { Bundle returnData = new Bundle(); diff --git a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java index b6811d2ee..901097bbc 100644 --- a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java +++ b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Vector; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; @@ -66,7 +67,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { /* keys for data bundle */ - // encrypt and decrypt + // encrypt, decrypt, import export public static final String TARGET = "target"; // possible targets: public static final int TARGET_BYTES = 1; @@ -91,7 +92,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { public static final String RETURN_BYTES = "returnBinary"; public static final String CIPHERTEXT_BYTES = "ciphertextBytes"; public static final String ASSUME_SYMMETRIC = "assumeSymmetric"; - public static final String LOOKUP_UNKNOWN_KEY = "lookup_unknown_key"; + public static final String LOOKUP_UNKNOWN_KEY = "lookupUnknownKey"; // edit keys public static final String NEW_PASSPHRASE = "newPassphrase"; @@ -103,13 +104,26 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { // generate key public static final String ALGORITHM = "algorithm"; - public static final String KEY_SIZE = "key_size"; + public static final String KEY_SIZE = "keySize"; public static final String SYMMETRIC_PASSPHRASE = "passphrase"; public static final String MASTER_KEY = "masterKey"; // delete file securely public static final String DELETE_FILE = "deleteFile"; + // import key + public static final String IMPORT_INPUT_STREAM = "importInputStream"; + public static final String IMPORT_FILENAME = "importFilename"; + public static final String IMPORT_BYTES = "importBytes"; + public static final String IMPORT_KEY_TYPE = "importKeyType"; + + // export key + public static final String EXPORT_OUTPUT_STREAM = "exportOutputStream"; + public static final String EXPORT_FILENAME = "exportFilename"; + public static final String EXPORT_KEY_TYPE = "exportKeyType"; + public static final String EXPORT_ALL = "exportAll"; + public static final String EXPORT_KEY_RING_ID = "exportKeyRingId"; + /* possible EXTRA_ACTIONs */ public static final int ACTION_ENCRYPT_SIGN = 10; @@ -121,6 +135,9 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { public static final int ACTION_DELETE_FILE_SECURELY = 40; + public static final int ACTION_IMPORT_KEY = 50; + public static final int ACTION_EXPORT_KEY = 51; + /* possible data keys as result send over messenger */ // keys public static final String RESULT_NEW_KEY = "newKey"; @@ -580,6 +597,104 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { break; + case ACTION_IMPORT_KEY: + try { + + /* Input */ + int target = data.getInt(TARGET); + + int keyType = Id.type.public_key; + if (data.containsKey(IMPORT_KEY_TYPE)) { + keyType = data.getInt(IMPORT_KEY_TYPE); + } + + /* Operation */ + InputStream inStream = null; + long inLength = -1; + InputData inputData = null; + switch (target) { + case TARGET_BYTES: /* import key from bytes directly */ + byte[] bytes = data.getByteArray(IMPORT_BYTES); + + inStream = new ByteArrayInputStream(bytes); + inLength = bytes.length; + + inputData = new InputData(inStream, inLength); + + break; + case TARGET_FILE: /* import key from file */ + String inputFile = data.getString(IMPORT_FILENAME); + + inStream = new FileInputStream(inputFile); + File file = new File(inputFile); + inLength = file.length(); + inputData = new InputData(inStream, inLength); + + break; + + case TARGET_STREAM: + // TODO: not implemented + break; + } + + Bundle resultData = new Bundle(); + resultData = PGPMain.importKeyRings(this, keyType, inputData, this); + + sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } + + break; + + case ACTION_EXPORT_KEY: + try { + + /* Input */ + int keyType = Id.type.public_key; + if (data.containsKey(EXPORT_KEY_TYPE)) { + keyType = data.getInt(EXPORT_KEY_TYPE); + } + + String outputFile = data.getString(EXPORT_FILENAME); + + boolean exportAll = data.getBoolean(EXPORT_ALL); + int keyRingId = -1; + if (!exportAll) { + keyRingId = data.getInt(EXPORT_KEY_RING_ID); + } + + /* Operation */ + + // check if storage is ready + if (!FileHelper.isStorageMounted(outputFile)) { + sendErrorToHandler(new GeneralException( + getString(R.string.error_externalStorageNotReady))); + return; + } + + // OutputStream + FileOutputStream outStream = new FileOutputStream(outputFile); + + Vector<Integer> keyRingIds = new Vector<Integer>(); + if (exportAll) { + keyRingIds = PGPMain + .getKeyRingIds(keyType == Id.type.public_key ? Id.database.type_public + : Id.database.type_secret); + } else { + keyRingIds.add(keyRingId); + } + + Bundle resultData = new Bundle(); + resultData = PGPMain.exportKeyRings(this, keyRingIds, outStream, this); + + sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } + + break; + default: break; } diff --git a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java index ee6ad5af8..53b0ed029 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java @@ -693,7 +693,7 @@ public class DecryptActivity extends SherlockFragmentActivity { private void decryptStart() { Log.d(Constants.TAG, "decryptStart"); - // Send all information needed to service to edit key in other thread + // Send all information needed to service to decrypt in other thread Intent intent = new Intent(this, ApgService.class); // fill values for this action diff --git a/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java index 5d70e6924..0b751f66c 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java @@ -33,6 +33,8 @@ import android.content.Intent; import android.os.Bundle; import android.os.Message; import org.thialfihar.android.apg.util.Log; + +import android.widget.TextView; import android.widget.Toast; import com.google.zxing.integration.android.IntentIntegrator; @@ -61,86 +63,98 @@ public class ImportFromQRCodeActivity extends BaseActivity { new IntentIntegrator(this).initiateScan(); } + // private void importAndSignOld(final long keyId, final String expectedFingerprint) { + // if (expectedFingerprint != null && expectedFingerprint.length() > 0) { + // + // Thread t = new Thread() { + // @Override + // public void run() { + // try { + // // TODO: display some sort of spinner here while the user waits + // + // // TODO: there should be only 1 + // HkpKeyServer server = new HkpKeyServer(mPreferences.getKeyServers()[0]); + // String encodedKey = server.get(keyId); + // + // PGPKeyRing keyring = PGPHelper.decodeKeyRing(new ByteArrayInputStream( + // encodedKey.getBytes())); + // if (keyring != null && keyring instanceof PGPPublicKeyRing) { + // PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; + // + // // make sure the fingerprints match before we cache this thing + // String actualFingerprint = PGPHelper.convertToHex(publicKeyRing + // .getPublicKey().getFingerprint()); + // if (expectedFingerprint.equals(actualFingerprint)) { + // // store the signed key in our local cache + // int retval = PGPMain.storeKeyRingInCache(publicKeyRing); + // if (retval != Id.return_value.ok + // && retval != Id.return_value.updated) { + // status.putString(EXTRA_ERROR, + // "Failed to store signed key in local cache"); + // } else { + // Intent intent = new Intent(ImportFromQRCodeActivity.this, + // SignKeyActivity.class); + // intent.putExtra(EXTRA_KEY_ID, keyId); + // startActivityForResult(intent, Id.request.sign_key); + // } + // } else { + // status.putString( + // EXTRA_ERROR, + // "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key."); + // } + // } + // } catch (QueryException e) { + // Log.e(TAG, "Failed to query KeyServer", e); + // status.putString(EXTRA_ERROR, "Failed to query KeyServer"); + // status.putInt(Constants.extras.STATUS, Id.message.done); + // } catch (IOException e) { + // Log.e(TAG, "Failed to query KeyServer", e); + // status.putString(EXTRA_ERROR, "Failed to query KeyServer"); + // status.putInt(Constants.extras.STATUS, Id.message.done); + // } + // } + // }; + // + // t.setName("KeyExchange Download Thread"); + // t.setDaemon(true); + // t.start(); + // } + // } + private void importAndSign(final long keyId, final String expectedFingerprint) { - if (expectedFingerprint != null && expectedFingerprint.length() > 0) { - - Thread t = new Thread() { - @Override - public void run() { - try { - // TODO: display some sort of spinner here while the user waits - - // TODO: there should be only 1 - HkpKeyServer server = new HkpKeyServer(mPreferences.getKeyServers()[0]); - String encodedKey = server.get(keyId); - - PGPKeyRing keyring = PGPHelper.decodeKeyRing(new ByteArrayInputStream( - encodedKey.getBytes())); - if (keyring != null && keyring instanceof PGPPublicKeyRing) { - PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; - - // make sure the fingerprints match before we cache this thing - String actualFingerprint = PGPHelper.convertToHex(publicKeyRing - .getPublicKey().getFingerprint()); - if (expectedFingerprint.equals(actualFingerprint)) { - // store the signed key in our local cache - int retval = PGPMain.storeKeyRingInCache(publicKeyRing); - if (retval != Id.return_value.ok - && retval != Id.return_value.updated) { - status.putString(EXTRA_ERROR, - "Failed to store signed key in local cache"); - } else { - Intent intent = new Intent(ImportFromQRCodeActivity.this, - SignKeyActivity.class); - intent.putExtra(EXTRA_KEY_ID, keyId); - startActivityForResult(intent, Id.request.sign_key); - } - } else { - status.putString( - EXTRA_ERROR, - "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key."); - } - } - } catch (QueryException e) { - Log.e(TAG, "Failed to query KeyServer", e); - status.putString(EXTRA_ERROR, "Failed to query KeyServer"); - status.putInt(Constants.extras.STATUS, Id.message.done); - } catch (IOException e) { - Log.e(TAG, "Failed to query KeyServer", e); - status.putString(EXTRA_ERROR, "Failed to query KeyServer"); - status.putInt(Constants.extras.STATUS, Id.message.done); - } - } - }; - - t.setName("KeyExchange Download Thread"); - t.setDaemon(true); - t.start(); - } + + // setContentView(R.layout.import_from_qr_code); + } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case IntentIntegrator.REQUEST_CODE: { - boolean debug = true; // TODO: remove this!!! IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); - if (debug || (scanResult != null && scanResult.getFormatName() != null)) { - String[] bits = debug ? new String[] { "5993515643896327656", - "0816 F68A 6816 68FB 01BF 2CA5 532D 3EB9 1E2F EDE8" } : scanResult - .getContents().split(","); - if (bits.length != 2) { - return; // dont know how to handle this. Not a valid code - } + if (scanResult != null && scanResult.getFormatName() != null) { - long keyId = Long.parseLong(bits[0]); - String expectedFingerprint = bits[1]; + // show layout + setContentView(R.layout.import_from_qr_code); + TextView contentView = (TextView) findViewById(R.id.import_from_qr_code_content); - importAndSign(keyId, expectedFingerprint); + String content = scanResult.getContents(); + + contentView.setText(content); + // String[] bits = scanResult.getContents().split(","); + // if (bits.length != 2) { + // return; // dont know how to handle this. Not a valid code + // } + // + // long keyId = Long.parseLong(bits[0]); + // String expectedFingerprint = bits[1]; + + // importAndSign(keyId, expectedFingerprint); - break; } + + break; } case Id.request.sign_key: { diff --git a/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java index 97449d316..1d41ab696 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java @@ -16,9 +16,6 @@ package org.thialfihar.android.apg.ui; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.helper.PGPHelper; @@ -26,14 +23,19 @@ import org.thialfihar.android.apg.helper.PGPMain; import org.thialfihar.android.apg.provider.KeyRings; import org.thialfihar.android.apg.provider.Keys; import org.thialfihar.android.apg.provider.UserIds; +import org.thialfihar.android.apg.service.ApgHandler; +import org.thialfihar.android.apg.service.ApgService; +import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment; +import org.thialfihar.android.apg.ui.dialog.DeleteKeyDialogFragment; import org.thialfihar.android.apg.ui.dialog.FileDialogFragment; -import org.thialfihar.android.apg.util.InputData; +import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment; import org.thialfihar.android.apg.R; +import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.MenuItem; import android.app.AlertDialog; -import android.app.Dialog; +import android.app.ProgressDialog; import android.app.SearchManager; import android.content.Context; import android.content.DialogInterface; @@ -59,25 +61,14 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.Vector; -public class KeyListActivity extends BaseActivity { +public class KeyListActivity extends SherlockFragmentActivity { public static final String ACTION_IMPORT = Constants.INTENT_PREFIX + "IMPORT"; public static final String EXTRA_TEXT = "text"; - // TODO: remove when using new intentservice: - public static final String EXTRA_ERROR = "error"; - protected ExpandableListView mList; protected KeyListAdapter mListAdapter; protected View mFilterLayout; @@ -251,7 +242,7 @@ public class KeyListActivity extends BaseActivity { case Id.menu.delete: { mSelectedItem = groupPosition; - showDialog(Id.dialog.delete_key); + showDeleteKeyDialog(); return true; } @@ -261,177 +252,87 @@ public class KeyListActivity extends BaseActivity { } } - @Override - protected Dialog onCreateDialog(int id) { + private void showDeleteKeyDialog() { + final int keyRingId = mListAdapter.getKeyRingId(mSelectedItem); + mSelectedItem = -1; - switch (id) { - case Id.dialog.delete_key: { - final int keyRingId = mListAdapter.getKeyRingId(mSelectedItem); - mSelectedItem = -1; - // TODO: better way to do this? - String userId = "<unknown>"; - Object keyRing = PGPMain.getKeyRing(keyRingId); - if (keyRing != null) { - if (keyRing instanceof PGPPublicKeyRing) { - userId = PGPHelper.getMainUserIdSafe(this, - PGPHelper.getMasterKey((PGPPublicKeyRing) keyRing)); - } else { - userId = PGPHelper.getMainUserIdSafe(this, - PGPHelper.getMasterKey((PGPSecretKeyRing) keyRing)); + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + refreshList(); } } + }; - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.warning); - builder.setMessage(getString( - mKeyType == Id.type.public_key ? R.string.keyDeletionConfirmation - : R.string.secretKeyDeletionConfirmation, userId)); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - deleteKey(keyRingId); - removeDialog(Id.dialog.delete_key); - } - }); - builder.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - removeDialog(Id.dialog.delete_key); - } - }); - return builder.create(); - } + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); - default: { - return super.onCreateDialog(id); - } - } + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, + keyRingId, mKeyType); + + deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); } public void importKeys() { - showDialog(Id.dialog.importing); - mTask = Id.task.import_keys; - startThread(); - } + Log.d(Constants.TAG, "importKeys started"); - public void exportKeys() { - showDialog(Id.dialog.exporting); - mTask = Id.task.export_keys; - startThread(); - } + // Send all information needed to service to import key in other thread + Intent intent = new Intent(this, ApgService.class); - @Override - public void run() { - String error = null; - Bundle data = new Bundle(); - Message msg = new Message(); - - try { - InputStream importInputStream = null; - OutputStream exportOutputStream = null; - long size = 0; - if (mTask == Id.task.import_keys) { - if (mImportData != null) { - byte[] bytes = mImportData.getBytes(); - size = bytes.length; - importInputStream = new ByteArrayInputStream(bytes); - } else { - File file = new File(mImportFilename); - size = file.length(); - importInputStream = new FileInputStream(file); - } - } else { - exportOutputStream = new FileOutputStream(mExportFilename); - } + intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_IMPORT_KEY); - if (mTask == Id.task.import_keys) { - data = PGPMain.importKeyRings(this, mKeyType, new InputData(importInputStream, - size), this); - } else { - Vector<Integer> keyRingIds = new Vector<Integer>(); - if (mSelectedItem == -1) { - keyRingIds = PGPMain - .getKeyRingIds(mKeyType == Id.type.public_key ? Id.database.type_public - : Id.database.type_secret); - } else { - int keyRingId = mListAdapter.getKeyRingId(mSelectedItem); - keyRingIds.add(keyRingId); - mSelectedItem = -1; - } - data = PGPMain.exportKeyRings(this, keyRingIds, exportOutputStream, this); - } - } catch (FileNotFoundException e) { - error = getString(R.string.error_fileNotFound); - } catch (IOException e) { - error = "" + e; - } catch (PGPException e) { - error = "" + e; - } catch (PGPMain.GeneralException e) { - error = "" + e; - } + // fill values for this action + Bundle data = new Bundle(); - mImportData = null; + data.putInt(ApgService.IMPORT_KEY_TYPE, mKeyType); - if (mTask == Id.task.import_keys) { - data.putInt(Constants.extras.STATUS, Id.message.import_done); + if (mImportData != null) { + data.putInt(ApgService.TARGET, ApgService.TARGET_BYTES); + data.putByteArray(ApgService.IMPORT_BYTES, mImportData.getBytes()); } else { - data.putInt(Constants.extras.STATUS, Id.message.export_done); + data.putInt(ApgService.TARGET, ApgService.TARGET_FILE); + data.putString(ApgService.IMPORT_FILENAME, mImportFilename); } - if (error != null) { - data.putString(EXTRA_ERROR, error); - } + intent.putExtra(ApgService.EXTRA_DATA, data); - msg.setData(data); - sendMessage(msg); - } + // create progress dialog + ProgressDialogFragment importingDialog = ProgressDialogFragment.newInstance( + R.string.progress_importing, ProgressDialog.STYLE_HORIZONTAL); - protected void deleteKey(int keyRingId) { - PGPMain.deleteKey(keyRingId); - refreshList(); - } + // Message is received after importing is done in ApgService + ApgHandler saveHandler = new ApgHandler(this, importingDialog) { + public void handleMessage(Message message) { + // handle messages by standard ApgHandler first + super.handleMessage(message); - protected void refreshList() { - mListAdapter.rebuild(true); - mListAdapter.notifyDataSetChanged(); - } + if (message.arg1 == ApgHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); - @Override - public void doneCallback(Message msg) { - super.doneCallback(msg); - - Bundle data = msg.getData(); - if (data != null) { - int type = data.getInt(Constants.extras.STATUS); - switch (type) { - case Id.message.import_done: { - removeDialog(Id.dialog.importing); - - String error = data.getString(EXTRA_ERROR); - if (error != null) { - Toast.makeText(KeyListActivity.this, getString(R.string.errorMessage, error), - Toast.LENGTH_SHORT).show(); - } else { - int added = data.getInt("added"); - int updated = data.getInt("updated"); - int bad = data.getInt("bad"); - String message; + int added = returnData.getInt("added"); + int updated = returnData.getInt("updated"); + int bad = returnData.getInt("bad"); + String toastMessage; if (added > 0 && updated > 0) { - message = getString(R.string.keysAddedAndUpdated, added, updated); + toastMessage = getString(R.string.keysAddedAndUpdated, added, updated); } else if (added > 0) { - message = getString(R.string.keysAdded, added); + toastMessage = getString(R.string.keysAdded, added); } else if (updated > 0) { - message = getString(R.string.keysUpdated, updated); + toastMessage = getString(R.string.keysUpdated, updated); } else { - message = getString(R.string.noKeysAddedOrUpdated); + toastMessage = getString(R.string.noKeysAddedOrUpdated); } - Toast.makeText(KeyListActivity.this, message, Toast.LENGTH_SHORT).show(); + Toast.makeText(KeyListActivity.this, toastMessage, Toast.LENGTH_SHORT).show(); if (bad > 0) { - AlertDialog.Builder alert = new AlertDialog.Builder(this); + AlertDialog.Builder alert = new AlertDialog.Builder(KeyListActivity.this); alert.setIcon(android.R.drawable.ic_dialog_alert); alert.setTitle(R.string.warning); - alert.setMessage(this.getString(R.string.badKeysEncountered, bad)); + alert.setMessage(KeyListActivity.this.getString( + R.string.badKeysEncountered, bad)); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @@ -443,41 +344,94 @@ public class KeyListActivity extends BaseActivity { alert.create().show(); } else if (mDeleteAfterImport) { // everything went well, so now delete, if that was turned on - setDeleteFile(mImportFilename); - showDialog(Id.dialog.delete_file); + DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment + .newInstance(mImportFilename); + deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); } + refreshList(); + } - refreshList(); - break; - } + }; + }; - case Id.message.export_done: { - removeDialog(Id.dialog.exporting); + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(ApgService.EXTRA_MESSENGER, messenger); - String error = data.getString(EXTRA_ERROR); - if (error != null) { - Toast.makeText(KeyListActivity.this, getString(R.string.errorMessage, error), - Toast.LENGTH_SHORT).show(); - } else { - int exported = data.getInt("exported"); - String message; + // show progress dialog + importingDialog.show(getSupportFragmentManager(), "importingDialog"); + + // start service with intent + startService(intent); + } + + public void exportKeys() { + Log.d(Constants.TAG, "exportKeys started"); + + // Send all information needed to service to export key in other thread + Intent intent = new Intent(this, ApgService.class); + + intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_EXPORT_KEY); + + // fill values for this action + Bundle data = new Bundle(); + + data.putString(ApgService.EXPORT_FILENAME, mExportFilename); + data.putInt(ApgService.EXPORT_KEY_TYPE, mKeyType); + + if (mSelectedItem == -1) { + data.putBoolean(ApgService.EXPORT_ALL, true); + } else { + int keyRingId = mListAdapter.getKeyRingId(mSelectedItem); + data.putInt(ApgService.EXPORT_KEY_RING_ID, keyRingId); + mSelectedItem = -1; + } + + intent.putExtra(ApgService.EXTRA_DATA, data); + + // create progress dialog + ProgressDialogFragment exportingDialog = ProgressDialogFragment.newInstance( + R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL); + + // Message is received after exporting is done in ApgService + ApgHandler exportHandler = new ApgHandler(this, exportingDialog) { + public void handleMessage(Message message) { + // handle messages by standard ApgHandler first + super.handleMessage(message); + + if (message.arg1 == ApgHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + + int exported = returnData.getInt("exported"); + String toastMessage; if (exported == 1) { - message = getString(R.string.keyExported); + toastMessage = getString(R.string.keyExported); } else if (exported > 0) { - message = getString(R.string.keysExported, exported); + toastMessage = getString(R.string.keysExported, exported); } else { - message = getString(R.string.noKeysExported); + toastMessage = getString(R.string.noKeysExported); } - Toast.makeText(KeyListActivity.this, message, Toast.LENGTH_SHORT).show(); + Toast.makeText(KeyListActivity.this, toastMessage, Toast.LENGTH_SHORT).show(); + } - break; - } + }; + }; - default: { - break; - } - } - } + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(exportHandler); + intent.putExtra(ApgService.EXTRA_MESSENGER, messenger); + + // show progress dialog + exportingDialog.show(getSupportFragmentManager(), "exportingDialog"); + + // start service with intent + startService(intent); + } + + protected void refreshList() { + mListAdapter.rebuild(true); + mListAdapter.notifyDataSetChanged(); } protected class KeyListAdapter extends BaseExpandableListAdapter { diff --git a/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java deleted file mode 100644 index 85d9d6ce5..000000000 --- a/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.thialfihar.android.apg.ui; - -import java.util.Vector; -import java.util.regex.Matcher; - -import org.thialfihar.android.apg.R; -import org.thialfihar.android.apg.helper.PGPMain; -import org.thialfihar.android.apg.helper.Preferences; - -import android.app.ListActivity; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.text.Html; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.TextView; - -public class MailListActivity extends ListActivity { - LayoutInflater mInflater = null; - - public static final String EXTRA_ACCOUNT = "account"; - - private static class Conversation { - public long id; - public String subject; - public Vector<Message> messages; - - public Conversation(long id, String subject) { - this.id = id; - this.subject = subject; - } - } - - private static class Message { - public Conversation parent; - public long id; - public String subject; - public String fromAddress; - public String data; - public String replyTo; - public boolean signedOnly; - - public Message(Conversation parent, long id, String subject, String fromAddress, - String replyTo, String data, boolean signedOnly) { - this.parent = parent; - this.id = id; - this.subject = subject; - this.fromAddress = fromAddress; - this.replyTo = replyTo; - this.data = data; - if (this.replyTo == null || this.replyTo.equals("")) { - this.replyTo = this.fromAddress; - } - this.signedOnly = signedOnly; - } - } - - private Vector<Conversation> mConversations; - private Vector<Message> mMessages; - - @Override - protected void onCreate(Bundle savedInstanceState) { - Preferences prefs = Preferences.getPreferences(this); - - super.onCreate(savedInstanceState); - - mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mConversations = new Vector<Conversation>(); - mMessages = new Vector<Message>(); - - String account = getIntent().getExtras().getString(EXTRA_ACCOUNT); - // TODO: what if account is null? - Uri uri = Uri.parse("content://gmail-ls/conversations/" + account); - Cursor cursor = managedQuery(uri, new String[] { "conversation_id", "subject" }, null, - null, null); - for (int i = 0; i < cursor.getCount(); ++i) { - cursor.moveToPosition(i); - - int idIndex = cursor.getColumnIndex("conversation_id"); - int subjectIndex = cursor.getColumnIndex("subject"); - long conversationId = cursor.getLong(idIndex); - Conversation conversation = new Conversation(conversationId, - cursor.getString(subjectIndex)); - Uri messageUri = Uri.withAppendedPath(uri, "" + conversationId + "/messages"); - Cursor messageCursor = managedQuery(messageUri, new String[] { "messageId", "subject", - "fromAddress", "replyToAddresses", "body" }, null, null, null); - Vector<Message> messages = new Vector<Message>(); - for (int j = 0; j < messageCursor.getCount(); ++j) { - messageCursor.moveToPosition(j); - idIndex = messageCursor.getColumnIndex("messageId"); - subjectIndex = messageCursor.getColumnIndex("subject"); - int fromAddressIndex = messageCursor.getColumnIndex("fromAddress"); - int replyToIndex = messageCursor.getColumnIndex("replyToAddresses"); - int bodyIndex = messageCursor.getColumnIndex("body"); - String data = messageCursor.getString(bodyIndex); - data = Html.fromHtml(data).toString(); - boolean signedOnly = false; - Matcher matcher = PGPMain.PGP_MESSAGE.matcher(data); - if (matcher.matches()) { - data = matcher.group(1); - } else { - matcher = PGPMain.PGP_SIGNED_MESSAGE.matcher(data); - if (matcher.matches()) { - data = matcher.group(1); - signedOnly = true; - } else { - data = null; - } - } - Message message = new Message(conversation, messageCursor.getLong(idIndex), - messageCursor.getString(subjectIndex), - messageCursor.getString(fromAddressIndex), - messageCursor.getString(replyToIndex), data, signedOnly); - - messages.add(message); - mMessages.add(message); - } - conversation.messages = messages; - mConversations.add(conversation); - } - - setListAdapter(new MailboxAdapter()); - getListView().setOnItemClickListener(new OnItemClickListener() { - public void onItemClick(AdapterView<?> arg0, View v, int position, long id) { - Intent intent = new Intent(MailListActivity.this, DecryptActivity.class); - intent.setAction(DecryptActivity.ACTION_DECRYPT); - Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position); - intent.putExtra(DecryptActivity.EXTRA_TEXT, message.data); - intent.putExtra(DecryptActivity.EXTRA_SUBJECT, message.subject); - intent.putExtra(DecryptActivity.EXTRA_REPLY_TO, message.replyTo); - startActivity(intent); - } - }); - } - - private class MailboxAdapter extends BaseAdapter implements ListAdapter { - - @Override - public boolean isEnabled(int position) { - Message message = (Message) getItem(position); - return message.data != null; - } - - @Override - public boolean hasStableIds() { - return true; - } - - public int getCount() { - return mMessages.size(); - } - - public Object getItem(int position) { - return mMessages.get(position); - } - - public long getItemId(int position) { - return mMessages.get(position).id; - } - - public View getView(int position, View convertView, ViewGroup parent) { - View view = mInflater.inflate(R.layout.mailbox_message_item, null); - - Message message = (Message) getItem(position); - - TextView subject = (TextView) view.findViewById(R.id.subject); - TextView email = (TextView) view.findViewById(R.id.emailAddress); - ImageView status = (ImageView) view.findViewById(R.id.ic_status); - - subject.setText(message.subject); - email.setText(message.fromAddress); - if (message.data != null) { - if (message.signedOnly) { - status.setImageResource(R.drawable.signed); - } else { - status.setImageResource(R.drawable.encrypted); - } - status.setVisibility(View.VISIBLE); - } else { - status.setVisibility(View.INVISIBLE); - } - - return view; - } - } -} diff --git a/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java index dafc2924b..26387f870 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java @@ -17,9 +17,6 @@ package org.thialfihar.android.apg.ui; -import java.security.Security; - -import org.spongycastle.jce.provider.BouncyCastleProvider; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.R; @@ -33,9 +30,6 @@ import android.os.Bundle; import android.view.View; public class MainActivity extends SherlockActivity { - static { - Security.addProvider(new BouncyCastleProvider()); - } public void manageKeysOnClick(View view) { startActivity(new Intent(this, PublicKeyListActivity.class)); diff --git a/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java index 2d5108cad..0ba476768 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java @@ -19,16 +19,19 @@ package org.thialfihar.android.apg.ui; import org.thialfihar.android.apg.R; import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.Id; -import org.thialfihar.android.apg.deprecated.AskForPassphrase; import org.thialfihar.android.apg.helper.PGPHelper; import org.thialfihar.android.apg.helper.PGPMain; +import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment; +import org.thialfihar.android.apg.util.Log; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -import android.app.Dialog; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.View; @@ -39,6 +42,7 @@ import android.widget.ExpandableListView.OnChildClickListener; import com.google.zxing.integration.android.IntentIntegrator; public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener { + @Override public void onCreate(Bundle savedInstanceState) { mExportFilename = Constants.path.APP_DIR + "/secexport.asc"; @@ -86,7 +90,7 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli menu.add(0, Id.menu.edit, 0, R.string.menu_editKey); menu.add(0, Id.menu.export, 1, R.string.menu_exportKey); menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey); - menu.add(0, Id.menu.share, 2, R.string.menu_share); + menu.add(0, Id.menu.share_qr_code, 2, R.string.menu_share); } } @@ -107,12 +111,13 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli return true; } - case Id.menu.share: { + case Id.menu.share_qr_code: { mSelectedItem = groupPosition; long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()) .getGroupId(mSelectedItem); - String msg = keyId + "," + PGPHelper.getFingerPrint(keyId); + // String msg = keyId + "," + PGPHelper.getFingerPrint(keyId); + String msg = PGPHelper.getPubkeyAsArmoredString(keyId); new IntentIntegrator(this).shareText(msg); } @@ -130,37 +135,43 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli return true; } - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case Id.dialog.pass_phrase: { - long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()) - .getGroupId(mSelectedItem); - return AskForPassphrase.createDialog(this, keyId, this); - } - - default: { - return super.onCreateDialog(id); - } - } - } - public void checkPassPhraseAndEdit() { long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem); String passPhrase = PGPMain.getCachedPassPhrase(keyId); if (passPhrase == null) { - showDialog(Id.dialog.pass_phrase); + showPassphraseDialog(keyId); } else { PGPMain.setEditPassPhrase(passPhrase); editKey(); } } - @Override - public void passPhraseCallback(long keyId, String passPhrase) { - super.passPhraseCallback(keyId, passPhrase); - PGPMain.setEditPassPhrase(passPhrase); - editKey(); + private void showPassphraseDialog(final long secretKeyId) { + // Message is received after passphrase is cached + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { + String passPhrase = PGPMain.getCachedPassPhrase(secretKeyId); + PGPMain.setEditPassPhrase(passPhrase); + editKey(); + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + try { + PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance( + messenger, secretKeyId); + + passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); + } catch (PGPMain.GeneralException e) { + Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); + // send message to handler to start encryption directly + returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); + } } private void createKey() { diff --git a/org_apg/src/org/thialfihar/android/apg/ui/dialog/DeleteKeyDialogFragment.java b/org_apg/src/org/thialfihar/android/apg/ui/dialog/DeleteKeyDialogFragment.java new file mode 100644 index 000000000..4cb1cd02f --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/ui/dialog/DeleteKeyDialogFragment.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thialfihar.android.apg.ui.dialog; + +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.Id; +import org.thialfihar.android.apg.R; +import org.thialfihar.android.apg.helper.PGPHelper; +import org.thialfihar.android.apg.helper.PGPMain; +import org.thialfihar.android.apg.util.Log; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; + +public class DeleteKeyDialogFragment extends DialogFragment { + + private Messenger mMessenger; + + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_DELETE_KEY_RING_ID = "delete_file"; + private static final String ARG_KEY_TYPE = "key_type"; + + public static final int MESSAGE_OKAY = 1; + + /** + * Creates new instance of this delete file dialog fragment + */ + public static DeleteKeyDialogFragment newInstance(Messenger messenger, int deleteKeyRingId, + int keyType) { + DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); + Bundle args = new Bundle(); + + args.putParcelable(ARG_MESSENGER, messenger); + args.putInt(ARG_DELETE_KEY_RING_ID, deleteKeyRingId); + args.putInt(ARG_KEY_TYPE, keyType); + + frag.setArguments(args); + + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity activity = getActivity(); + + final int deleteKeyRingId = getArguments().getInt(ARG_DELETE_KEY_RING_ID); + final int keyType = getArguments().getInt(ARG_KEY_TYPE); + + // TODO: better way to do this? + String userId = "<unknown>"; + Object keyRing = PGPMain.getKeyRing(deleteKeyRingId); + if (keyRing != null) { + if (keyRing instanceof PGPPublicKeyRing) { + userId = PGPHelper.getMainUserIdSafe(activity, + PGPHelper.getMasterKey((PGPPublicKeyRing) keyRing)); + } else { + userId = PGPHelper.getMainUserIdSafe(activity, + PGPHelper.getMasterKey((PGPSecretKeyRing) keyRing)); + } + } + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.warning); + builder.setMessage(getString( + keyType == Id.type.public_key ? R.string.keyDeletionConfirmation + : R.string.secretKeyDeletionConfirmation, userId)); + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // deleteKey(deleteKeyRingId); + PGPMain.deleteKey(deleteKeyRingId); + + dismiss(); + + sendMessageToHandler(MESSAGE_OKAY); + } + }); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dismiss(); + } + }); + return builder.create(); + } + + /** + * Send message back to handler which is initialized in a activity + * + * @param what + * Message integer you want to send + */ + private void sendMessageToHandler(Integer what) { + Message msg = Message.obtain(); + msg.what = what; + + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } +}
\ No newline at end of file diff --git a/org_apg/src/org/thialfihar/android/apg/ui/dialog/LookupUnknownKeyDialogFragment.java b/org_apg/src/org/thialfihar/android/apg/ui/dialog/LookupUnknownKeyDialogFragment.java new file mode 100644 index 000000000..9797abc2a --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/ui/dialog/LookupUnknownKeyDialogFragment.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thialfihar.android.apg.ui.dialog; + +import org.thialfihar.android.apg.helper.PGPHelper; +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.Id; +import org.thialfihar.android.apg.R; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.DialogFragment; + +import org.thialfihar.android.apg.ui.KeyServerQueryActivity; +import org.thialfihar.android.apg.util.Log; + +public class LookupUnknownKeyDialogFragment extends DialogFragment { + + private Messenger mMessenger; + + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_UNKNOWN_KEY_ID = "unknown_key_id"; + + public static final int MESSAGE_OKAY = 1; + public static final int MESSAGE_CANCEL = 2; + + /** + * Creates new instance of this dialog fragment + * + * @param messenger + * @param unknownKeyId + * @return + */ + public static LookupUnknownKeyDialogFragment newInstance(Messenger messenger, long unknownKeyId) { + LookupUnknownKeyDialogFragment frag = new LookupUnknownKeyDialogFragment(); + Bundle args = new Bundle(); + args.putLong(ARG_UNKNOWN_KEY_ID, unknownKeyId); + args.putParcelable(ARG_MESSENGER, messenger); + + frag.setArguments(args); + + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + final long unknownKeyId = getArguments().getLong(ARG_UNKNOWN_KEY_ID); + mMessenger = getArguments().getParcelable(ARG_MESSENGER); + + AlertDialog.Builder alert = new AlertDialog.Builder(activity); + + alert.setIcon(android.R.drawable.ic_dialog_alert); + alert.setTitle(R.string.title_unknownSignatureKey); + alert.setMessage(getString(R.string.lookupUnknownKey, + PGPHelper.getSmallFingerPrint(unknownKeyId))); + + alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dismiss(); + + sendMessageToHandler(MESSAGE_OKAY); + + Intent intent = new Intent(activity, KeyServerQueryActivity.class); + intent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID); + intent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, unknownKeyId); + startActivityForResult(intent, Id.request.look_up_key_id); + } + }); + alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dismiss(); + + sendMessageToHandler(MESSAGE_CANCEL); + } + }); + alert.setCancelable(true); + alert.setOnCancelListener(new OnCancelListener() { + + @Override + public void onCancel(DialogInterface dialog) { + sendMessageToHandler(MESSAGE_CANCEL); + } + }); + + return alert.create(); + } + + /** + * Send message back to handler which is initialized in a activity + * + * @param what + * Message integer you want to send + */ + private void sendMessageToHandler(Integer what) { + Message msg = Message.obtain(); + msg.what = what; + + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } +}
\ No newline at end of file |