reworked openpgp integration part #1

Daniel Gultsch created

Change summary

libs/openpgp-keychain                                               |   2 
project.properties                                                  |   4 
res/values/strings.xml                                              |   1 
src/eu/siacs/conversations/crypto/OnPgpEngineResult.java            |  11 
src/eu/siacs/conversations/crypto/PgpEngine.java                    | 209 
src/eu/siacs/conversations/entities/Account.java                    |  12 
src/eu/siacs/conversations/entities/Message.java                    |   1 
src/eu/siacs/conversations/services/XmppConnectionService.java      | 258 
src/eu/siacs/conversations/ui/ConversationFragment.java             | 162 
src/eu/siacs/conversations/ui/ManageAccountActivity.java            |  52 
src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java |   2 
11 files changed, 445 insertions(+), 269 deletions(-)

Detailed changes

libs/openpgp-keychain πŸ”—

@@ -1 +1 @@
-Subproject commit 098823bd525bdbf215060dba1ed248af853bbfac
+Subproject commit e0a0bf04ee6fa4794a82b44dae905bc814d85491

project.properties πŸ”—

@@ -12,5 +12,5 @@
 
 # Project target.
 target=android-19
-android.library.reference.1=libs/openpgp-keychain/OpenPGP-Keychain-API/libraries/openpgp-api-library
-android.library.reference.2=libs/minidns
+android.library.reference.1=libs/minidns
+android.library.reference.2=libs/openpgp-keychain/OpenKeychain-API/libraries/openpgp-api-library

res/values/strings.xml πŸ”—

@@ -78,4 +78,5 @@
     <string name="contact_offline_otr">Sending OTR encrypted messages to an offline contact is unfortunately not supported.\nWould you like to send the message in plain text?</string>
     <string name="contact_offline_file">Sending files to an offline contact is unfortunately not supported.</string>
     <string name="send_unencrypted">Send unencrypted</string>
+    <string name="decryption_failed">Decrpytion failed. Maybe you don’t have the proper private key.</string>
 </resources>

src/eu/siacs/conversations/crypto/OnPgpEngineResult.java πŸ”—

@@ -0,0 +1,11 @@
+package eu.siacs.conversations.crypto;
+
+import org.openintents.openpgp.OpenPgpError;
+
+import android.app.PendingIntent;
+
+public interface OnPgpEngineResult {
+	public void success();
+	public void error(OpenPgpError openPgpError);
+	public void userInputRequried(PendingIntent pi);
+}

src/eu/siacs/conversations/crypto/PgpEngine.java πŸ”—

@@ -3,12 +3,16 @@ package eu.siacs.conversations.crypto;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.io.OutputStream;
 
 import org.openintents.openpgp.OpenPgpError;
 import org.openintents.openpgp.OpenPgpSignatureResult;
 import org.openintents.openpgp.util.OpenPgpApi;
+import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
 
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Message;
 
 import android.app.PendingIntent;
 import android.content.Intent;
@@ -21,66 +25,80 @@ public class PgpEngine {
 		this.api = api;
 	}
 
-	public String decrypt(Account account, String message) throws UserInputRequiredException,
-			OpenPgpException {
+	public void decrypt(final Message message, final OnPgpEngineResult callback) {
 		Intent params = new Intent();
 		params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
-		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
-		InputStream is = new ByteArrayInputStream(message.getBytes());
-		ByteArrayOutputStream os = new ByteArrayOutputStream();
-		Intent result = api.executeApi(params, is, os);
-		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
-		case OpenPgpApi.RESULT_CODE_SUCCESS:
-			return os.toString();
-		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
-		case OpenPgpApi.RESULT_CODE_ERROR:
-			throw new OpenPgpException(
-					(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
-		default:
-			return null;
-		}
+		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
+				.getConversation().getAccount().getJid());
+		InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
+		final OutputStream os = new ByteArrayOutputStream();
+		api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+
+			@Override
+			public void onReturn(Intent result) {
+				switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+						OpenPgpApi.RESULT_CODE_ERROR)) {
+				case OpenPgpApi.RESULT_CODE_SUCCESS:
+					message.setBody(os.toString());
+					message.setEncryption(Message.ENCRYPTION_DECRYPTED);
+					callback.success();
+					return;
+				case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+					callback.userInputRequried((PendingIntent) result
+							.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+					return;
+				case OpenPgpApi.RESULT_CODE_ERROR:
+					callback.error((OpenPgpError) result
+							.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
+					return;
+				default:
+					return;
+				}
+			}
+		});
 	}
 
