diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/entities')
4 files changed, 269 insertions, 80 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index a86002862..e29ebb52c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -655,23 +655,6 @@ public class Conversation extends AbstractEntity implements Blockable { return this.nextCounterpart; } - private int getMostRecentlyUsedOutgoingEncryption() { - synchronized (this.messages) { - for(int i = this.messages.size() -1; i >= 0; --i) { - final Message m = this.messages.get(i); - if (!m.isCarbon() && m.getStatus() != Message.STATUS_RECEIVED) { - final int e = m.getEncryption(); - if (e == Message.ENCRYPTION_DECRYPTED || e == Message.ENCRYPTION_DECRYPTION_FAILED) { - return Message.ENCRYPTION_PGP; - } else { - return e; - } - } - } - } - return Message.ENCRYPTION_NONE; - } - private int getMostRecentlyUsedIncomingEncryption() { synchronized (this.messages) { for(int i = this.messages.size() -1; i >= 0; --i) { @@ -700,12 +683,8 @@ public class Conversation extends AbstractEntity implements Blockable { && getAccount().getSelfContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY) && getContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY)) { return Message.ENCRYPTION_AXOLOTL; - } - int outgoing = this.getMostRecentlyUsedOutgoingEncryption(); - if (outgoing == Message.ENCRYPTION_NONE) { - next = this.getMostRecentlyUsedIncomingEncryption(); } else { - next = outgoing; + next = this.getMostRecentlyUsedIncomingEncryption(); } } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 225d05315..818ac1d65 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -492,6 +492,9 @@ public class Message extends AbstractEntity { Message current = this; while(current.mergeable(current.next())) { current = current.next(); + if (current == null) { + break; + } body.append(MERGE_SEPARATOR); body.append(current.getBody().trim()); } @@ -507,6 +510,9 @@ public class Message extends AbstractEntity { Message current = this; while(current.mergeable(current.next())) { current = current.next(); + if (current == null) { + break; + } status = current.status; } return status; @@ -517,6 +523,9 @@ public class Message extends AbstractEntity { Message current = this; while(current.mergeable(current.next())) { current = current.next(); + if (current == null) { + break; + } time = current.timeSent; } return time; diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 1309956eb..d4a15ea7a 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -5,9 +5,7 @@ import android.annotation.SuppressLint; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import eu.siacs.conversations.R; @@ -28,6 +26,19 @@ public class MucOptions { this.self = user; } + public void changeAffiliation(Jid jid, Affiliation affiliation) { + User user = findUserByRealJid(jid); + synchronized (users) { + if (user != null && user.getRole() == Role.NONE) { + users.remove(user); + if (affiliation.ranks(Affiliation.MEMBER)) { + user.affiliation = affiliation; + users.add(user); + } + } + } + } + public enum Affiliation { OWNER("owner", 4, R.string.owner), ADMIN("admin", 3, R.string.admin), @@ -124,10 +135,10 @@ public class MucOptions { } - public static class User { + public static class User implements Comparable<User> { private Role role = Role.NONE; private Affiliation affiliation = Affiliation.NONE; - private Jid jid; + private Jid realJid; private Jid fullJid; private long pgpKeyId = 0; private Avatar avatar; @@ -139,15 +150,11 @@ public class MucOptions { } public String getName() { - return this.fullJid.getResourcepart(); + return fullJid == null ? null : fullJid.getResourcepart(); } - public void setJid(Jid jid) { - this.jid = jid; - } - - public Jid getJid() { - return this.jid; + public void setRealJid(Jid jid) { + this.realJid = jid != null ? jid.toBareJid() : null; } public Role getRole() { @@ -155,6 +162,10 @@ public class MucOptions { } public void setRole(String role) { + if (role == null) { + this.role = Role.NONE; + return; + } role = role.toLowerCase(); switch (role) { case "moderator": @@ -172,26 +183,15 @@ public class MucOptions { } } - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } else if (!(other instanceof User)) { - return false; - } else { - User o = (User) other; - return getName() != null && getName().equals(o.getName()) - && jid != null && jid.equals(o.jid) - && affiliation == o.affiliation - && role == o.role; - } - } - public Affiliation getAffiliation() { return this.affiliation; } public void setAffiliation(String affiliation) { + if (affiliation == null) { + this.affiliation = Affiliation.NONE; + return; + } affiliation = affiliation.toLowerCase(); switch (affiliation) { case "admin": @@ -220,7 +220,13 @@ public class MucOptions { } public Contact getContact() { - return getAccount().getRoster().getContactFromRoster(getJid()); + if (fullJid != null) { + return getAccount().getRoster().getContactFromRoster(realJid); + } else if (realJid != null){ + return getAccount().getRoster().getContact(realJid); + } else { + return null; + } } public boolean setAvatar(Avatar avatar) { @@ -243,11 +249,62 @@ public class MucOptions { public Jid getFullJid() { return fullJid; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + User user = (User) o; + + if (role != user.role) return false; + if (affiliation != user.affiliation) return false; + if (realJid != null ? !realJid.equals(user.realJid) : user.realJid != null) + return false; + return fullJid != null ? fullJid.equals(user.fullJid) : user.fullJid == null; + + } + + @Override + public int hashCode() { + int result = role != null ? role.hashCode() : 0; + result = 31 * result + (affiliation != null ? affiliation.hashCode() : 0); + result = 31 * result + (realJid != null ? realJid.hashCode() : 0); + result = 31 * result + (fullJid != null ? fullJid.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "[fulljid:"+String.valueOf(fullJid)+",realjid:"+String.valueOf(realJid)+",affiliation"+affiliation.toString()+"]"; + } + + public boolean realJidMatchesAccount() { + return realJid != null && realJid.equals(options.account.getJid().toBareJid()); + } + + @Override + public int compareTo(User another) { + Contact ourContact = getContact(); + Contact anotherContact = another.getContact(); + if (ourContact != null && anotherContact != null) { + return ourContact.compareTo(anotherContact); + } else if (ourContact == null && anotherContact != null) { + return getName().compareToIgnoreCase(anotherContact.getDisplayName()); + } else if (ourContact != null) { + return ourContact.getDisplayName().compareToIgnoreCase(another.getName()); + } else { + return getName().compareToIgnoreCase(another.getName()); + } + } + + public Jid getRealJid() { + return realJid; + } } private Account account; - private final Map<String, User> users = Collections.synchronizedMap(new LinkedHashMap<String, User>()); - private final Set<Jid> members = Collections.synchronizedSet(new HashSet<Jid>()); + private final Set<User> users = new HashSet<>(); private final List<String> features = new ArrayList<>(); private Data form = new Data(); private Conversation conversation; @@ -315,20 +372,82 @@ public class MucOptions { return hasFeature("muc_moderated"); } - public User deleteUser(String name) { - return this.users.remove(name); + public User deleteUser(Jid jid) { + User user = findUserByFullJid(jid); + if (user != null) { + synchronized (users) { + users.remove(user); + if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null) { + user.role = Role.NONE; + user.avatar = null; + user.fullJid = null; + users.add(user); + } + } + } + return user; } public void addUser(User user) { - this.users.put(user.getName(), user); + User old; + if (user.fullJid == null && user.realJid != null) { + old = findUserByRealJid(user.realJid); + if (old != null) { + if (old.fullJid != null) { + return; //don't add. user already exists + } else { + synchronized (users) { + users.remove(old); + } + } + } + } else if (user.realJid != null) { + old = findUserByRealJid(user.realJid); + synchronized (users) { + if (old != null && old.fullJid == null) { + users.remove(old); + } + } + } + old = findUserByFullJid(user.getFullJid()); + synchronized (this.users) { + if (old != null) { + users.remove(old); + } + this.users.add(user); + } } - public User findUser(String name) { - return this.users.get(name); + public User findUserByFullJid(Jid jid) { + if (jid == null) { + return null; + } + synchronized (users) { + for (User user : users) { + if (jid.equals(user.getFullJid())) { + return user; + } + } + } + return null; } - public boolean isUserInRoom(String name) { - return findUser(name) != null; + public User findUserByRealJid(Jid jid) { + if (jid == null) { + return null; + } + synchronized (users) { + for (User user : users) { + if (jid.equals(user.realJid)) { + return user; + } + } + } + return null; + } + + public boolean isUserInRoom(Jid jid) { + return findUserByFullJid(jid) != null; } public void setError(Error error) { @@ -341,7 +460,23 @@ public class MucOptions { } public ArrayList<User> getUsers() { - return new ArrayList<>(users.values()); + return getUsers(true); + } + + public ArrayList<User> getUsers(boolean includeOffline) { + synchronized (users) { + if (includeOffline) { + return new ArrayList<>(users); + } else { + ArrayList<User> onlineUsers = new ArrayList<>(); + for (User user : users) { + if (user.getRole().ranks(Role.PARTICIPANT)) { + onlineUsers.add(user); + } + } + return onlineUsers; + } + } } public List<User> getUsers(int max) { @@ -350,7 +485,9 @@ public class MucOptions { } public int getUserCount() { - return this.users.size(); + synchronized (users) { + return users.size(); + } } public String getProposedNick() { @@ -386,7 +523,9 @@ public class MucOptions { } public void setOffline() { - this.users.clear(); + synchronized (users) { + this.users.clear(); + } this.error = Error.NO_RESPONSE; this.isOnline = false; } @@ -410,7 +549,7 @@ public class MucOptions { Contact contact = user.getContact(); if (contact != null && !contact.getDisplayName().isEmpty()) { names.add(contact.getDisplayName().split("\\s+")[0]); - } else { + } else if (user.getName() != null){ names.add(user.getName()); } } @@ -429,7 +568,7 @@ public class MucOptions { public long[] getPgpKeyIds() { List<Long> ids = new ArrayList<>(); - for (User user : this.users.values()) { + for (User user : this.users) { if (user.getPgpKeyId() != 0) { ids.add(user.getPgpKeyId()); } @@ -443,18 +582,22 @@ public class MucOptions { } public boolean pgpKeysInUse() { - for (User user : this.users.values()) { - if (user.getPgpKeyId() != 0) { - return true; + synchronized (users) { + for (User user : users) { + if (user.getPgpKeyId() != 0) { + return true; + } } } return false; } public boolean everybodyHasKeys() { - for (User user : this.users.values()) { - if (user.getPgpKeyId() == 0) { - return false; + synchronized (users) { + for (User user : users) { + if (user.getPgpKeyId() == 0) { + return false; + } } } return true; @@ -468,12 +611,12 @@ public class MucOptions { } } - public Jid getTrueCounterpart(String name) { - if (name.equals(getSelf().getName())) { + public Jid getTrueCounterpart(Jid jid) { + if (jid.equals(getSelf().getFullJid())) { return account.getJid().toBareJid(); } - User user = findUser(name); - return user == null ? null : user.getJid(); + User user = findUserByFullJid(jid); + return user == null ? null : user.realJid; } public String getPassword() { @@ -499,11 +642,15 @@ public class MucOptions { return this.conversation; } - public void putMember(Jid jid) { - members.add(jid); - } - public List<Jid> getMembers() { - return new ArrayList<>(members); + ArrayList<Jid> members = new ArrayList<>(); + synchronized (users) { + for (User user : users) { + if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null) { + members.add(user.realJid); + } + } + } + return members; } } diff --git a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java index 9accec95d..9ee1d180e 100644 --- a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java +++ b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java @@ -146,7 +146,7 @@ public class ServiceDiscoveryResult { this.hash = hash; this.ver = ver; - JSONArray identities = o.optJSONArray("identites"); + JSONArray identities = o.optJSONArray("identities"); if (identities != null) { for (int i = 0; i < identities.length(); i++) { this.identities.add(new Identity(identities.getJSONObject(i))); @@ -158,6 +158,54 @@ public class ServiceDiscoveryResult { this.features.add(features.getString(i)); } } + JSONArray forms = o.optJSONArray("forms"); + if (forms != null) { + for(int i = 0; i < forms.length(); i++) { + this.forms.add(createFormFromJSONObject(forms.getJSONObject(i))); + } + } + } + + private static Data createFormFromJSONObject(JSONObject o) { + Data data = new Data(); + JSONArray names = o.names(); + for(int i = 0; i < names.length(); ++i) { + try { + String name = names.getString(i); + JSONArray jsonValues = o.getJSONArray(name); + ArrayList<String> values = new ArrayList<>(jsonValues.length()); + for(int j = 0; j < jsonValues.length(); ++j) { + values.add(jsonValues.getString(j)); + } + data.put(name, values); + } catch (Exception e) { + e.printStackTrace(); + } + } + return data; + } + + private static JSONObject createJSONFromForm(Data data) { + JSONObject object = new JSONObject(); + for(Field field : data.getFields()) { + try { + JSONArray jsonValues = new JSONArray(); + for(String value : field.getValues()) { + jsonValues.put(value); + } + object.put(field.getFieldName(), jsonValues); + } catch(Exception e) { + e.printStackTrace(); + } + } + try { + JSONArray jsonValues = new JSONArray(); + jsonValues.put(data.getFormType()); + object.put(Data.FORM_TYPE, jsonValues); + } catch(Exception e) { + e.printStackTrace(); + } + return object; } public String getVer() { @@ -274,10 +322,16 @@ public class ServiceDiscoveryResult { for(Identity id : this.getIdentities()) { ids.put(id.toJSON()); } - o.put("identites", ids); + o.put("identities", ids); o.put("features", new JSONArray(this.getFeatures())); + JSONArray forms = new JSONArray(); + for(Data data : this.forms) { + forms.put(createJSONFromForm(data)); + } + o.put("forms", forms); + return o; } catch(JSONException e) { return null; |