groundwork for offline otr messages

iNPUTmice created

Change summary

src/eu/siacs/conversations/entities/Contact.java               |   4 
src/eu/siacs/conversations/entities/Conversation.java          |   4 
src/eu/siacs/conversations/entities/Presences.java             |  10 
src/eu/siacs/conversations/parser/MessageParser.java           |  17 
src/eu/siacs/conversations/services/XmppConnectionService.java |  49 +
src/eu/siacs/conversations/ui/ConversationActivity.java        | 134 +--
src/eu/siacs/conversations/ui/ConversationFragment.java        |  13 
src/eu/siacs/conversations/utils/ExceptionHelper.java          |   2 
8 files changed, 111 insertions(+), 122 deletions(-)

Detailed changes

src/eu/siacs/conversations/entities/Contact.java 🔗

@@ -146,8 +146,8 @@ public class Contact {
 		}
 	}
 
-	public Hashtable<String, Integer> getPresences() {
-		return this.presences.getPresences();
+	public Presences getPresences() {
+		return this.presences;
 	}
 
 	public void updatePresence(String resource, int status) {

src/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -257,14 +257,14 @@ public class Conversation extends AbstractEntity {
 	public void endOtrIfNeeded() {
 		if (this.otrSession != null) {
 			if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
-				Log.d("xmppService", "ending otr session with "
-						+ getContactJid());
 				try {
 					this.otrSession.endSession();
 					this.resetOtrSession();
 				} catch (OtrException e) {
 					this.resetOtrSession();
 				}
+			} else {
+				this.resetOtrSession();
 			}
 		}
 	}

src/eu/siacs/conversations/entities/Presences.java 🔗

@@ -62,4 +62,14 @@ public class Presences {
 	public int size() {
 		return presences.size();
 	}
+	
+	public String[] asStringArray() {
+		final String[] presencesArray = new String[presences.size()];
+		presences.keySet().toArray(presencesArray);
+		return presencesArray;
+	}
+
+	public boolean has(String presence) {
+		return presences.containsKey(presence);
+	}
 }

src/eu/siacs/conversations/parser/MessageParser.java 🔗

@@ -6,7 +6,6 @@ import net.java.otr4j.session.Session;
 import net.java.otr4j.session.SessionStatus;
 import android.util.Log;
 import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.services.XmppConnectionService;
@@ -80,21 +79,7 @@ public class MessageParser extends AbstractParser {
 			body = otrSession.transformReceiving(body);
 			SessionStatus after = otrSession.getSessionStatus();
 			if ((before != after) && (after == SessionStatus.ENCRYPTED)) {
-				List<Message> messages = conversation.getMessages();
-				for (int i = 0; i < messages.size(); ++i) {
-					Message msg = messages.get(i);
-					if ((msg.getStatus() == Message.STATUS_UNSEND)
-							&& (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
-						MessagePacket outPacket = mXmppConnectionService
-								.prepareMessagePacket(account, msg, otrSession);
-						msg.setStatus(Message.STATUS_SEND);
-						mXmppConnectionService.databaseBackend
-								.updateMessage(msg);
-						account.getXmppConnection()
-								.sendMessagePacket(outPacket);
-					}
-				}
-				mXmppConnectionService.updateUi(conversation, false);
+				mXmppConnectionService.onOtrSessionEstablished(conversation);
 			} else if ((before != after) && (after == SessionStatus.FINISHED)) {
 				conversation.resetOtrSession();
 			}

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -20,6 +20,7 @@ import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
+import eu.siacs.conversations.entities.Presences;
 import eu.siacs.conversations.parser.MessageParser;
 import eu.siacs.conversations.parser.PresenceParser;
 import eu.siacs.conversations.persistance.DatabaseBackend;
@@ -226,6 +227,7 @@ public class XmppConnectionService extends Service {
 				List<Conversation> conversations = getConversations();
 				for (int i = 0; i < conversations.size(); ++i) {
 					if (conversations.get(i).getAccount() == account) {
+						conversations.get(i).endOtrIfNeeded();
 						sendUnsendMessages(conversations.get(i));
 					}
 				}
@@ -265,7 +267,7 @@ public class XmppConnectionService extends Service {
 			} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
 				mPresenceParser.parseConferencePresence(packet, account);
 			} else {
-				mPresenceParser.parseContactPresence(packet,account);
+				mPresenceParser.parseContactPresence(packet, account);
 			}
 		}
 	};
@@ -379,7 +381,7 @@ public class XmppConnectionService extends Service {
 						callback.success(message);
 					}
 				} catch (FileBackend.ImageCopyException e) {
-					callback.error(e.getResId(),message);
+					callback.error(e.getResId(), message);
 				}
 			}
 		}).start();
