groundwork for offline otr messages

This commit is contained in:
iNPUTmice 2014-06-11 21:53:25 +02:00
parent 95f1a3d57d
commit bb90452673
8 changed files with 111 additions and 122 deletions

View file

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

View file

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

View file

@ -62,4 +62,14 @@ public class Presences {
public int size() { public int size() {
return presences.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);
}
} }

View file

@ -6,7 +6,6 @@ import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus; import net.java.otr4j.session.SessionStatus;
import android.util.Log; import android.util.Log;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
@ -80,21 +79,7 @@ public class MessageParser extends AbstractParser {
body = otrSession.transformReceiving(body); body = otrSession.transformReceiving(body);
SessionStatus after = otrSession.getSessionStatus(); SessionStatus after = otrSession.getSessionStatus();
if ((before != after) && (after == SessionStatus.ENCRYPTED)) { if ((before != after) && (after == SessionStatus.ENCRYPTED)) {
List<Message> messages = conversation.getMessages(); mXmppConnectionService.onOtrSessionEstablished(conversation);
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);
} else if ((before != after) && (after == SessionStatus.FINISHED)) { } else if ((before != after) && (after == SessionStatus.FINISHED)) {
conversation.resetOtrSession(); conversation.resetOtrSession();
} }

View file

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

View file

@ -11,6 +11,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.services.ImageProvider; import eu.siacs.conversations.services.ImageProvider;
import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.UIHelper;
@ -835,7 +836,7 @@ public class ConversationActivity extends XmppActivity {
message.getConversation().getMessages().add(message); message.getConversation().getMessages().add(message);
xmppConnectionService.databaseBackend xmppConnectionService.databaseBackend
.createMessage(message); .createMessage(message);
xmppConnectionService.sendMessage(message, null); xmppConnectionService.sendMessage(message);
xmppConnectionService.updateUi( xmppConnectionService.updateUi(
message.getConversation(), false); message.getConversation(), false);
} }
@ -868,99 +869,52 @@ public class ConversationActivity extends XmppActivity {
public void selectPresence(final Conversation conversation, public void selectPresence(final Conversation conversation,
final OnPresenceSelected listener, String reason) { final OnPresenceSelected listener, String reason) {
Account account = conversation.getAccount(); Contact contact = conversation.getContact();
if (account.getStatus() != Account.STATUS_ONLINE) { if (contact == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); showAddToRosterDialog(conversation);
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();
listener.onPresenceSelected(false, null); listener.onPresenceSelected(false, null);
} else { } else {
Contact contact = conversation.getContact(); Presences presences = contact.getPresences();
if (contact == null) { if (presences.size() == 0) {
showAddToRosterDialog(conversation); listener.onPresenceSelected(true, null);
listener.onPresenceSelected(false, null); } else if (presences.size() == 1) {
String presence = (String) presences.asStringArray()[0];
conversation.setNextPresence(presence);
listener.onPresenceSelected(true, presence);
} else { } else {
Hashtable<String, Integer> presences = contact.getPresences(); final StringBuilder presence = new StringBuilder();
if (presences.size() == 0) { AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.choose_presence));
builder.setTitle(getString(R.string.contact_offline)); final String[] presencesArray = presences.asStringArray();
if ("otr".equals(reason)) { int preselectedPresence = 0;
builder.setMessage(getString(R.string.contact_offline_otr)); for (int i = 0; i < presencesArray.length; ++i) {
builder.setPositiveButton( if (presencesArray[i].equals(contact.lastseen.presence)) {
getString(R.string.send_unencrypted), preselectedPresence = i;
new OnClickListener() { break;
@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;
}
}
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 @Override
public void success(Message message) { public void success(Message message) {
xmppConnectionService.sendMessage(message, null); xmppConnectionService.sendMessage(message);
} }
@Override @Override

View file

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

View file

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