Preserve nick/hats/avatar across basic presence change

Stephen Paul Weber created

Only require them on join/rename presence, basically.  Just sending
"away" to the room with no metadata doesn't break you.

Change summary

src/main/java/eu/siacs/conversations/entities/MucOptions.java   | 15 +-
src/main/java/eu/siacs/conversations/parser/AbstractParser.java | 10 +
2 files changed, 15 insertions(+), 10 deletions(-)

Detailed changes

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

@@ -283,6 +283,9 @@ public class MucOptions {
         synchronized (this.users) {
             if (old != null) {
                 users.remove(old);
+                if (old.nick != null && user.nick == null && old.getName().equals(user.getName())) user.nick = old.nick;
+                if (old.hats != null && user.hats == null) user.hats = old.hats;
+                if (old.avatar != null && user.avatar == null) user.avatar = old.avatar;
             }
             boolean fullJidIsSelf = isOnline && user.getFullJid() != null && user.getFullJid().equals(self.getFullJid());
             if ((!membersOnly() || user.getAffiliation().ranks(Affiliation.MEMBER))
@@ -821,17 +824,17 @@ public class MucOptions {
         private Affiliation affiliation = Affiliation.NONE;
         private Jid realJid;
         private Jid fullJid;
-        private String nick;
+        protected String nick;
         private long pgpKeyId = 0;
-        private Avatar avatar;
+        protected Avatar avatar;
         private final MucOptions options;
         private ChatState chatState = Config.DEFAULT_CHAT_STATE;
-        private final Set<Hat> hats;
+        protected Set<Hat> hats;
 
         public User(MucOptions options, Jid fullJid, final String nick, final Set<Hat> hats) {
             this.options = options;
             this.fullJid = fullJid;
-            this.nick = nick == null ? getName() : nick;
+            this.nick = nick;
             this.hats = hats;
         }
 
@@ -840,7 +843,7 @@ public class MucOptions {
         }
 
         public String getNick() {
-            return nick;
+            return nick == null ? getName() : nick;
         }
 
         public Role getRole() {
@@ -860,7 +863,7 @@ public class MucOptions {
         }
 
         public Set<Hat> getHats() {
-            return this.hats;
+            return this.hats == null ? new HashSet<>() : hats;
         }
 
         public long getPgpKeyId() {

src/main/java/eu/siacs/conversations/parser/AbstractParser.java 🔗

@@ -137,7 +137,7 @@ public abstract class AbstractParser {
 		return parseItem(conference,item,null,null,new Element("hats", "urn:xmpp:hats:0"));
 	}
 
-	public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid, final String nickname, final Element hatsEl) {
+	public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid, final String nicknameIn, final Element hatsEl) {
 		final String local = conference.getJid().getLocal();
 		final String domain = conference.getJid().getDomain().toEscapedString();
 		String affiliation = item.getAttribute("affiliation");
@@ -152,9 +152,11 @@ public abstract class AbstractParser {
 		}
 		Jid realJid = item.getAttributeAsJid("jid");
 		if (fullJid != null) nick = fullJid.getResource();
+		String nickname = null;
+		if (nick != null && nicknameIn != null) nickname = nick.equals(nicknameIn) ? nick : null;
 		try {
-			if (nickname != null && nick != null && !nick.equals(nickname) && gnu.inet.encoding.Punycode.decode(nick).equals(nickname)) {
-				nick = nickname;
+			if (nickname == null && nicknameIn != null && nick != null && gnu.inet.encoding.Punycode.decode(nick).equals(nicknameIn)) {
+				nickname = nicknameIn;
 			}
 		} catch (final gnu.inet.encoding.PunycodeException | ArrayIndexOutOfBoundsException e) { }
 		Set<MucOptions.Hat> hats = new TreeSet<>();
@@ -163,7 +165,7 @@ public abstract class AbstractParser {
 				hats.add(new MucOptions.Hat(hat));
 			}
 		}
-		MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid, nick, hats);
+		MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid, nickname, hatsEl == null ? null : hats);
 		if (InvalidJid.isValid(realJid)) {
 			user.setRealJid(realJid);
 		}