@@ -636,7 +638,7 @@ public class XmppConnectionService extends Service {
 		return connection;
 	}
 
-	synchronized public void sendMessage(Message message, String presence) {
+	synchronized public void sendMessage(Message message) {
 		Account account = message.getConversation().getAccount();
 		Conversation conv = message.getConversation();
 		MessagePacket packet = null;
@@ -650,7 +652,7 @@ 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,
+						conv.startOtrSession(getApplicationContext(), message.getPresence(),
 								true);
 					} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
 						// otr session aleary exists, creating message packet
@@ -694,6 +696,13 @@ public class XmppConnectionService extends Service {
 				message.setEncryption(Message.ENCRYPTION_DECRYPTED);
 				message.setBody(decryptedBody);
 				addToConversation = true;
+			} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
+				if (!conv.hasValidOtrSession()) {
+					conv.startOtrSession(getApplicationContext(), message.getPresence(),false);
+				}
+				message.setPresence(conv.getOtrSession().getSessionID().getUserID());
+				saveInDb = true;
+				addToConversation = true;
 			} else {
 				saveInDb = true;
 				addToConversation = true;
@@ -743,13 +752,25 @@ public class XmppConnectionService extends Service {
 				packet.setBody("This is an XEP-0027 encryted message");
 				packet.addChild("x", "jabber:x:encrypted").setContent(
 						message.getBody());
+			} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
+				Presences presences = message.getConversation().getContact().getPresences();
+				if (!message.getConversation().hasValidOtrSession()) {
+					if ((message.getPresence() != null)&&(presences.has(message.getPresence()))) {
+						message.getConversation().startOtrSession(getApplicationContext(), message.getPresence(), true);
+					} else {
+						if (presences.size() == 1) {
+							String presence = presences.asStringArray()[0];
+							message.getConversation().startOtrSession(getApplicationContext(), presence, true);
+						}
+					}
+				}
 			}
 			if (packet != null) {
 				account.getXmppConnection().sendMessagePacket(packet);
 				markMessage(message, Message.STATUS_SEND);
 			}
 		} else if (message.getType() == Message.TYPE_IMAGE) {
-			//TODO: send images
+			// TODO: send images
 		}
 	}
 
@@ -1166,6 +1187,24 @@ public class XmppConnectionService extends Service {
 		pushContactToServer(contact);
 	}
 
