Change summary
src/main/java/eu/siacs/conversations/entities/Message.java | 49
src/main/java/eu/siacs/conversations/generator/MessageGenerator.java | 4
src/main/java/eu/siacs/conversations/parser/MessageParser.java | 19
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 2
4 files changed, 69 insertions(+), 5 deletions(-)
Detailed changes
@@ -9,6 +9,7 @@ import android.text.Html;
import android.text.SpannableStringBuilder;
import android.util.Base64;
import android.util.Log;
+import android.util.Pair;
import com.cheogram.android.BobTransfer;
import com.cheogram.android.GetThumbnailForCid;
@@ -392,6 +393,11 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
public Contact getContact() {
if (this.conversation.getMode() == Conversation.MODE_SINGLE) {
+ if (this.trueCounterpart != null) {
+ return this.conversation.getAccount().getRoster()
+ .getContact(this.trueCounterpart);
+ }
+
return this.conversation.getContact();
} else {
if (this.trueCounterpart == null) {
@@ -404,10 +410,29 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
}
public String getBody() {
- if (getOob() != null) {
- return body.replace(getOob().toString(), "");
+ StringBuilder body = new StringBuilder(this.body);
+
+ List<Element> fallbacks = getFallbacks();
+ List<Pair<Integer, Integer>> spans = new ArrayList<>();
+ for (Element fallback : fallbacks) {
+ for (Element span : fallback.getChildren()) {
+ if (!span.getName().equals("body") && !span.getNamespace().equals("urn:xmpp:fallback:0")) continue;
+ if (span.getAttribute("start") == null || span.getAttribute("end") == null) return "";
+ spans.add(new Pair(parseInt(span.getAttribute("start")), parseInt(span.getAttribute("end"))));
+ }
+ }
+ // Do them in reverse order so that span deletions don't affect the indexes of other spans
+ spans.sort((x, y) -> y.first.compareTo(x.first));
+ try {
+ for (Pair<Integer, Integer> span : spans) {
+ body.delete(span.first, span.second);
+ }
+ } catch (final StringIndexOutOfBoundsException e) { spans.clear(); }
+
+ if (spans.isEmpty() && getOob() != null) {
+ return body.toString().replace(getOob().toString(), "");
} else {
- return body;
+ return body.toString();
}
}
@@ -948,6 +973,24 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
return new ArrayList<>(this.payloads);
}
+ public List<Element> getFallbacks() {
+ List<Element> fallbacks = new ArrayList<>();
+
+ if (this.payloads == null) return fallbacks;
+
+ for (Element el : this.payloads) {
+ if (el.getName().equals("fallback") && el.getNamespace().equals("urn:xmpp:fallback:0")) {
+ final String fallbackFor = el.getAttribute("for");
+ if (fallbackFor == null) continue;
+ if (fallbackFor.equals("http://jabber.org/protocol/address") || fallbackFor.equals(Namespace.OOB)) {
+ fallbacks.add(el);
+ }
+ }
+ }
+
+ return fallbacks;
+ }
+
public Element getHtml() {
if (this.payloads == null) return null;
@@ -107,6 +107,8 @@ public class MessageGenerator extends AbstractGenerator {
final Message.FileParams fileParams = message.getFileParams();
content = fileParams.url;
packet.addChild("x", Namespace.OOB).addChild("url").setContent(content);
+ packet.addChild("fallback", "urn:xmpp:fallback:0").setAttribute("for", Namespace.OOB)
+ .addChild("body", "urn:xmpp:fallback:0");
} else {
content = message.getBody();
}
@@ -121,6 +123,8 @@ public class MessageGenerator extends AbstractGenerator {
final String url = fileParams.url;
packet.setBody(url);
packet.addChild("x", Namespace.OOB).addChild("url").setContent(url);
+ packet.addChild("fallback", "urn:xmpp:fallback:0").setAttribute("for", Namespace.OOB)
+ .addChild("body", "urn:xmpp:fallback:0");
} else {
if (Config.supportUnencrypted()) {
packet.setBody(PGP_FALLBACK_MESSAGE);
@@ -602,6 +602,22 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
+ Element addresses = packet.findChild("addresses", "http://jabber.org/protocol/address");
+ if (status == Message.STATUS_RECEIVED && addresses != null) {
+ for (Element address : addresses.getChildren()) {
+ if (!address.getName().equals("address") || !address.getNamespace().equals("http://jabber.org/protocol/address")) continue;
+
+ if (address.getAttribute("type").equals("ofrom") && address.getAttribute("jid") != null) {
+ Jid ofrom = address.getAttributeAsJid("jid");
+ if (InvalidJid.isValid(ofrom) && ofrom.getDomain().equals(counterpart.getDomain()) &&
+ conversation.getAccount().getRoster().getContact(counterpart.getDomain()).getPresences().anySupport("http://jabber.org/protocol/address")) {
+
+ message.setTrueCounterpart(ofrom);
+ }
+ }
+ }
+ }
+
if (html != null) message.addPayload(html);
message.setSubject(original.findChildContent("subject"));
message.setCounterpart(counterpart);
@@ -617,7 +633,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
message.markable = packet.hasChild("markable", "urn:xmpp:chat-markers:0");
for (Element el : packet.getChildren()) {
- if (el.getName().equals("query") && el.getNamespace().equals("http://jabber.org/protocol/disco#items") && el.getAttribute("node").equals("http://jabber.org/protocol/commands")) {
+ if ((el.getName().equals("query") && el.getNamespace().equals("http://jabber.org/protocol/disco#items") && el.getAttribute("node").equals("http://jabber.org/protocol/commands")) ||
+ (el.getName().equals("fallback") && el.getNamespace().equals("urn:xmpp:fallback:0"))) {
message.addPayload(el);
}
if (el.getName().equals("thread") && (el.getNamespace() == null || el.getNamespace().equals("jabber:client"))) {
@@ -267,7 +267,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
error = true;
break;
default:
- if (mForceNames || multiReceived) {
+ if (mForceNames || multiReceived || (message.getTrueCounterpart() != null && message.getContact() != null)) {
info = UIHelper.getMessageDisplayName(message);
}
break;