diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java index 8f4b6193e..58f1f1359 100644 --- a/src/eu/siacs/conversations/entities/Contact.java +++ b/src/eu/siacs/conversations/entities/Contact.java @@ -146,8 +146,8 @@ public class Contact { } } - public Hashtable getPresences() { - return this.presences.getPresences(); + public Presences getPresences() { + return this.presences; } public void updatePresence(String resource, int status) { diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java index f5542925b..e440b27cc 100644 --- a/src/eu/siacs/conversations/entities/Conversation.java +++ b/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(); } } } diff --git a/src/eu/siacs/conversations/entities/Presences.java b/src/eu/siacs/conversations/entities/Presences.java index fd8af5735..778916487 100644 --- a/src/eu/siacs/conversations/entities/Presences.java +++ b/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); + } } diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index 046b48332..63e789a37 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/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 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(); } diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index 10d7f409d..16814baa3 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/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 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 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(); diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index bded4e6fb..995568903 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/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 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)); + 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; } - 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; - } - } - 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 diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index 8d936781a..5d7e9f94d 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/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"); diff --git a/src/eu/siacs/conversations/utils/ExceptionHelper.java b/src/eu/siacs/conversations/utils/ExceptionHelper.java index f9cd375eb..05b16240b 100644 --- a/src/eu/siacs/conversations/utils/ExceptionHelper.java +++ b/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() {