-	public String encrypt(Account account, long keyId, String message) throws UserInputRequiredException, OpenPgpException {
-		Log.d("xmppService","called to pgpengine::encrypt");
-		long[] keys = {keyId};
+	public void encrypt(Account account, long keyId, Message message,
+			final OnPgpEngineResult callback) {
+		Log.d("xmppService", "called to pgpengine::encrypt");
+		long[] keys = { keyId };
 		Intent params = new Intent();
 		params.setAction(OpenPgpApi.ACTION_ENCRYPT);
-		params.putExtra(OpenPgpApi.EXTRA_KEY_IDS,keys);
+		params.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keys);
 		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
 		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
-		
-		InputStream is = new ByteArrayInputStream(message.getBytes());
+
+		InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
 		ByteArrayOutputStream os = new ByteArrayOutputStream();
 		Intent result = api.executeApi(params, is, os);
-		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
+		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+				OpenPgpApi.RESULT_CODE_ERROR)) {
 		case OpenPgpApi.RESULT_CODE_SUCCESS:
 			StringBuilder encryptedMessageBody = new StringBuilder();
 			String[] lines = os.toString().split("\n");
 			for (int i = 3; i < lines.length - 1; ++i) {
 				encryptedMessageBody.append(lines[i].trim());
 			}
-			Log.d("xmppService","encrpyted message: "+encryptedMessageBody.toString());
-			return encryptedMessageBody.toString();
+			message.setEncryptedBody(encryptedMessageBody.toString());
+			callback.success();
+			return;
 		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-			Log.d("xmppService","user input required");
-			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+			callback.userInputRequried((PendingIntent) result
+					.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+			return;
 		case OpenPgpApi.RESULT_CODE_ERROR:
-			OpenPgpError error = (OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
-			throw new OpenPgpException(error);
-		default:
-			return null;
+			callback.error((OpenPgpError) result
+					.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
+			return;
 		}
 	}
 
-	public long fetchKeyId(Account account, String status, String signature)
-			throws OpenPgpException {
-		if ((signature==null)||(api==null)) {
+	public long fetchKeyId(Account account, String status, String signature) {
+		if ((signature == null) || (api == null)) {
 			return 0;
 		}
-		if (status==null) {
-			status="";
+		if (status == null) {
+			status = "";
 		}
 		StringBuilder pgpSig = new StringBuilder();
 		pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
@@ -97,75 +115,90 @@ public class PgpEngine {
 		Intent params = new Intent();
 		params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
 		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
 		InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
 		ByteArrayOutputStream os = new ByteArrayOutputStream();
 		Intent result = api.executeApi(params, is, os);
-		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
+		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
+				OpenPgpApi.RESULT_CODE_ERROR)) {
 		case OpenPgpApi.RESULT_CODE_SUCCESS:
-			OpenPgpSignatureResult sigResult
-            = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
-			if (sigResult==null) {
-				return 0;
-			} else {
+			OpenPgpSignatureResult sigResult = result
+					.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
+			if (sigResult != null) {
 				return sigResult.getKeyId();
+			} else {
+				return 0;
 			}
 		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-			break;
+			Log.d("xmppService","user interaction required");
+			return 0;
 		case OpenPgpApi.RESULT_CODE_ERROR:
-			throw new OpenPgpException(
-					(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
+			Log.d("xmppService","pgp error");
+			return 0;
 		}
 		return 0;
 	}
 
-	public String generateSignature(Account account, String status)
-			throws UserInputRequiredException {
+	public void generateSignature(final Account account, String status,
+			final OnPgpEngineResult callback) {
 		Intent params = new Intent();
 		params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
 		params.setAction(OpenPgpApi.ACTION_SIGN);
 		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
 		InputStream is = new ByteArrayInputStream(status.getBytes());
-		ByteArrayOutputStream os = new ByteArrayOutputStream();
-		Intent result = api.executeApi(params, is, os);
-		StringBuilder signatureBuilder = new StringBuilder();
-		switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
-		case OpenPgpApi.RESULT_CODE_SUCCESS:
-			String[] lines = os.toString().split("\n");
-			for (int i = 7; i < lines.length - 1; ++i) {
-				signatureBuilder.append(lines[i].trim());
+		final OutputStream os = new ByteArrayOutputStream();
+		api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+
+			@Override
+			public void onReturn(Intent result) {
+				switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
+				case OpenPgpApi.RESULT_CODE_SUCCESS:
+					StringBuilder signatureBuilder = new StringBuilder();
+					String[] lines = os.toString().split("\n");
+					for (int i = 7; i < lines.length - 1; ++i) {
+						signatureBuilder.append(lines[i].trim());
+					}
+					account.setKey("pgp_signature", signatureBuilder.toString());
+					callback.success();
+					return;
+				case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+					callback.userInputRequried((PendingIntent) result
+							.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+					return;
+				case OpenPgpApi.RESULT_CODE_ERROR:
+					callback.error((OpenPgpError) result
+							.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
+					return;
+				}
 			}
-			break;
-		case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-			throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
-		case OpenPgpApi.RESULT_CODE_ERROR:
-			break;
-		}
-		return signatureBuilder.toString();
-	}
-
-	public class UserInputRequiredException extends Exception {
-		private static final long serialVersionUID = -6913480043269132016L;
-		private PendingIntent pi;
-
-		public UserInputRequiredException(PendingIntent pi) {
-			this.pi = pi;
-		}
-
-		public PendingIntent getPendingIntent() {
-			return this.pi;
-		}
+		});
 	}
-
-	public class OpenPgpException extends Exception {
-		private static final long serialVersionUID = -7324789703473056077L;
-		private OpenPgpError error;
-
-		public OpenPgpException(OpenPgpError openPgpError) {
-			this.error = openPgpError;
-		}
-
-		public OpenPgpError getOpenPgpError() {
-			return this.error;
-		}
+	
+	public void hasKey(Account account, long keyId, final OnPgpEngineResult callback) {
+		Intent params = new Intent();
+		params.setAction(OpenPgpApi.ACTION_GET_KEY);
+		params.putExtra(OpenPgpApi.EXTRA_KEY_ID, keyId);
+		params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
+		InputStream is = new ByteArrayInputStream(new byte[0]);
+		OutputStream os = new ByteArrayOutputStream();
+		api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
+			
+			@Override
+			public void onReturn(Intent result) {
+				switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
+				case OpenPgpApi.RESULT_CODE_SUCCESS:
+					callback.success();
+					return;
+				case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
+					callback.userInputRequried((PendingIntent) result
+							.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+					return;
+				case OpenPgpApi.RESULT_CODE_ERROR:
+					callback.error((OpenPgpError) result
+							.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
+					return;
+				}
+			}
+		});
 	}
 }

src/eu/siacs/conversations/entities/Account.java πŸ”—

@@ -275,4 +275,16 @@ public class Account  extends AbstractEntity{
 	public int countPresences() {
 		return this.presences.size();
 	}
+
+	public String getPgpSignature() {
+		if (keys.has("pgp_signature")) {
+			try {
+				return keys.getString("pgp_signature");
+			} catch (JSONException e) {
+				return null;
+			}
+		} else {
+			return null;
+		}
+	}
 }

src/eu/siacs/conversations/entities/Message.java πŸ”—

@@ -24,6 +24,7 @@ public class Message extends AbstractEntity {
 	public static final int ENCRYPTION_PGP = 1;
 	public static final int ENCRYPTION_OTR = 2;
 	public static final int ENCRYPTION_DECRYPTED = 3;
+	public static final int ENCRYPTION_DECRYPTION_FAILED = 4;
 	
 	public static final int TYPE_TEXT = 0;
 	public static final int TYPE_IMAGE = 1;

src/eu/siacs/conversations/services/XmppConnectionService.java πŸ”—

@@ -10,6 +10,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Random;
 
+import org.openintents.openpgp.OpenPgpError;
 import org.openintents.openpgp.util.OpenPgpApi;
 import org.openintents.openpgp.util.OpenPgpServiceConnection;
 
@@ -17,8 +18,8 @@ import net.java.otr4j.OtrException;
 import net.java.otr4j.session.Session;
 import net.java.otr4j.session.SessionStatus;
 
+import eu.siacs.conversations.crypto.OnPgpEngineResult;
 import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
@@ -88,8 +89,9 @@ public class XmppConnectionService extends Service {
 
 	private List<Account> accounts;
 	private List<Conversation> conversations = null;
-	private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this);
-	
+	private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
+			this);
+
 	public OnConversationListChangedListener convChangedListener = null;
 	private int convChangedListenerCount = 0;
 	private OnAccountListChangedListener accountChangedListener = null;
@@ -123,8 +125,9 @@ public class XmppConnectionService extends Service {
 				MessagePacket packet) {
 			Message message = null;
 			boolean notify = true;
-			if(getPreferences().getBoolean("notification_grace_period_after_carbon_received", true)){
-				notify=(SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD;
+			if (getPreferences().getBoolean(
+					"notification_grace_period_after_carbon_received", true)) {
+				notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD;
 			}
 
 			if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
@@ -133,7 +136,8 @@ public class XmppConnectionService extends Service {
 					message = MessageParser.parsePgpChat(pgpBody, packet,
 							account, service);
 					message.markUnread();
-				} else if ((packet.getBody()!=null) && (packet.getBody().startsWith("?OTR"))) {
+				} else if ((packet.getBody() != null)
+						&& (packet.getBody().startsWith("?OTR"))) {
 					message = MessageParser.parseOtrChat(packet, account,
 							service);
 					if (message != null) {
@@ -149,7 +153,8 @@ public class XmppConnectionService extends Service {
 							service);
 					if (message != null) {
 						if (message.getStatus() == Message.STATUS_SEND) {
-							lastCarbonMessageReceived = SystemClock.elapsedRealtime();
+							lastCarbonMessageReceived = SystemClock
+									.elapsedRealtime();
 							notify = false;
 							message.getConversation().markRead();
 						} else {
@@ -242,7 +247,8 @@ public class XmppConnectionService extends Service {
 				databaseBackend.updateAccount(account);
 				reconnectAccount(account, true);
 			} else {
-				UIHelper.showErrorNotification(getApplicationContext(), getAccounts());
+				UIHelper.showErrorNotification(getApplicationContext(),
+						getAccounts());
 			}
 		}
 	};
@@ -250,20 +256,25 @@ public class XmppConnectionService extends Service {
 	private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() {
 
 		@Override
-		public void onPresencePacketReceived(Account account,
+		public void onPresencePacketReceived(final Account account,
 				PresencePacket packet) {
-			if (packet.hasChild("x","http://jabber.org/protocol/muc#user")) {
+			if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
 				Conversation muc = findMuc(
 						packet.getAttribute("from").split("/")[0], account);
 				if (muc != null) {
 					muc.getMucOptions().processPacket(packet);
 				} else {
-					Log.d(LOGTAG,account.getJid()+": could not find muc for received muc package "+packet.toString());
+					Log.d(LOGTAG, account.getJid()
+							+ ": could not find muc for received muc package "
+							+ packet.toString());
 				}
-			} else if (packet.hasChild("x","http://jabber.org/protocol/muc")) {
-				Conversation muc = findMuc(packet.getAttribute("from").split("/")[0], account);
+			} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
+				Conversation muc = findMuc(
+						packet.getAttribute("from").split("/")[0], account);
 				if (muc != null) {
-					Log.d(LOGTAG,account.getJid()+": reading muc status packet "+packet.toString());
+					Log.d(LOGTAG,
+							account.getJid() + ": reading muc status packet "
+									+ packet.toString());
 					int error = muc.getMucOptions().getError();
 					muc.getMucOptions().processPacket(packet);
 					if ((muc.getMucOptions().getError() != error)
@@ -276,50 +287,52 @@ public class XmppConnectionService extends Service {
 				String[] fromParts = packet.getAttribute("from").split("/");
 				String type = packet.getAttribute("type");
 				if (fromParts[0].equals(account.getJid())) {
-					if (fromParts.length==2) {
+					if (fromParts.length == 2) {
 						if (type == null) {
-							account.updatePresence(fromParts[1],Presences.parseShow(packet.findChild("show")));
+							account.updatePresence(fromParts[1], Presences
+									.parseShow(packet.findChild("show")));
 						} else if (type.equals("unavailable")) {
 							account.removePresence(fromParts[1]);
 						}
 					}
-						
+
 				} else {
 					Contact contact = findContact(account, fromParts[0]);
 					if (contact == null) {
 						if ("subscribe".equals(type)) {
-							account.getXmppConnection().addPendingSubscription(fromParts[0]);
+							account.getXmppConnection().addPendingSubscription(
+									fromParts[0]);
 						} else {
-							//Log.d(LOGTAG,packet.getFrom()+ " could not be found");
+							// Log.d(LOGTAG,packet.getFrom()+
+							// " could not be found");
 						}
 						return;
 					}
 					if (type == null) {
 						if (fromParts.length == 2) {
-							contact.updatePresence(fromParts[1], Presences.parseShow(packet.findChild("show")));
+							contact.updatePresence(fromParts[1], Presences
+									.parseShow(packet.findChild("show")));
 							PgpEngine pgp = getPgpEngine();
 							if (pgp != null) {
-								Element x = packet.findChild("x","jabber:x:signed");
+								Element x = packet.findChild("x",
+										"jabber:x:signed");
 								if (x != null) {
-									try {
-										Element status = packet.findChild("status");
-										String msg;
-										if (status!=null) {
-											msg = status.getContent();
-										} else {
-											msg = "";
-										}
-										contact.setPgpKeyId(pgp.fetchKeyId(account,msg, x
-														.getContent()));
-									} catch (OpenPgpException e) {
-										Log.d(LOGTAG, "faulty pgp. just ignore");
+									Element status = packet.findChild("status");
+									String msg;
+									if (status != null) {
+										msg = status.getContent();
+									} else {
+										msg = "";
 									}
+									contact.setPgpKeyId(pgp.fetchKeyId(account,msg,x.getContent()));
+									Log.d("xmppService","fetched key id for "+contact.getDisplayName()+" was:"+contact.getPgpKeyId());
 								}
 							}
-							replaceContactInConversation(account,contact.getJid(), contact);
-							databaseBackend.updateContact(contact,true);
+							replaceContactInConversation(account,
+									contact.getJid(), contact);
+								databaseBackend.updateContact(contact, true);
 						} else {
-							//Log.d(LOGTAG,"presence without resource "+packet.toString());
+							// Log.d(LOGTAG,"presence without resource "+packet.toString());
 						}
 					} else if (type.equals("unavailable")) {
 						if (fromParts.length != 2) {
@@ -327,19 +340,21 @@ public class XmppConnectionService extends Service {
 						} else {
 							contact.removePresence(fromParts[1]);
 						}
-						replaceContactInConversation(account,contact.getJid(), contact);
-						databaseBackend.updateContact(contact,true);
+						replaceContactInConversation(account, contact.getJid(),
+								contact);
+						databaseBackend.updateContact(contact, true);
 					} else if (type.equals("subscribe")) {
-						Log.d(LOGTAG,"received subscribe packet from "+packet.getFrom());
+						Log.d(LOGTAG, "received subscribe packet from "
+								+ packet.getFrom());
 						if (contact
 								.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
-							Log.d(LOGTAG,"preemptive grant; granting");
+							Log.d(LOGTAG, "preemptive grant; granting");
 							sendPresenceUpdatesTo(contact);
 							contact.setSubscriptionOption(Contact.Subscription.FROM);
 							contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
-							replaceContactInConversation(account,contact.getJid(),
-									contact);
-							databaseBackend.updateContact(contact,false);
+							replaceContactInConversation(account,
+									contact.getJid(), contact);
+							databaseBackend.updateContact(contact, false);
 							if ((contact
 									.getSubscriptionOption(Contact.Subscription.ASKING))
 									&& (!contact
@@ -347,10 +362,11 @@ public class XmppConnectionService extends Service {
 								requestPresenceUpdatesFrom(contact);
 							}
 						} else {
-							account.getXmppConnection().addPendingSubscription(fromParts[0]);
+							account.getXmppConnection().addPendingSubscription(
+									fromParts[0]);
 						}
 					} else {
-						//Log.d(LOGTAG, packet.toString());
+						// Log.d(LOGTAG, packet.toString());
 					}
 				}
 			}
@@ -368,16 +384,20 @@ public class XmppConnectionService extends Service {
 					processRosterItems(account, query);
 					mergePhoneContactsWithRoster(null);
 				}
-			} else if (packet.hasChild("open","http://jabber.org/protocol/ibb")||packet.hasChild("data","http://jabber.org/protocol/ibb")) {
-				XmppConnectionService.this.mJingleConnectionManager.deliverIbbPacket(account,packet);
+			} else if (packet
+					.hasChild("open", "http://jabber.org/protocol/ibb")
+					|| packet
+							.hasChild("data", "http://jabber.org/protocol/ibb")) {
+				XmppConnectionService.this.mJingleConnectionManager
+						.deliverIbbPacket(account, packet);
 			} else {
-				Log.d(LOGTAG,"iq packet arrived "+packet.toString());
+				Log.d(LOGTAG, "iq packet arrived " + packet.toString());
 			}
 		}
 	};
-	
+
 	private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
-		
+
 		@Override
 		public void onJinglePacketReceived(Account account, JinglePacket packet) {
 			mJingleConnectionManager.deliverPacket(account, packet);
@@ -408,32 +428,33 @@ public class XmppConnectionService extends Service {
 	public FileBackend getFileBackend() {
 		return this.fileBackend;
 	}
-	
-	public void attachImageToConversation(final Conversation conversation, final String presence, final Uri uri) {
+
+	public void attachImageToConversation(final Conversation conversation,
+			final String presence, final Uri uri) {
 		new Thread(new Runnable() {
-			
+
 			@Override
 			public void run() {
-				Message message = new Message(conversation, "", Message.ENCRYPTION_NONE);
+				Message message = new Message(conversation, "",
+						Message.ENCRYPTION_NONE);
 				message.setPresence(presence);
 				message.setType(Message.TYPE_IMAGE);
 				message.setStatus(Message.STATUS_PREPARING);
 				conversation.getMessages().add(message);
-				if (convChangedListener!=null) {
+				if (convChangedListener != null) {
 					convChangedListener.onConversationListChanged();
 				}
 				getFileBackend().copyImageToPrivateStorage(message, uri);
 				message.setStatus(Message.STATUS_OFFERED);
 				databaseBackend.createMessage(message);
-				if (convChangedListener!=null) {
+				if (convChangedListener != null) {
 					convChangedListener.onConversationListChanged();
 				}
 				sendMessage(message, null);
 			}
 		}).start();
 	}
-	
-	
+
 	protected Conversation findMuc(String name, Account account) {
 		for (Conversation conversation : this.conversations) {
 			if (conversation.getContactJid().split("/")[0].equals(name)
@@ -468,21 +489,24 @@ public class XmppConnectionService extends Service {
 				} else {
 					if (subscription.equals("remove")) {
 						databaseBackend.deleteContact(contact);
-						replaceContactInConversation(account,contact.getJid(), null);
+						replaceContactInConversation(account, contact.getJid(),
+								null);
 					} else {
 						contact.parseSubscriptionFromElement(item);
-						databaseBackend.updateContact(contact,false);
-						replaceContactInConversation(account,contact.getJid(), contact);
+						databaseBackend.updateContact(contact, false);
+						replaceContactInConversation(account, contact.getJid(),
+								contact);
 					}
 				}
 			}
 		}
 	}
 
-	private void replaceContactInConversation(Account account, String jid, Contact contact) {
+	private void replaceContactInConversation(Account account, String jid,
+			Contact contact) {
 		List<Conversation> conversations = getConversations();
 		for (Conversation c : conversations) {
-			if (c.getContactJid().equals(jid)&&(c.getAccount()==account)) {
+			if (c.getContactJid().equals(jid) && (c.getAccount() == account)) {
 				c.setContact(contact);
 				break;
 			}
@@ -575,12 +599,13 @@ public class XmppConnectionService extends Service {
 	@Override
 	public void onCreate() {
 		ExceptionHelper.init(getApplicationContext());
-		this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
+		this.databaseBackend = DatabaseBackend
+				.getInstance(getApplicationContext());
 		this.fileBackend = new FileBackend(getApplicationContext());
 		this.accounts = databaseBackend.getAccounts();
 
 		this.getConversations();
-		
+
 		getContentResolver().registerContentObserver(
 				ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
 		this.pgpServiceConnection = new OpenPgpServiceConnection(
@@ -644,7 +669,8 @@ public class XmppConnectionService extends Service {
 
 	public XmppConnection createConnection(Account account) {
 		SharedPreferences sharedPref = getPreferences();
-		account.setResource(sharedPref.getString("resource", "mobile").toLowerCase(Locale.getDefault()));
+		account.setResource(sharedPref.getString("resource", "mobile")
+				.toLowerCase(Locale.getDefault()));
 		XmppConnection connection = new XmppConnection(account, this.pm);
 		connection.setOnMessagePacketReceivedListener(this.messageListener);
 		connection.setOnStatusChangedListener(this.statusListener);
@@ -697,7 +723,8 @@ public class XmppConnectionService extends Service {
 				if (message.getEncryption() == Message.ENCRYPTION_OTR) {
 					if (!conv.hasValidOtrSession()) {
 						// starting otr session. messages will be send later
-						conv.startOtrSession(getApplicationContext(), presence,true);
+						conv.startOtrSession(getApplicationContext(), presence,
+								true);
 					} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
 						// otr session aleary exists, creating message packet
 						// accordingly
@@ -718,7 +745,8 @@ public class XmppConnectionService extends Service {
 							.getFullJid());
 					packet.setTo(message.getCounterpart());
 					packet.setBody("This is an XEP-0027 encryted message");
-					packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody());
+					packet.addChild("x", "jabber:x:encrypted").setContent(
+							message.getEncryptedBody());
 					message.setStatus(Message.STATUS_SEND);
 					message.setEncryption(Message.ENCRYPTION_DECRYPTED);
 					saveInDb = true;
@@ -751,7 +779,7 @@ public class XmppConnectionService extends Service {
 				convChangedListener.onConversationListChanged();
 			}
 		}
-		if ((send)&&(packet!=null)) {
+		if ((send) && (packet != null)) {
 			account.getXmppConnection().sendMessagePacket(packet);
 		}
 
@@ -759,7 +787,8 @@ public class XmppConnectionService extends Service {
 
 	private void sendUnsendMessages(Conversation conversation) {
 		for (int i = 0; i < conversation.getMessages().size(); ++i) {
-			if ((conversation.getMessages().get(i).getStatus() == Message.STATUS_UNSEND)&&(conversation.getMessages().get(i).getEncryption() == Message.ENCRYPTION_NONE)) {
+			if ((conversation.getMessages().get(i).getStatus() == Message.STATUS_UNSEND)
+					&& (conversation.getMessages().get(i).getEncryption() == Message.ENCRYPTION_NONE)) {
 				Message message = conversation.getMessages().get(i);
 				MessagePacket packet = prepareMessagePacket(
 						conversation.getAccount(), message, null);
@@ -792,8 +821,8 @@ public class XmppConnectionService extends Service {
 									+ ": could not encrypt message to "
 									+ message.getCounterpart());
 				}
-				packet.addChild("private","urn:xmpp:carbons:2");
-				packet.addChild("no-copy","urn:xmpp:hints");
+				packet.addChild("private", "urn:xmpp:carbons:2");
+				packet.addChild("no-copy", "urn:xmpp:hints");
 				packet.setTo(otrSession.getSessionID().getAccountID() + "/"
 						+ otrSession.getSessionID().getUserID());
 				packet.setFrom(account.getFullJid());
@@ -840,7 +869,8 @@ public class XmppConnectionService extends Service {
 		} else {
 			Log.d(LOGTAG, account.getJid() + ": fetching roster");
 		}
-		iqPacket.query("jabber:iq:roster").setAttribute("ver", account.getRosterVersion());
+		iqPacket.query("jabber:iq:roster").setAttribute("ver",
+				account.getRosterVersion());
 		account.getXmppConnection().sendIqPacket(iqPacket,
 				new OnIqPacketReceived() {
 
@@ -870,8 +900,8 @@ public class XmppConnectionService extends Service {
 									.getContacts(mWhere.toString());
 							for (Contact contact : contactsToDelete) {
 								databaseBackend.deleteContact(contact);
-								replaceContactInConversation(account,contact.getJid(),
-										null);
+								replaceContactInConversation(account,
+										contact.getJid(), null);
 							}
 
 						} else {
@@ -914,16 +944,19 @@ public class XmppConnectionService extends Service {
 										.getString("photouri"));
 								contact.setDisplayName(phoneContact
 										.getString("displayname"));
-								databaseBackend.updateContact(contact,false);
-								replaceContactInConversation(contact.getAccount(),contact.getJid(),
+								databaseBackend.updateContact(contact, false);
+								replaceContactInConversation(
+										contact.getAccount(), contact.getJid(),
 										contact);
 							} else {
 								if ((contact.getSystemAccount() != null)
 										|| (contact.getProfilePhoto() != null)) {
 									contact.setSystemAccount(null);
 									contact.setPhotoUri(null);
-									databaseBackend.updateContact(contact,false);
-									replaceContactInConversation(contact.getAccount(),
+									databaseBackend.updateContact(contact,
+											false);
+									replaceContactInConversation(
+											contact.getAccount(),
 											contact.getJid(), contact);
 								}
 							}
@@ -1014,7 +1047,8 @@ public class XmppConnectionService extends Service {
 			this.databaseBackend.createConversation(conversation);
 		}
 		this.conversations.add(conversation);
-		if ((account.getStatus() == Account.STATUS_ONLINE)&&(conversation.getMode() == Conversation.MODE_MULTI)) {
+		if ((account.getStatus() == Account.STATUS_ONLINE)
+				&& (conversation.getMode() == Conversation.MODE_MULTI)) {
 			joinMuc(conversation);
 		}
 		if (this.convChangedListener != null) {
@@ -1035,7 +1069,7 @@ public class XmppConnectionService extends Service {
 			this.convChangedListener.onConversationListChanged();
 		}
 	}
-	
+
 	public void clearConversationHistory(Conversation conversation) {
 		this.databaseBackend.deleteMessagesInConversation(conversation);
 		this.fileBackend.removeFiles(conversation);
@@ -1060,9 +1094,11 @@ public class XmppConnectionService extends Service {
 	public void deleteContact(Contact contact) {
 		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
 		Element query = iq.query("jabber:iq:roster");
-		query.addChild("item").setAttribute("jid", contact.getJid()).setAttribute("subscription", "remove");
+		query.addChild("item").setAttribute("jid", contact.getJid())
+				.setAttribute("subscription", "remove");
 		contact.getAccount().getXmppConnection().sendIqPacket(iq, null);
-		replaceContactInConversation(contact.getAccount(),contact.getJid(), null);
+		replaceContactInConversation(contact.getAccount(), contact.getJid(),
+				null);
 		databaseBackend.deleteContact(contact);
 	}
 
@@ -1092,7 +1128,7 @@ public class XmppConnectionService extends Service {
 
 	public void removeOnConversationListChangedListener() {
 		this.convChangedListenerCount--;
-		if (this.convChangedListenerCount==0) {
+		if (this.convChangedListenerCount == 0) {
 			this.convChangedListener = null;
 		}
 	}
@@ -1159,6 +1195,9 @@ public class XmppConnectionService extends Service {
 						renameListener.onRename(success);
 					}
 					if (success) {
+						String jid = conversation.getContactJid().split("/")[0] + "/"
+								+ nick;
+						conversation.setContactJid(jid);
 						databaseBackend.updateConversation(conversation);
 					}
 				}
@@ -1184,10 +1223,11 @@ public class XmppConnectionService extends Service {
 
 	public void leaveMuc(Conversation conversation) {
 		PresencePacket packet = new PresencePacket();
-		packet.setAttribute("to", conversation.getContactJid().split("/")[0] + "/" + conversation.getMucOptions().getNick());
+		packet.setAttribute("to", conversation.getContactJid().split("/")[0]
+				+ "/" + conversation.getMucOptions().getNick());
 		packet.setAttribute("from", conversation.getAccount().getFullJid());
 		packet.setAttribute("type", "unavailable");
-		Log.d(LOGTAG,"send leaving muc " + packet);
+		Log.d(LOGTAG, "send leaving muc " + packet);
 		conversation.getAccount().getXmppConnection()
 				.sendPresencePacket(packet);
 		conversation.getMucOptions().setOffline();
@@ -1219,8 +1259,9 @@ public class XmppConnectionService extends Service {
 	}
 
 	public void updateContact(Contact contact) {
-		databaseBackend.updateContact(contact,false);
-		replaceContactInConversation(contact.getAccount(),contact.getJid(), contact);
+		databaseBackend.updateContact(contact, false);
+		replaceContactInConversation(contact.getAccount(), contact.getJid(),
+				contact);
 	}
 
 	public void updateMessage(Message message) {
@@ -1247,12 +1288,14 @@ public class XmppConnectionService extends Service {
 		account.getXmppConnection().sendIqPacket(iq, null);
 		if (autoGrant) {
 			requestPresenceUpdatesFrom(contact);
-			if (account.getXmppConnection().hasPendingSubscription(contact.getJid())) {
-				Log.d("xmppService","contact had pending subscription");
+			if (account.getXmppConnection().hasPendingSubscription(
+					contact.getJid())) {
+				Log.d("xmppService", "contact had pending subscription");
 				sendPresenceUpdatesTo(contact);
 			}
 		}
-		replaceContactInConversation(contact.getAccount(),contact.getJid(), contact);
+		replaceContactInConversation(contact.getAccount(), contact.getJid(),
+				contact);
 	}
 
 	public void requestPresenceUpdatesFrom(Contact contact) {
@@ -1308,23 +1351,13 @@ public class XmppConnectionService extends Service {
 		account.getXmppConnection().sendPresencePacket(packet);
 	}
 
-	public void generatePgpAnnouncement(Account account)
-			throws PgpEngine.UserInputRequiredException {
-		if (account.getStatus() == Account.STATUS_ONLINE) {
-			String signature = getPgpEngine().generateSignature(account,"online");
-			account.setKey("pgp_signature", signature);
-			databaseBackend.updateAccount(account);
-			sendPgpPresence(account, signature);
-		}
-	}
-
 	public void updateConversation(Conversation conversation) {
 		this.databaseBackend.updateConversation(conversation);
 	}
 
 	public Contact findContact(String uuid) {
 		Contact contact = this.databaseBackend.getContact(uuid);
-		if (contact!=null) {
+		if (contact != null) {
 			for (Account account : getAccounts()) {
 				if (contact.getAccountUuid().equals(account.getUuid())) {
 					contact.setAccount(account);
@@ -1398,12 +1431,14 @@ public class XmppConnectionService extends Service {
 		}
 
 	}
-	
-	public boolean markMessage(Account account, String recipient, String uuid, int status) {
+
+	public boolean markMessage(Account account, String recipient, String uuid,
+			int status) {
 		boolean marked = false;
-		for(Conversation conversation : getConversations()) {
-			if (conversation.getContactJid().equals(recipient)&&conversation.getAccount().equals(account)) {
-				for(Message message : conversation.getMessages()) {
+		for (Conversation conversation : getConversations()) {
+			if (conversation.getContactJid().equals(recipient)
+					&& conversation.getAccount().equals(account)) {
+				for (Message message : conversation.getMessages()) {
 					if (message.getUuid().equals(uuid)) {
 						markMessage(message, status);
 						marked = true;
@@ -1415,16 +1450,17 @@ public class XmppConnectionService extends Service {
 		}
 		return marked;
 	}
-	
+
 	public void markMessage(Message message, int status) {
 		message.setStatus(status);
 		databaseBackend.updateMessage(message);
-		if (convChangedListener!=null) {
+		if (convChangedListener != null) {
 			convChangedListener.onConversationListChanged();
 		}
 	}
-	
+
 	public SharedPreferences getPreferences() {
-		return PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+		return PreferenceManager
+				.getDefaultSharedPreferences(getApplicationContext());
 	}
 }

src/eu/siacs/conversations/ui/ConversationFragment.java πŸ”—

@@ -1,18 +1,17 @@
 package eu.siacs.conversations.ui;
 
-import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
+import org.openintents.openpgp.OpenPgpError;
+
 import net.java.otr4j.session.SessionStatus;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException;
-import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException;
+import eu.siacs.conversations.crypto.OnPgpEngineResult;
+import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
@@ -24,6 +23,7 @@ import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.jingle.JingleConnection;
 import android.app.AlertDialog;
 import android.app.Fragment;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -33,7 +33,6 @@ import android.content.IntentSender.SendIntentException;
 import android.graphics.Bitmap;
 import android.graphics.Typeface;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.util.DisplayMetrics;
@@ -245,6 +244,7 @@ public class ConversationFragment extends Fragment {
 				} else {
 					viewHolder = (ViewHolder) view.getTag();
 				}
+				
 				if (type == RECIEVED) {
 					if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
 						if (item.getCounterpart() != null) {
@@ -267,8 +267,14 @@ public class ConversationFragment extends Fragment {
 					viewHolder.indicator.setVisibility(View.VISIBLE);
 				}
 				
+				String filesize = "";
 				
 				if (item.getType() == Message.TYPE_IMAGE) {
+					String[] fileParams = item.getBody().split(",");
+					if (fileParams.length>=1) {
+						long size = Long.parseLong(fileParams[0]);
+						filesize = size/1024+" KB \u00B7 ";
+					}
 					if ((item.getStatus() == Message.STATUS_PREPARING)||(item.getStatus() == Message.STATUS_RECIEVING)) {
 						viewHolder.image.setVisibility(View.GONE);
 						viewHolder.messageBody.setVisibility(View.VISIBLE);
@@ -299,11 +305,10 @@ public class ConversationFragment extends Fragment {
 					} else {
 						viewHolder.messageBody.setVisibility(View.GONE);
 						viewHolder.image.setVisibility(View.VISIBLE);
-						String[] params = item.getBody().split(",");
-			        	if (params.length==3) {
+			        	if (fileParams.length==3) {
 			        		double target = metrics.density * 288;
-			        		int w = Integer.parseInt(params[1]);
-			        		int h = Integer.parseInt(params[2]);
+			        		int w = Integer.parseInt(fileParams[1]);
+			        		int h = Integer.parseInt(fileParams[2]);
 			        		int scalledW;
 			    			int scalledH;
 			    			if (w <= h) {
@@ -341,11 +346,10 @@ public class ConversationFragment extends Fragment {
 							viewHolder.messageBody.setTextColor(0xff33B5E5);
 							viewHolder.messageBody.setTypeface(null,
 									Typeface.ITALIC);
-						} else if ((item.getEncryption() == Message.ENCRYPTION_OTR)||(item.getEncryption() == Message.ENCRYPTION_DECRYPTED)) {
-							viewHolder.messageBody.setText(body.trim());
-							viewHolder.messageBody.setTextColor(0xff333333);
-							viewHolder.messageBody.setTypeface(null,
-									Typeface.NORMAL);
+						} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
+							viewHolder.messageBody.setText(getString(R.string.decryption_failed));
+							viewHolder.messageBody.setTextColor(0xFFe92727);
+							viewHolder.messageBody.setTypeface(null,Typeface.NORMAL);
 						} else {
 							viewHolder.messageBody.setText(body.trim());
 							viewHolder.messageBody.setTextColor(0xff333333);
@@ -358,21 +362,21 @@ public class ConversationFragment extends Fragment {
 				case Message.STATUS_UNSEND:
 					viewHolder.time.setTypeface(null, Typeface.ITALIC);
 					viewHolder.time.setTextColor(0xFF8e8e8e);
-					viewHolder.time.setText("sending\u2026");
+					viewHolder.time.setText(filesize+"sending\u2026");
 					break;
 				case Message.STATUS_OFFERED:
 					viewHolder.time.setTypeface(null, Typeface.ITALIC);
 					viewHolder.time.setTextColor(0xFF8e8e8e);
-					viewHolder.time.setText("offering\u2026");
+					viewHolder.time.setText(filesize+"offering\u2026");
 					break;
 				case Message.STATUS_SEND_FAILED:
-					viewHolder.time.setText(getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item
+					viewHolder.time.setText(filesize+getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item
 							.getTimeSent()));
 					viewHolder.time.setTextColor(0xFFe92727);
 					viewHolder.time.setTypeface(null,Typeface.NORMAL);
 					break;
 				case Message.STATUS_SEND_REJECTED:
-					viewHolder.time.setText(getString(R.string.send_rejected));
+					viewHolder.time.setText(filesize+getString(R.string.send_rejected));
 					viewHolder.time.setTextColor(0xFFe92727);
 					viewHolder.time.setTypeface(null,Typeface.NORMAL);
 					break;
@@ -380,7 +384,7 @@ public class ConversationFragment extends Fragment {
 					viewHolder.time.setTypeface(null, Typeface.NORMAL);
 					viewHolder.time.setTextColor(0xFF8e8e8e);
 					if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-						viewHolder.time.setText(UIHelper
+						viewHolder.time.setText(filesize+UIHelper
 								.readableTimeDifference(item.getTimeSent()));
 					} else {
 						viewHolder.time.setText(item.getCounterpart()
@@ -470,21 +474,47 @@ public class ConversationFragment extends Fragment {
 					});
 		}
 	}
-
+	
+	private void decryptMessage(final Message message) {
+		Log.d("xmppService","called to decrypt");
+		PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
+		if (engine!=null) {
+			engine.decrypt(message,new OnPgpEngineResult() {
+				
+				@Override
+				public void userInputRequried(PendingIntent pi) {
+					askForPassphraseIntent = pi.getIntentSender();
+					pgpInfo.setVisibility(View.VISIBLE);
+				}
+				
+				@Override
+				public void success() {
+					Log.d("xmppService","successfully decrypted");
+					activity.xmppConnectionService.databaseBackend.updateMessage(message);
+					updateMessages();
+				}
+				
+				@Override
+				public void error(OpenPgpError openPgpError) {
+					Log.d("xmppService","decryption error"+openPgpError.getMessage());
+					message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
+					//updateMessages();
+				}
+			});
+		} else {
+			Log.d("xmppService","engine was null");
+		}
+	}
+	
 	public void updateMessages() {
 		ConversationActivity activity = (ConversationActivity) getActivity();
 		if (this.conversation != null) {
-			List<Message> encryptedMessages = new LinkedList<Message>();
 			for (Message message : this.conversation.getMessages()) {
 				if (message.getEncryption() == Message.ENCRYPTION_PGP) {
-					encryptedMessages.add(message);
+					decryptMessage(message);
+					break;
 				}
 			}
-			if (encryptedMessages.size() > 0) {
-				DecryptMessage task = new DecryptMessage();
-				Message[] msgs = new Message[encryptedMessages.size()];
-				task.execute(encryptedMessages.toArray(msgs));
-			}
 			this.messageList.clear();
 			this.messageList.addAll(this.conversation.getMessages());
 			this.messageListAdapter.notifyDataSetChanged();
@@ -492,7 +522,7 @@ public class ConversationFragment extends Fragment {
 				if (messageList.size() >= 1) {
 					int latestEncryption = this.conversation.getLatestMessage()
 							.getEncryption();
-					if (latestEncryption == Message.ENCRYPTION_DECRYPTED) {
+					if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)||(latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
 						conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
 					} else {
 						conversation.nextMessageEncryption = latestEncryption;
@@ -566,25 +596,63 @@ public class ConversationFragment extends Fragment {
 	protected void sendPgpMessage(final Message message) {
 		ConversationActivity activity = (ConversationActivity) getActivity();
 		final XmppConnectionService xmppService = activity.xmppConnectionService;
-		Contact contact = message.getConversation().getContact();
-		Account account = message.getConversation().getAccount();
+		final Contact contact = message.getConversation().getContact();
+		final Account account = message.getConversation().getAccount();
 		if (activity.hasPgp()) {
 			if (contact.getPgpKeyId() != 0) {
-				try {
-					message.setEncryptedBody(xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message.getBody()));
-					xmppService.sendMessage(message, null);
-					chatMsg.setText("");
-				} catch (UserInputRequiredException e) {
-					try {
-						getActivity().startIntentSenderForResult(e.getPendingIntent().getIntentSender(),
-								ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
-								0, 0);
-					} catch (SendIntentException e1) {
-						Log.d("xmppService","failed to start intent to send message");
+				xmppService.getPgpEngine().hasKey(account,contact.getPgpKeyId(), new OnPgpEngineResult() {
+					
+					@Override
+					public void userInputRequried(PendingIntent pi) {
+						Log.d("xmppService","hasKey returned user input required");
+						try {
+							getActivity().startIntentSenderForResult(pi.getIntentSender(),
+									ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
+									0, 0);
+						} catch (SendIntentException e1) {
+							Log.d("xmppService","failed to start intent to send message");
+						}
 					}
-				} catch (OpenPgpException e) {
-					Log.d("xmppService","error encrypting with pgp: "+e.getOpenPgpError().getMessage());
-				}
+					
+					@Override
+					public void success() {
+						Log.d("xmppService","hasKey returned success");
+						xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message,new OnPgpEngineResult() {
+							
+							@Override
+							public void userInputRequried(PendingIntent pi) {
+								try {
+									getActivity().startIntentSenderForResult(pi.getIntentSender(),
+											ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
+											0, 0);
+								} catch (SendIntentException e1) {
+									Log.d("xmppService","failed to start intent to send message");
+								}
+							}
+							
+							@Override
+							public void success() {
+								xmppService.sendMessage(message, null);
+								chatMsg.setText("");
+							}
+							
+							@Override
+							public void error(OpenPgpError openPgpError) {
+								// TODO Auto-generated method stub
+								
+							}
+						});
+					}
+					
+					@Override
+					public void error(OpenPgpError openPgpError) {
+						Log.d("xmppService","openpgp error"+openPgpError.getMessage());
+					}
+				});
+				
+				
+					
+					
 			} else {
 				AlertDialog.Builder builder = new AlertDialog.Builder(
 						getActivity());
@@ -667,7 +735,7 @@ public class ConversationFragment extends Fragment {
 		}
 	}
 
-	class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
+	/*class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
 
 		@Override
 		protected Boolean doInBackground(Message... params) {
@@ -729,7 +797,7 @@ public class ConversationFragment extends Fragment {
 			return true;
 		}
 
-	}
+	}*/
 
 	public void setText(String text) {
 		this.pastedText = text;

src/eu/siacs/conversations/ui/ManageAccountActivity.java πŸ”—

@@ -3,15 +3,18 @@ package eu.siacs.conversations.ui;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.openintents.openpgp.OpenPgpError;
+
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.OnPgpEngineResult;
 import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
 import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
@@ -278,15 +281,7 @@ public class ManageAccountActivity extends XmppActivity {
 							} else if (item.getItemId()==R.id.mgmt_account_announce_pgp) {
 								if (activity.hasPgp()) {
 									mode.finish();
-									try {
-										xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
-									} catch (PgpEngine.UserInputRequiredException e) {
-										try {
-											startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
-										} catch (SendIntentException e1) {
-											Log.d("gultsch","sending intent failed");
-										}
-									}
+									announcePgp();
 								}
 							} else if (item.getItemId() == R.id.mgmt_otr_key) {
 								AlertDialog.Builder builder = new AlertDialog.Builder(activity);
@@ -367,6 +362,33 @@ public class ManageAccountActivity extends XmppActivity {
 		});
 	}
 
+	private void announcePgp() {
+		final Account account = selectedAccountForActionMode;
+		xmppConnectionService.getPgpEngine().generateSignature(account, "online", new OnPgpEngineResult() {
+			
+			@Override
+			public void userInputRequried(PendingIntent pi) {
+				try {
+					startIntentSenderForResult(pi.getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
+				} catch (SendIntentException e) {
+					Log.d("xmppService","coulnd start intent for pgp anncouncment");
+				}
+			}
+			
+			@Override
+			public void success() {
+				xmppConnectionService.databaseBackend.updateAccount(account);
+				xmppConnectionService.sendPgpPresence(account, account.getPgpSignature());
+			}
+			
+			@Override
+			public void error(OpenPgpError openPgpError) {
+				// TODO Auto-generated method stub
+				
+			}
+		});
+	}
+	
 	@Override
 	protected void onStop() {
 		if (xmppConnectionServiceBound) {
@@ -465,15 +487,7 @@ public class ManageAccountActivity extends XmppActivity {
 		 super.onActivityResult(requestCode, resultCode, data);
 		 if (resultCode == RESULT_OK) {
 			if (requestCode == REQUEST_ANNOUNCE_PGP) {
-				 try {
-					xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
-				} catch (UserInputRequiredException e) {
-					try {
-						startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
-					} catch (SendIntentException e1) {
-						Log.d(LOGTAG,"sending intent failed");
-					}
-				}
+				announcePgp();
 			 }
 		 }
 	 }