diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 04175632ef46035b175a40da6cf09727de0b2c14..5c6f263af9d7b20597dff87fe8cf048029be44e0 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -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 fallbacks = getFallbacks(); + List> 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 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 getFallbacks() { + List 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; diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 90a312204094c58cc2bda1baf3e27ed4aa7f25bf..b1d57fef74cc7b7933866fe646cfd2ddbef7e040 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -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); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 6ccfe69b4cde5c2b07cb84656c6b2bd5354a7a17..f0b3d83e27289f9bac282e4d9f723fba2c4a211d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -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"))) { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 7194f5c80ec1f7a890a454bd0fcfbc02ffde8a00..a6e53d77a3b45713efd628a1d1c8511185e98c00 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -267,7 +267,7 @@ public class MessageAdapter extends ArrayAdapter { error = true; break; default: - if (mForceNames || multiReceived) { + if (mForceNames || multiReceived || (message.getTrueCounterpart() != null && message.getContact() != null)) { info = UIHelper.getMessageDisplayName(message); } break;