+	public void onOtrSessionEstablished(Conversation conversation) {
+		Account account = conversation.getAccount();
+		List<Message> messages = conversation.getMessages();
+		Session otrSession = conversation.getOtrSession();
+		for (int i = 0; i < messages.size(); ++i) {
+			Message msg = messages.get(i);
+			if ((msg.getStatus() == Message.STATUS_UNSEND)
+					&& (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
+				MessagePacket outPacket = prepareMessagePacket(account, msg,
+						otrSession);
+				msg.setStatus(Message.STATUS_SEND);
+				databaseBackend.updateMessage(msg);
+				account.getXmppConnection().sendMessagePacket(outPacket);
+			}
+		}
+		updateUi(conversation, false);
+	}
+
 	public void pushContactToServer(Contact contact) {
 		contact.resetOption(Contact.Options.DIRTY_DELETE);
 		Account account = contact.getAccount();

src/eu/siacs/conversations/ui/ConversationActivity.java 🔗

@@ -11,6 +11,7 @@ import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Presences;
 import eu.siacs.conversations.services.ImageProvider;
 import eu.siacs.conversations.utils.ExceptionHelper;
 import eu.siacs.conversations.utils.UIHelper;
@@ -835,7 +836,7 @@ public class ConversationActivity extends XmppActivity {
 						message.getConversation().getMessages().add(message);
 						xmppConnectionService.databaseBackend
 								.createMessage(message);
-						xmppConnectionService.sendMessage(message, null);
+						xmppConnectionService.sendMessage(message);
 						xmppConnectionService.updateUi(
 								message.getConversation(), false);
 					}
@@ -868,99 +869,52 @@ public class ConversationActivity extends XmppActivity {
 
 	public void selectPresence(final Conversation conversation,
 			final OnPresenceSelected listener, String reason) {
-		Account account = conversation.getAccount();
-		if (account.getStatus() != Account.STATUS_ONLINE) {
-			AlertDialog.Builder builder = new AlertDialog.Builder(this);
-			builder.setTitle(getString(R.string.not_connected));
-			builder.setIconAttribute(android.R.attr.alertDialogIcon);
-			if ("otr".equals(reason)) {
-				builder.setMessage(getString(R.string.you_are_offline,
-						getString(R.string.otr_messages)));
-			} else if ("file".equals(reason)) {
-				builder.setMessage(getString(R.string.you_are_offline,
-						getString(R.string.files)));
-			} else {
-				builder.setMessage(getString(R.string.you_are_offline_blank));
-			}
-			builder.setNegativeButton(getString(R.string.cancel), null);
-			builder.setPositiveButton(getString(R.string.manage_account),
-					new OnClickListener() {
-
-						@Override
-						public void onClick(DialogInterface dialog, int which) {
-							startActivity(new Intent(activity,
-									ManageAccountActivity.class));
-						}
-					});
-			builder.create().show();
+		Contact contact = conversation.getContact();
+		if (contact == null) {
+			showAddToRosterDialog(conversation);
 			listener.onPresenceSelected(false, null);
 		} else {
-			Contact contact = conversation.getContact();
-			if (contact == null) {
-				showAddToRosterDialog(conversation);
-				listener.onPresenceSelected(false, null);
+			Presences presences = contact.getPresences();
+			if (presences.size() == 0) {
+				listener.onPresenceSelected(true, null);
+			} else if (presences.size() == 1) {
+				String presence = (String) presences.asStringArray()[0];
+				conversation.setNextPresence(presence);
+				listener.onPresenceSelected(true, presence);
 			} else {
-				Hashtable<String, Integer> presences = contact.getPresences();
-				if (presences.size() == 0) {
-					AlertDialog.Builder builder = new AlertDialog.Builder(this);
-					builder.setTitle(getString(R.string.contact_offline));
-					if ("otr".equals(reason)) {
-						builder.setMessage(getString(R.string.contact_offline_otr));
-						builder.setPositiveButton(
-								getString(R.string.send_unencrypted),
-								new OnClickListener() {
-
-									@Override
-									public void onClick(DialogInterface dialog,
-											int which) {
-										listener.onSendPlainTextInstead();
-									}
-								});
-					} else if ("file".equals(reason)) {
-						builder.setMessage(getString(R.string.contact_offline_file));
-					}
-					builder.setIconAttribute(android.R.attr.alertDialogIcon);
-					builder.setNegativeButton(getString(R.string.cancel), null);
-					builder.create().show();
-					listener.onPresenceSelected(false, null);
-				} else if (presences.size() == 1) {
-					String presence = (String) presences.keySet().toArray()[0];
-					conversation.setNextPresence(presence);
-					listener.onPresenceSelected(true, presence);
-				} else {
-					final StringBuilder presence = new StringBuilder();
-					AlertDialog.Builder builder = new AlertDialog.Builder(this);
-					builder.setTitle(getString(R.string.choose_presence));
-					final String[] presencesArray = new String[presences.size()];
-					presences.keySet().toArray(presencesArray);
-					int preselectedPresence = 0;
-					for(int i = 0; i < presencesArray.length; ++i) {
-						if (presencesArray[i].equals(contact.lastseen.presence)) {
-							preselectedPresence = i;
-							break;
-						}
+				final StringBuilder presence = new StringBuilder();
+				AlertDialog.Builder builder = new AlertDialog.Builder(this);
+				builder.setTitle(getString(R.string.choose_presence));
+				final String[] presencesArray = presences.asStringArray();
+				int preselectedPresence = 0;
+				for (int i = 0; i < presencesArray.length; ++i) {
+					if (presencesArray[i].equals(contact.lastseen.presence)) {
+						preselectedPresence = i;
+						break;
 					}
-					presence.append(presencesArray[preselectedPresence]);
-					builder.setSingleChoiceItems(presencesArray,preselectedPresence , 
-							new DialogInterface.OnClickListener() {
-
-								@Override
-								public void onClick(DialogInterface dialog,
-										int which) {
-									presence.delete(0, presence.length());
-									presence.append(presencesArray[which]);
-								}});
-					builder.setNegativeButton(R.string.cancel,	null);
-					builder.setPositiveButton(R.string.ok, new OnClickListener() {
-						
-						@Override
-						public void onClick(DialogInterface dialog, int which) {
-							conversation.setNextPresence(presence.toString());
-							listener.onPresenceSelected(true, presence.toString());
-						}
-					});
-					builder.create().show();
 				}
+				presence.append(presencesArray[preselectedPresence]);
+				builder.setSingleChoiceItems(presencesArray,
+						preselectedPresence,
+						new DialogInterface.OnClickListener() {
+
+							@Override
+							public void onClick(DialogInterface dialog,
+									int which) {
+								presence.delete(0, presence.length());
+								presence.append(presencesArray[which]);
+							}
+						});
+				builder.setNegativeButton(R.string.cancel, null);
+				builder.setPositiveButton(R.string.ok, new OnClickListener() {
+
+					@Override
+					public void onClick(DialogInterface dialog, int which) {
+						conversation.setNextPresence(presence.toString());
+						listener.onPresenceSelected(true, presence.toString());
+					}
+				});
+				builder.create().show();
 			}
 		}
 	}
@@ -1113,7 +1067,7 @@ public class ConversationActivity extends XmppActivity {
 
 					@Override
 					public void success(Message message) {
-						xmppConnectionService.sendMessage(message, null);
+						xmppConnectionService.sendMessage(message);
 					}
 
 					@Override

src/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -784,7 +784,7 @@ public class ConversationFragment extends Fragment {
 
 	protected void sendPlainTextMessage(Message message) {
 		ConversationActivity activity = (ConversationActivity) getActivity();
-		activity.xmppConnectionService.sendMessage(message, null);
+		activity.xmppConnectionService.sendMessage(message);
 		messageSent();
 	}
 
@@ -828,7 +828,7 @@ public class ConversationFragment extends Fragment {
 									conversation
 											.setNextEncryption(Message.ENCRYPTION_NONE);
 									message.setEncryption(Message.ENCRYPTION_NONE);
-									xmppService.sendMessage(message, null);
+									xmppService.sendMessage(message);
 									messageSent();
 								}
 							});
@@ -854,7 +854,7 @@ public class ConversationFragment extends Fragment {
 									conversation
 											.setNextEncryption(Message.ENCRYPTION_NONE);
 									message.setEncryption(Message.ENCRYPTION_NONE);
-									xmppService.sendMessage(message, null);
+									xmppService.sendMessage(message);
 									messageSent();
 								}
 							});
@@ -886,7 +886,7 @@ public class ConversationFragment extends Fragment {
 		ConversationActivity activity = (ConversationActivity) getActivity();
 		final XmppConnectionService xmppService = activity.xmppConnectionService;
 		if (conversation.hasValidOtrSession()) {
-			activity.xmppConnectionService.sendMessage(message, null);
+			activity.xmppConnectionService.sendMessage(message);
 			messageSent();
 		} else {
 			activity.selectPresence(message.getConversation(),
@@ -896,7 +896,8 @@ public class ConversationFragment extends Fragment {
 						public void onPresenceSelected(boolean success,
 								String presence) {
 							if (success) {
-								xmppService.sendMessage(message, presence);
+								message.setPresence(presence);
+								xmppService.sendMessage(message);
 								messageSent();
 							}
 						}
@@ -904,7 +905,7 @@ public class ConversationFragment extends Fragment {
 						@Override
 						public void onSendPlainTextInstead() {
 							message.setEncryption(Message.ENCRYPTION_NONE);
-							xmppService.sendMessage(message, null);
+							xmppService.sendMessage(message);
 							messageSent();
 						}
 					}, "otr");

src/eu/siacs/conversations/utils/ExceptionHelper.java 🔗

@@ -70,7 +70,7 @@ public class ExceptionHelper {
 						Log.d("xmppService","using account="+finalAccount.getJid()+" to send in stack trace");
 						Conversation conversation = service.findOrCreateConversation(finalAccount, "bugs@siacs.eu", false);
 						Message message = new Message(conversation, stacktrace.toString(), Message.ENCRYPTION_NONE);
-						service.sendMessage(message, null);
+						service.sendMessage(message);
 				}
 			});
 			builder.setNegativeButton(context.getText(R.string.send_never),new OnClickListener() {