From f67821752d81253478ac248e62482d6d89427e41 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Thu, 27 Sep 2018 20:07:11 +0200 Subject: store avatars received over muc presence in contact --- .../java/de/pixart/messenger/entities/Contact.java | 6 +- .../de/pixart/messenger/entities/MucOptions.java | 1172 ++++++++++---------- .../de/pixart/messenger/parser/PresenceParser.java | 8 + .../messenger/persistance/DatabaseBackend.java | 2 +- .../pixart/messenger/services/AvatarService.java | 24 +- .../messenger/services/XmppConnectionService.java | 8 + .../pixart/messenger/ui/ConversationFragment.java | 2 +- 7 files changed, 618 insertions(+), 604 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/pixart/messenger/entities/Contact.java b/src/main/java/de/pixart/messenger/entities/Contact.java index 6edb14ada..a74b09dff 100644 --- a/src/main/java/de/pixart/messenger/entities/Contact.java +++ b/src/main/java/de/pixart/messenger/entities/Contact.java @@ -479,10 +479,14 @@ public class Contact implements ListItem, Blockable { } } - public String getAvatar() { + public String getAvatarFilename() { return avatar == null ? null : avatar.getFilename(); } + public Avatar getAvatar() { + return avatar; + } + public boolean deleteOtrFingerprint(String fingerprint) { synchronized (this.keys) { boolean success = false; diff --git a/src/main/java/de/pixart/messenger/entities/MucOptions.java b/src/main/java/de/pixart/messenger/entities/MucOptions.java index 258ded842..cf09e73a7 100644 --- a/src/main/java/de/pixart/messenger/entities/MucOptions.java +++ b/src/main/java/de/pixart/messenger/entities/MucOptions.java @@ -25,7 +25,31 @@ import rocks.xmpp.addr.Jid; @SuppressLint("DefaultLocale") public class MucOptions { + public static final String STATUS_CODE_SELF_PRESENCE = "110"; + public static final String STATUS_CODE_ROOM_CREATED = "201"; + public static final String STATUS_CODE_BANNED = "301"; + public static final String STATUS_CODE_CHANGED_NICK = "303"; + public static final String STATUS_CODE_KICKED = "307"; + public static final String STATUS_CODE_AFFILIATION_CHANGE = "321"; + public static final String STATUS_CODE_LOST_MEMBERSHIP = "322"; + public static final String STATUS_CODE_SHUTDOWN = "332"; + private final Set users = new HashSet<>(); + private final Conversation conversation; + public OnRenameListener onRenameListener = null; private boolean mAutoPushConfiguration = true; + private Account account; + private ServiceDiscoveryResult serviceDiscoveryResult; + private boolean isOnline = false; + private Error error = Error.NONE; + private User self; + private String password = null; + public MucOptions(Conversation conversation) { + this.account = conversation.getAccount(); + this.conversation = conversation; + this.self = new User(this, createJoinJid(getProposedNick())); + this.self.affiliation = Affiliation.of(conversation.getAttribute("affiliation")); + this.self.role = Role.of(conversation.getAttribute("role")); + } public Account getAccount() { return this.conversation.getAccount(); @@ -75,779 +99,745 @@ public class MucOptions { return MessageArchiveService.Version.has(getFeatures()); } - public enum Affiliation { - OWNER(4, R.string.owner), - ADMIN(3, R.string.admin), - MEMBER(2, R.string.member), - OUTCAST(0, R.string.outcast), - NONE(1, R.string.no_affiliation); - - Affiliation(int rank, int resId) { - this.resId = resId; - this.rank = rank; - } - - private int resId; - private int rank; - - public int getResId() { - return resId; - } - - @Override - public String toString() { - return name().toLowerCase(Locale.US); - } - - public boolean outranks(Affiliation affiliation) { - return rank > affiliation.rank; - } - - public boolean ranks(Affiliation affiliation) { - return rank >= affiliation.rank; - } - - public static Affiliation of(@Nullable String value) { - if (value == null) { - return NONE; - } - try { - return Affiliation.valueOf(value.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - return NONE; + public boolean updateConfiguration(ServiceDiscoveryResult serviceDiscoveryResult) { + this.serviceDiscoveryResult = serviceDiscoveryResult; + String name; + Field roomConfigName = getRoomInfoForm().getFieldByName("muc#roomconfig_roomname"); + if (roomConfigName != null) { + name = roomConfigName.getValue(); + } else { + List identities = serviceDiscoveryResult.getIdentities(); + String identityName = identities.size() > 0 ? identities.get(0).getName() : null; + final Jid jid = conversation.getJid(); + if (identityName != null && !identityName.equals(jid == null ? null : jid.getEscapedLocal())) { + name = identityName; + } else { + name = null; } } + boolean changed = conversation.setAttribute("muc_name", name); + changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly")); + changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated")); + changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous")); + return changed; } - public enum Role { - MODERATOR(R.string.moderator, 3), - VISITOR(R.string.visitor, 1), - PARTICIPANT(R.string.participant, 2), - NONE(R.string.no_role, 0); + private Data getRoomInfoForm() { + final List forms = serviceDiscoveryResult == null ? Collections.emptyList() : serviceDiscoveryResult.forms; + return forms.size() == 0 ? new Data() : forms.get(0); + } - Role(int resId, int rank) { - this.resId = resId; - this.rank = rank; - } + public String getAvatar() { + return account.getRoster().getContact(conversation.getJid()).getAvatarFilename(); + } - private int resId; - private int rank; + public boolean hasFeature(String feature) { + return this.serviceDiscoveryResult != null && this.serviceDiscoveryResult.features.contains(feature); + } - public int getResId() { - return resId; - } + public boolean hasVCards() { + return hasFeature("vcard-temp"); + } - @Override - public String toString() { - return name().toLowerCase(Locale.US); - } + public boolean canInvite() { + Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowinvites"); + return !membersOnly() || self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue())); + } - public boolean ranks(Role role) { - return rank >= role.rank; - } + public boolean canChangeSubject() { + Field field = getRoomInfoForm().getFieldByName("muc#roominfo_changesubject"); + return self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue())); + } - public static Role of(@Nullable String value) { - if (value == null) { - return NONE; - } - try { - return Role.valueOf(value.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - return NONE; - } + public boolean allowPm() { + final Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowpm"); + if (field == null) { + return true; //fall back if field does not exists + } + if ("anyone".equals(field.getValue())) { + return true; + } else if ("participants".equals(field.getValue())) { + return self.getRole().ranks(Role.PARTICIPANT); + } else if ("moderators".equals(field.getValue())) { + return self.getRole().ranks(Role.MODERATOR); + } else { + return false; } } - public enum Error { - NO_RESPONSE, - SERVER_NOT_FOUND, - NONE, - NICK_IN_USE, - PASSWORD_REQUIRED, - BANNED, - MEMBERS_ONLY, - RESOURCE_CONSTRAINT, - KICKED, - SHUTDOWN, - DESTROYED, - INVALID_NICK, - UNKNOWN + public boolean participating() { + return self.getRole().ranks(Role.PARTICIPANT) || !moderated(); } - public static final String STATUS_CODE_SELF_PRESENCE = "110"; - public static final String STATUS_CODE_ROOM_CREATED = "201"; - public static final String STATUS_CODE_BANNED = "301"; - public static final String STATUS_CODE_CHANGED_NICK = "303"; - public static final String STATUS_CODE_KICKED = "307"; - public static final String STATUS_CODE_AFFILIATION_CHANGE = "321"; - public static final String STATUS_CODE_LOST_MEMBERSHIP = "322"; - public static final String STATUS_CODE_SHUTDOWN = "332"; - - private interface OnEventListener { - void onSuccess(); + public boolean membersOnly() { + return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, false); + } - void onFailure(); + public List getFeatures() { + return this.serviceDiscoveryResult != null ? this.serviceDiscoveryResult.features : Collections.emptyList(); } - public interface OnRenameListener extends OnEventListener { + public boolean nonanonymous() { + return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, false); + } + public boolean isPrivateAndNonAnonymous() { + return membersOnly() && nonanonymous(); } - public static class User implements Comparable { - private Role role = Role.NONE; - private Affiliation affiliation = Affiliation.NONE; - private Jid realJid; - private Jid fullJid; - private long pgpKeyId = 0; - private Avatar avatar; - private MucOptions options; - private ChatState chatState = Config.DEFAULT_CHATSTATE; + public boolean moderated() { + return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_MODERATED, false); + } - public User(MucOptions options, Jid from) { - this.options = options; - this.fullJid = from; + public User deleteUser(Jid jid) { + User user = findUserByFullJid(jid); + if (user != null) { + synchronized (users) { + users.remove(user); + boolean realJidInMuc = false; + for (User u : users) { + if (user.realJid != null && user.realJid.equals(u.realJid)) { + realJidInMuc = true; + break; + } + } + boolean self = user.realJid != null && user.realJid.equals(account.getJid().asBareJid()); + if (membersOnly() + && nonanonymous() + && user.affiliation.ranks(Affiliation.MEMBER) + && user.realJid != null + && !realJidInMuc + && !self) { + user.role = Role.NONE; + user.avatar = null; + user.fullJid = null; + users.add(user); + } + } } + return user; + } - public String getName() { - return fullJid == null ? null : fullJid.getResource(); + //returns true if real jid was new; + public boolean updateUser(User user) { + User old; + boolean realJidFound = false; + if (user.fullJid == null && user.realJid != null) { + old = findUserByRealJid(user.realJid); + realJidFound = old != null; + if (old != null) { + if (old.fullJid != null) { + return false; //don't add. user already exists + } else { + synchronized (users) { + users.remove(old); + } + } + } + } else if (user.realJid != null) { + old = findUserByRealJid(user.realJid); + realJidFound = old != null; + synchronized (users) { + if (old != null && old.fullJid == null) { + users.remove(old); + } + } } - - public void setRealJid(Jid jid) { - this.realJid = jid != null ? jid.asBareJid() : null; - } - - public Role getRole() { - return this.role; - } - - public void setRole(String role) { - this.role = Role.of(role); - } - - public Affiliation getAffiliation() { - return this.affiliation; - } - - public void setAffiliation(String affiliation) { - this.affiliation = Affiliation.of(affiliation); - } - - public void setPgpKeyId(long id) { - this.pgpKeyId = id; - } - - public long getPgpKeyId() { - if (this.pgpKeyId != 0) { - return this.pgpKeyId; - } else if (realJid != null) { - return getAccount().getRoster().getContact(realJid).getPgpKeyId(); - } else { - return 0; + old = findUserByFullJid(user.getFullJid()); + synchronized (this.users) { + if (old != null) { + users.remove(old); } - } - - public Contact getContact() { - if (fullJid != null) { - return getAccount().getRoster().getContactFromRoster(realJid); - } else if (realJid != null) { - return getAccount().getRoster().getContact(realJid); - } else { - return null; + boolean fullJidIsSelf = isOnline && user.getFullJid() != null && user.getFullJid().equals(self.getFullJid()); + if ((!membersOnly() || user.getAffiliation().ranks(Affiliation.MEMBER)) + && user.getAffiliation().outranks(Affiliation.OUTCAST) + && !fullJidIsSelf) { + this.users.add(user); + return !realJidFound && user.realJid != null; } } + return false; + } - public boolean setAvatar(Avatar avatar) { - if (this.avatar != null && this.avatar.equals(avatar)) { - return false; - } else { - this.avatar = avatar; - return true; - } + public User findUserByFullJid(Jid jid) { + if (jid == null) { + return null; } - - public String getAvatar() { - return avatar == null ? null : avatar.getFilename(); + synchronized (users) { + for (User user : users) { + if (jid.equals(user.getFullJid())) { + return user; + } + } } + return null; + } - public Account getAccount() { - return options.getAccount(); + public User findUserByRealJid(Jid jid) { + if (jid == null) { + return null; } - - public Conversation getConversation() { - return options.getConversation(); + synchronized (users) { + for (User user : users) { + if (jid.equals(user.realJid)) { + return user; + } + } } + return null; + } - public Jid getFullJid() { - return fullJid; + public User findOrCreateUserByRealJid(Jid jid, Jid fullJid) { + User user = findUserByRealJid(jid); + if (user == null) { + user = new User(this, fullJid); + user.setRealJid(jid); } + return user; + } - @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; - + public User findUser(ReadByMarker readByMarker) { + if (readByMarker.getRealJid() != null) { + return findOrCreateUserByRealJid(readByMarker.getRealJid().asBareJid(), readByMarker.getFullJid()); + } else if (readByMarker.getFullJid() != null) { + return findUserByFullJid(readByMarker.getFullJid()); + } else { + return null; } + } - public boolean isDomain() { - return realJid != null && realJid.getLocal() == null && role == Role.NONE; - } + public boolean isContactInRoom(Contact contact) { + return findUserByRealJid(contact.getJid().asBareJid()) != 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; - } + public boolean isUserInRoom(Jid jid) { + return findUserByFullJid(jid) != null; + } - @Override - public String toString() { - return "[fulljid:" + String.valueOf(fullJid) + ",realjid:" + String.valueOf(realJid) + ",affiliation" + affiliation.toString() + "]"; - } + public boolean setOnline() { + boolean before = this.isOnline; + this.isOnline = true; + return !before; + } - public boolean realJidMatchesAccount() { - return realJid != null && realJid.equals(options.account.getJid().asBareJid()); - } + public ArrayList getUsers() { + return getUsers(true); + } - @Override - public int compareTo(@NonNull User another) { - if (another.getAffiliation().outranks(getAffiliation())) { - return 1; - } else if (getAffiliation().outranks(another.getAffiliation())) { - return -1; - } else { - return getComparableName().compareToIgnoreCase(another.getComparableName()); + public ArrayList getUsers(boolean includeOffline) { + synchronized (users) { + ArrayList users = new ArrayList<>(); + for (User user : this.users) { + if (!user.isDomain() && (includeOffline || user.getRole().ranks(Role.PARTICIPANT))) { + users.add(user); + } } + return users; } + } - - private String getComparableName() { - Contact contact = getContact(); - if (contact != null) { - return contact.getDisplayName(); - } else { - String name = getName(); - return name == null ? "" : name; + public ArrayList getUsersWithChatState(ChatState state, int max) { + synchronized (users) { + ArrayList list = new ArrayList<>(); + for (User user : users) { + if (user.chatState == state) { + list.add(user); + if (list.size() >= max) { + break; + } + } } + return list; } + } - public Jid getRealJid() { - return realJid; - } - - public boolean setChatState(ChatState chatState) { - if (this.chatState == chatState) { - return false; + public List getUsers(int max) { + ArrayList subset = new ArrayList<>(); + HashSet jids = new HashSet<>(); + jids.add(account.getJid().asBareJid()); + synchronized (users) { + for (User user : users) { + if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) { + subset.add(user); + } + if (subset.size() >= max) { + break; + } } - this.chatState = chatState; - return true; } + return subset; } - private Account account; - private final Set users = new HashSet<>(); - private ServiceDiscoveryResult serviceDiscoveryResult; - private final Conversation conversation; - private boolean isOnline = false; - private Error error = Error.NONE; - public OnRenameListener onRenameListener = null; - private User self; - private String password = null; - - public MucOptions(Conversation conversation) { - this.account = conversation.getAccount(); - this.conversation = conversation; - this.self = new User(this, createJoinJid(getProposedNick())); - this.self.affiliation = Affiliation.of(conversation.getAttribute("affiliation")); - this.self.role = Role.of(conversation.getAttribute("role")); + public int getUserCount() { + synchronized (users) { + return users.size(); + } } - public boolean updateConfiguration(ServiceDiscoveryResult serviceDiscoveryResult) { - this.serviceDiscoveryResult = serviceDiscoveryResult; - String name; - Field roomConfigName = getRoomInfoForm().getFieldByName("muc#roomconfig_roomname"); - if (roomConfigName != null) { - name = roomConfigName.getValue(); + public String getProposedNick() { + if (conversation.getBookmark() != null + && conversation.getBookmark().getNick() != null + && !conversation.getBookmark().getNick().trim().isEmpty()) { + return conversation.getBookmark().getNick().trim(); + } else if (!conversation.getJid().isBareJid()) { + return conversation.getJid().getResource(); } else { - List identities = serviceDiscoveryResult.getIdentities(); - String identityName = identities.size() > 0 ? identities.get(0).getName() : null; - final Jid jid = conversation.getJid(); - if (identityName != null && !identityName.equals(jid == null ? null : jid.getEscapedLocal())) { - name = identityName; - } else { - name = null; - } + return JidHelper.localPartOrFallback(account.getJid()); } - boolean changed = conversation.setAttribute("muc_name", name); - changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly")); - changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated")); - changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous")); - return changed; } - private Data getRoomInfoForm() { - final List forms = serviceDiscoveryResult == null ? Collections.emptyList() : serviceDiscoveryResult.forms; - return forms.size() == 0 ? new Data() : forms.get(0); - } - - public String getAvatar() { - return account.getRoster().getContact(conversation.getJid()).getAvatar(); + public String getActualNick() { + if (this.self.getName() != null) { + return this.self.getName(); + } else { + return this.getProposedNick(); + } } - public boolean hasFeature(String feature) { - return this.serviceDiscoveryResult != null && this.serviceDiscoveryResult.features.contains(feature); + public boolean online() { + return this.isOnline; } - public boolean hasVCards() { - return hasFeature("vcard-temp"); + public Error getError() { + return this.error; } - public boolean canInvite() { - Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowinvites"); - return !membersOnly() || self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue())); + public void setError(Error error) { + this.isOnline = isOnline && error == Error.NONE; + this.error = error; } - public boolean canChangeSubject() { - Field field = getRoomInfoForm().getFieldByName("muc#roominfo_changesubject"); - return self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue())); + public void setOnRenameListener(OnRenameListener listener) { + this.onRenameListener = listener; } - public boolean allowPm() { - final Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowpm"); - if (field == null) { - return true; //fall back if field does not exists - } - if ("anyone".equals(field.getValue())) { - return true; - } else if ("participants".equals(field.getValue())) { - return self.getRole().ranks(Role.PARTICIPANT); - } else if ("moderators".equals(field.getValue())) { - return self.getRole().ranks(Role.MODERATOR); - } else { - return false; + public void setOffline() { + synchronized (users) { + this.users.clear(); } + this.error = Error.NO_RESPONSE; + this.isOnline = false; } - public boolean participating() { - return self.getRole().ranks(Role.PARTICIPANT) || !moderated(); + public User getSelf() { + return self; } - public boolean membersOnly() { - return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, false); + public boolean setSubject(String subject) { + return this.conversation.setAttribute("subject", subject); } - public List getFeatures() { - return this.serviceDiscoveryResult != null ? this.serviceDiscoveryResult.features : Collections.emptyList(); + public String getSubject() { + return this.conversation.getAttribute("subject"); } - public boolean nonanonymous() { - return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, false); + public String getName() { + return this.conversation.getAttribute("muc_name"); } - public boolean isPrivateAndNonAnonymous() { - return membersOnly() && nonanonymous(); + private List getFallbackUsersFromCryptoTargets() { + List users = new ArrayList<>(); + for (Jid jid : conversation.getAcceptedCryptoTargets()) { + User user = new User(this, null); + user.setRealJid(jid); + users.add(user); + } + return users; } - public boolean moderated() { - return conversation.getBooleanAttribute(Conversation.ATTRIBUTE_MODERATED, false); + public List getUsersRelevantForNameAndAvatar() { + final List users; + if (isOnline) { + users = getUsers(5); + } else { + users = getFallbackUsersFromCryptoTargets(); + } + return users; } - public User deleteUser(Jid jid) { - User user = findUserByFullJid(jid); - if (user != null) { - synchronized (users) { - users.remove(user); - boolean realJidInMuc = false; - for (User u : users) { - if (user.realJid != null && user.realJid.equals(u.realJid)) { - realJidInMuc = true; - break; - } - } - boolean self = user.realJid != null && user.realJid.equals(account.getJid().asBareJid()); - if (membersOnly() - && nonanonymous() - && user.affiliation.ranks(Affiliation.MEMBER) - && user.realJid != null - && !realJidInMuc - && !self) { - user.role = Role.NONE; - user.avatar = null; - user.fullJid = null; - users.add(user); - } - } + public int NumberOfUsers() { + List users = getUsersRelevantForNameAndAvatar(); + if (users.size() >= 1) { + return users.size() + 1; // add 1 for yourself + } else { + return 1; } - return user; } - //returns true if real jid was new; - public boolean updateUser(User user) { - User old; - boolean realJidFound = false; - if (user.fullJid == null && user.realJid != null) { - old = findUserByRealJid(user.realJid); - realJidFound = old != null; - if (old != null) { - if (old.fullJid != null) { - return false; //don't add. user already exists - } else { - synchronized (users) { - users.remove(old); - } + public String createNameFromParticipants() { + List users = getUsersRelevantForNameAndAvatar(); + if (users.size() >= 2) { + StringBuilder builder = new StringBuilder(); + for (User user : users) { + if (builder.length() != 0) { + builder.append(", "); } - } - } else if (user.realJid != null) { - old = findUserByRealJid(user.realJid); - realJidFound = old != null; - synchronized (users) { - if (old != null && old.fullJid == null) { - users.remove(old); + String name = UIHelper.getDisplayName(user); + if (name != null) { + builder.append(name.split("\\s+")[0]); } } + return builder.toString(); + } else { + return null; } - old = findUserByFullJid(user.getFullJid()); - synchronized (this.users) { - if (old != null) { - users.remove(old); - } - boolean fullJidIsSelf = isOnline && user.getFullJid() != null && user.getFullJid().equals(self.getFullJid()); - if ((!membersOnly() || user.getAffiliation().ranks(Affiliation.MEMBER)) - && user.getAffiliation().outranks(Affiliation.OUTCAST) - && !fullJidIsSelf) { - this.users.add(user); - return !realJidFound && user.realJid != null; + } + + public long[] getPgpKeyIds() { + List ids = new ArrayList<>(); + for (User user : this.users) { + if (user.getPgpKeyId() != 0) { + ids.add(user.getPgpKeyId()); } } - return false; + ids.add(account.getPgpId()); + long[] primitiveLongArray = new long[ids.size()]; + for (int i = 0; i < ids.size(); ++i) { + primitiveLongArray[i] = ids.get(i); + } + return primitiveLongArray; } - public User findUserByFullJid(Jid jid) { - if (jid == null) { - return null; - } + public boolean pgpKeysInUse() { synchronized (users) { for (User user : users) { - if (jid.equals(user.getFullJid())) { - return user; + if (user.getPgpKeyId() != 0) { + return true; } } } - return null; + return false; } - public User findUserByRealJid(Jid jid) { - if (jid == null) { - return null; - } + public boolean everybodyHasKeys() { synchronized (users) { for (User user : users) { - if (jid.equals(user.realJid)) { - return user; + if (user.getPgpKeyId() == 0) { + return false; } } } - return null; - } - - public User findOrCreateUserByRealJid(Jid jid) { - User user = findUserByRealJid(jid); - if (user == null) { - user = new User(this, null); - user.setRealJid(jid); - } - return user; + return true; } - public User findUser(ReadByMarker readByMarker) { - if (readByMarker.getRealJid() != null) { - User user = findUserByRealJid(readByMarker.getRealJid().asBareJid()); - if (user == null) { - user = new User(this, readByMarker.getFullJid()); - user.setRealJid(readByMarker.getRealJid()); - } - return user; - } else if (readByMarker.getFullJid() != null) { - return findUserByFullJid(readByMarker.getFullJid()); - } else { + public Jid createJoinJid(String nick) { + try { + return Jid.of(this.conversation.getJid().asBareJid().toString() + "/" + nick); + } catch (final IllegalArgumentException e) { return null; } } - public boolean isContactInRoom(Contact contact) { - return findUserByRealJid(contact.getJid().asBareJid()) != null; - } - - public boolean isUserInRoom(Jid jid) { - return findUserByFullJid(jid) != null; + public Jid getTrueCounterpart(Jid jid) { + if (jid.equals(getSelf().getFullJid())) { + return account.getJid().asBareJid(); + } + User user = findUserByFullJid(jid); + return user == null ? null : user.realJid; } - public void setError(Error error) { - this.isOnline = isOnline && error == Error.NONE; - this.error = error; + public String getPassword() { + this.password = conversation.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD); + if (this.password == null && conversation.getBookmark() != null + && conversation.getBookmark().getPassword() != null) { + return conversation.getBookmark().getPassword(); + } else { + return this.password; + } } - public boolean setOnline() { - boolean before = this.isOnline; - this.isOnline = true; - return !before; + public void setPassword(String password) { + if (conversation.getBookmark() != null) { + conversation.getBookmark().setPassword(password); + } else { + this.password = password; + } + conversation.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password); } - public ArrayList getUsers() { - return getUsers(true); + public Conversation getConversation() { + return this.conversation; } - public ArrayList getUsers(boolean includeOffline) { + public List getMembers(final boolean includeDomains) { + ArrayList members = new ArrayList<>(); synchronized (users) { - ArrayList users = new ArrayList<>(); - for (User user : this.users) { - if (!user.isDomain() && (includeOffline || user.getRole().ranks(Role.PARTICIPANT))) { - users.add(user); + for (User user : users) { + if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null && (!user.isDomain() || includeDomains)) { + members.add(user.realJid); } } - return users; } + return members; } - public ArrayList getUsersWithChatState(ChatState state, int max) { - synchronized (users) { - ArrayList list = new ArrayList<>(); - for (User user : users) { - if (user.chatState == state) { - list.add(user); - if (list.size() >= max) { - break; - } - } + public enum Affiliation { + OWNER(4, R.string.owner), + ADMIN(3, R.string.admin), + MEMBER(2, R.string.member), + OUTCAST(0, R.string.outcast), + NONE(1, R.string.no_affiliation); + + private int resId; + private int rank; + Affiliation(int rank, int resId) { + this.resId = resId; + this.rank = rank; + } + + public static Affiliation of(@Nullable String value) { + if (value == null) { + return NONE; } - return list; + try { + return Affiliation.valueOf(value.toUpperCase(Locale.US)); + } catch (IllegalArgumentException e) { + return NONE; + } + } + + public int getResId() { + return resId; + } + + @Override + public String toString() { + return name().toLowerCase(Locale.US); + } + + public boolean outranks(Affiliation affiliation) { + return rank > affiliation.rank; + } + + public boolean ranks(Affiliation affiliation) { + return rank >= affiliation.rank; } } - public List getUsers(int max) { - ArrayList subset = new ArrayList<>(); - HashSet jids = new HashSet<>(); - jids.add(account.getJid().asBareJid()); - synchronized (users) { - for(User user : users) { - if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) { - subset.add(user); - } - if (subset.size() >= max) { - break; - } + public enum Role { + MODERATOR(R.string.moderator, 3), + VISITOR(R.string.visitor, 1), + PARTICIPANT(R.string.participant, 2), + NONE(R.string.no_role, 0); + + private int resId; + private int rank; + Role(int resId, int rank) { + this.resId = resId; + this.rank = rank; + } + + public static Role of(@Nullable String value) { + if (value == null) { + return NONE; + } + try { + return Role.valueOf(value.toUpperCase(Locale.US)); + } catch (IllegalArgumentException e) { + return NONE; } } - return subset; - } - public int getUserCount() { - synchronized (users) { - return users.size(); + public int getResId() { + return resId; } - } - public String getProposedNick() { - if (conversation.getBookmark() != null - && conversation.getBookmark().getNick() != null - && !conversation.getBookmark().getNick().trim().isEmpty()) { - return conversation.getBookmark().getNick().trim(); - } else if (!conversation.getJid().isBareJid()) { - return conversation.getJid().getResource(); - } else { - return JidHelper.localPartOrFallback(account.getJid()); + @Override + public String toString() { + return name().toLowerCase(Locale.US); } - } - public String getActualNick() { - if (this.self.getName() != null) { - return this.self.getName(); - } else { - return this.getProposedNick(); + public boolean ranks(Role role) { + return rank >= role.rank; } } - public boolean online() { - return this.isOnline; + public enum Error { + NO_RESPONSE, + SERVER_NOT_FOUND, + NONE, + NICK_IN_USE, + PASSWORD_REQUIRED, + BANNED, + MEMBERS_ONLY, + RESOURCE_CONSTRAINT, + KICKED, + SHUTDOWN, + DESTROYED, + INVALID_NICK, + UNKNOWN } - public Error getError() { - return this.error; - } + private interface OnEventListener { + void onSuccess(); - public void setOnRenameListener(OnRenameListener listener) { - this.onRenameListener = listener; + void onFailure(); } - public void setOffline() { - synchronized (users) { - this.users.clear(); - } - this.error = Error.NO_RESPONSE; - this.isOnline = false; - } + public interface OnRenameListener extends OnEventListener { - public User getSelf() { - return self; } - public boolean setSubject(String subject) { - return this.conversation.setAttribute("subject", subject); - } + public static class User implements Comparable { + private Role role = Role.NONE; + private Affiliation affiliation = Affiliation.NONE; + private Jid realJid; + private Jid fullJid; + private long pgpKeyId = 0; + private Avatar avatar; + private MucOptions options; + private ChatState chatState = Config.DEFAULT_CHATSTATE; - public String getSubject() { - return this.conversation.getAttribute("subject"); - } + public User(MucOptions options, Jid from) { + this.options = options; + this.fullJid = from; + } - public String getName() { - return this.conversation.getAttribute("muc_name"); - } + public String getName() { + return fullJid == null ? null : fullJid.getResource(); + } - private List getFallbackUsersFromCryptoTargets() { - List users = new ArrayList<>(); - for (Jid jid : conversation.getAcceptedCryptoTargets()) { - User user = new User(this, null); - user.setRealJid(jid); - users.add(user); + public Role getRole() { + return this.role; } - return users; - } - public List getUsersRelevantForNameAndAvatar() { - final List users; - if (isOnline) { - users = getUsers(5); - } else { - users = getFallbackUsersFromCryptoTargets(); + public void setRole(String role) { + this.role = Role.of(role); } - return users; - } + public Affiliation getAffiliation() { + return this.affiliation; + } - public int NumberOfUsers() { - List users = getUsersRelevantForNameAndAvatar(); - if (users.size() >= 1) { - return users.size(); - } else { - return 0; + public void setAffiliation(String affiliation) { + this.affiliation = Affiliation.of(affiliation); } - } + public long getPgpKeyId() { + if (this.pgpKeyId != 0) { + return this.pgpKeyId; + } else if (realJid != null) { + return getAccount().getRoster().getContact(realJid).getPgpKeyId(); + } else { + return 0; + } + } + public void setPgpKeyId(long id) { + this.pgpKeyId = id; + } - public String createNameFromParticipants() { - List users = getUsersRelevantForNameAndAvatar(); - if (users.size() >= 1) { - StringBuilder builder = new StringBuilder(); - for (User user : users) { - if (builder.length() != 0) { - builder.append(", "); - } - String name = UIHelper.getDisplayName(user); - if (name != null) { - builder.append(name.split("\\s+")[0]); - } + public Contact getContact() { + if (fullJid != null) { + return getAccount().getRoster().getContactFromRoster(realJid); + } else if (realJid != null) { + return getAccount().getRoster().getContact(realJid); + } else { + return null; } - return builder.toString(); - } else { - return null; } - } - public long[] getPgpKeyIds() { - List ids = new ArrayList<>(); - for (User user : this.users) { - if (user.getPgpKeyId() != 0) { - ids.add(user.getPgpKeyId()); + public boolean setAvatar(Avatar avatar) { + if (this.avatar != null && this.avatar.equals(avatar)) { + return false; + } else { + this.avatar = avatar; + return true; } } - ids.add(account.getPgpId()); - long[] primitiveLongArray = new long[ids.size()]; - for (int i = 0; i < ids.size(); ++i) { - primitiveLongArray[i] = ids.get(i); - } - return primitiveLongArray; - } - public boolean pgpKeysInUse() { - synchronized (users) { - for (User user : users) { - if (user.getPgpKeyId() != 0) { - return true; - } + public String getAvatar() { + if (avatar != null) { + return avatar.getFilename(); } + Avatar avatar = realJid != null ? getAccount().getRoster().getContact(realJid).getAvatar() : null; + return avatar == null ? null : avatar.getFilename(); } - return false; - } - public boolean everybodyHasKeys() { - synchronized (users) { - for (User user : users) { - if (user.getPgpKeyId() == 0) { - return false; - } - } + public Account getAccount() { + return options.getAccount(); } - return true; - } - public Jid createJoinJid(String nick) { - try { - return Jid.of(this.conversation.getJid().asBareJid().toString() + "/" + nick); - } catch (final IllegalArgumentException e) { - return null; + public Conversation getConversation() { + return options.getConversation(); } - } - public Jid getTrueCounterpart(Jid jid) { - if (jid.equals(getSelf().getFullJid())) { - return account.getJid().asBareJid(); + public Jid getFullJid() { + return fullJid; } - User user = findUserByFullJid(jid); - return user == null ? null : user.realJid; - } - public String getPassword() { - this.password = conversation.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD); - if (this.password == null && conversation.getBookmark() != null - && conversation.getBookmark().getPassword() != null) { - return conversation.getBookmark().getPassword(); - } else { - return this.password; + @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; + } - } - public void setPassword(String password) { - if (conversation.getBookmark() != null) { - conversation.getBookmark().setPassword(password); - } else { - this.password = password; + public boolean isDomain() { + return realJid != null && realJid.getLocal() == null && role == Role.NONE; } - conversation.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password); - } - public Conversation getConversation() { - return this.conversation; - } + @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; + } - public List getMembers(final boolean includeDomains) { - ArrayList members = new ArrayList<>(); - synchronized (users) { - for (User user : users) { - if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null && (!user.isDomain() || includeDomains)) { - members.add(user.realJid); - } + @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().asBareJid()); + } + + @Override + public int compareTo(@NonNull User another) { + if (another.getAffiliation().outranks(getAffiliation())) { + return 1; + } else if (getAffiliation().outranks(another.getAffiliation())) { + return -1; + } else { + return getComparableName().compareToIgnoreCase(another.getComparableName()); } } - return members; + + private String getComparableName() { + Contact contact = getContact(); + if (contact != null) { + return contact.getDisplayName(); + } else { + String name = getName(); + return name == null ? "" : name; + } + } + + public Jid getRealJid() { + return realJid; + } + + public void setRealJid(Jid jid) { + this.realJid = jid != null ? jid.asBareJid() : null; + } + + public boolean setChatState(ChatState chatState) { + if (this.chatState == chatState) { + return false; + } + this.chatState = chatState; + return true; + } } } diff --git a/src/main/java/de/pixart/messenger/parser/PresenceParser.java b/src/main/java/de/pixart/messenger/parser/PresenceParser.java index 39a3cfeba..6a878d27f 100644 --- a/src/main/java/de/pixart/messenger/parser/PresenceParser.java +++ b/src/main/java/de/pixart/messenger/parser/PresenceParser.java @@ -115,6 +115,14 @@ public class PresenceParser extends AbstractParser implements if (user.setAvatar(avatar)) { mXmppConnectionService.getAvatarService().clear(user); } + if (user.getRealJid() != null) { + Contact c = conversation.getAccount().getRoster().getContact(user.getRealJid()); + if (c.setAvatar(avatar)) { + mXmppConnectionService.syncRoster(conversation.getAccount()); + mXmppConnectionService.getAvatarService().clear(c); + mXmppConnectionService.updateRosterUi(); + } + } } else if (mXmppConnectionService.isDataSaverDisabled()) { mXmppConnectionService.fetchAvatar(mucOptions.getAccount(), avatar); } diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java index 365f8fa87..4cc5b7955 100644 --- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java +++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java @@ -925,7 +925,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { final SQLiteDatabase db = this.getWritableDatabase(); db.beginTransaction(); for (Contact contact : roster.getContacts()) { - if (contact.getOption(Contact.Options.IN_ROSTER) || contact.getAvatar() != null) { + if (contact.getOption(Contact.Options.IN_ROSTER) || contact.getAvatarFilename() != null) { db.insert(Contact.TABLENAME, null, contact.getContentValues()); } else { String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?"; diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java index bf415515b..aa861c147 100644 --- a/src/main/java/de/pixart/messenger/services/AvatarService.java +++ b/src/main/java/de/pixart/messenger/services/AvatarService.java @@ -80,8 +80,8 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { if (avatar != null || cachedOnly) { return avatar; } - if (avatar == null && contact.getAvatar() != null) { - avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatar(), size); + if (avatar == null && contact.getAvatarFilename() != null) { + avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatarFilename(), size); } if (avatar == null && contact.getProfilePhoto() != null) { try { @@ -146,7 +146,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) { Contact c = user.getContact(); - if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null || user.getAvatar() == null)) { + if (c != null && (c.getProfilePhoto() != null || c.getAvatarFilename() != null || user.getAvatar() == null)) { return get(c, size, cachedOnly); } else { return getImpl(user, size, cachedOnly); @@ -183,6 +183,10 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } } for (Conversation conversation : mXmppConnectionService.findAllConferencesWith(contact)) { + MucOptions.User user = conversation.getMucOptions().findUserByRealJid(contact.getJid().asBareJid()); + if (user != null) { + clear(user); + } clear(conversation); } } @@ -234,7 +238,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { Jid jid = bookmark.getJid(); Account account = bookmark.getAccount(); Contact contact = jid == null ? null : account.getRoster().getContact(jid); - if (contact != null && contact.getAvatar() != null) { + if (contact != null && contact.getAvatarFilename() != null) { return get(contact, size, cachedOnly); } String seed = jid != null ? jid.asBareJid().toString() : null; @@ -414,14 +418,14 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { return get(message.getCounterparts(), size, cachedOnly); } else if (message.getStatus() == Message.STATUS_RECEIVED) { Contact c = message.getContact(); - if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) { + if (c != null && (c.getProfilePhoto() != null || c.getAvatarFilename() != null)) { return get(c, size, cachedOnly); } else if (conversation instanceof Conversation && message.getConversation().getMode() == Conversation.MODE_MULTI) { final Jid trueCounterpart = message.getTrueCounterpart(); final MucOptions mucOptions = ((Conversation) conversation).getMucOptions(); MucOptions.User user; if (trueCounterpart != null) { - user = mucOptions.findUserByRealJid(trueCounterpart); + user = mucOptions.findOrCreateUserByRealJid(trueCounterpart, message.getCounterpart()); } else { user = mucOptions.findUserByFullJid(message.getCounterpart()); } @@ -520,11 +524,11 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { Contact contact = user.getContact(); if (contact != null) { Uri uri = null; - if (contact.getAvatar() != null) { - uri = mXmppConnectionService.getFileBackend().getAvatarUri( - contact.getAvatar()); - } else if (contact.getProfilePhoto() != null) { + if (contact.getProfilePhoto() != null) { uri = Uri.parse(contact.getProfilePhoto()); + } else if (contact.getAvatarFilename() != null) { + uri = mXmppConnectionService.getFileBackend().getAvatarUri( + contact.getAvatarFilename()); } if (drawTile(canvas, uri, left, top, right, bottom)) { return true; diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index 41d029d12..396a68446 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -3460,6 +3460,14 @@ public class XmppConnectionService extends Service { updateConversationUi(); updateMucRosterUi(); } + if (user.getRealJid() != null) { + Contact contact = account.getRoster().getContact(user.getRealJid()); + if (contact.setAvatar(avatar)) { + syncRoster(account); + getAvatarService().clear(contact); + updateRosterUi(); + } + } } } } diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java index e364c00bf..a0f4bf894 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java @@ -1221,7 +1221,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke Jid tcp = message.getTrueCounterpart(); Jid cp = message.getCounterpart(); if (cp != null && !cp.isBareJid()) { - User userByRealJid = tcp != null ? conversation.getMucOptions().findOrCreateUserByRealJid(tcp) : null; + User userByRealJid = tcp != null ? conversation.getMucOptions().findOrCreateUserByRealJid(tcp, cp) : null; final User user = userByRealJid != null ? userByRealJid : conversation.getMucOptions().findUserByFullJid(cp); final PopupMenu popupMenu = new PopupMenu(getActivity(), v); popupMenu.inflate(R.menu.muc_details_context); -- cgit v1.2.3