Support extended addressing ofrom when domain matches

Stephen Paul Weber created

Allow a message to appear as from a different jid using ofrom if the domain
matches the actual from and source domain advertises support for extended
addressing. This is safe because spoofing control is up to the source server,
and the source server could have chosen to write a different from with the same
domain if it wished.

If there is a true counterpart (set from ofrom) then display nickname like in a
MUC because this message isn't from the normal counterpart of this conversation.

Change summary

src/main/java/eu/siacs/conversations/entities/Message.java          |  5 
src/main/java/eu/siacs/conversations/parser/MessageParser.java      | 16 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java |  2 
3 files changed, 22 insertions(+), 1 deletion(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -392,6 +392,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) {

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);

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -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;