M src/main/java/eu/siacs/conversations/entities/MucOptions.java => src/main/java/eu/siacs/conversations/entities/MucOptions.java +50 -6
@@ 53,7 53,8 @@ public class MucOptions {
public MucOptions(Conversation conversation) {
this.account = conversation.getAccount();
this.conversation = conversation;
- this.self = new User(this, createJoinJid(getProposedNick()));
+ final String nick = getProposedNick(conversation.getAttribute("mucNick"));
+ this.self = new User(this, createJoinJid(nick), nick);
this.self.affiliation = Affiliation.of(conversation.getAttribute("affiliation"));
this.self.role = Role.of(conversation.getAttribute("role"));
}
@@ 66,6 67,7 @@ public class MucOptions {
this.self = user;
final boolean roleChanged = this.conversation.setAttribute("role", user.role.toString());
final boolean affiliationChanged = this.conversation.setAttribute("affiliation", user.affiliation.toString());
+ this.conversation.setAttribute("mucNick", user.getNick());
return roleChanged || affiliationChanged;
}
@@ 291,6 293,20 @@ public class MucOptions {
return false;
}
+ public User findUserByName(final String name) {
+ if (name == null) {
+ return null;
+ }
+ synchronized (users) {
+ for (User user : users) {
+ if (name.equals(user.getName())) {
+ return user;
+ }
+ }
+ }
+ return null;
+ }
+
public User findUserByFullJid(Jid jid) {
if (jid == null) {
return null;
@@ 322,7 338,7 @@ public class MucOptions {
public User findOrCreateUserByRealJid(Jid jid, Jid fullJid) {
User user = findUserByRealJid(jid);
if (user == null) {
- user = new User(this, fullJid);
+ user = new User(this, fullJid, null);
user.setRealJid(jid);
}
return user;
@@ 422,11 438,17 @@ public class MucOptions {
}
public String getProposedNick() {
+ return getProposedNick(null);
+ }
+
+ public String getProposedNick(final String mucNick) {
final Bookmark bookmark = this.conversation.getBookmark();
final String bookmarkedNick = normalize(account.getJid(), bookmark == null ? null : bookmark.getNick());
if (bookmarkedNick != null) {
this.tookProposedNickFromBookmark = true;
return bookmarkedNick;
+ } else if (mucNick != null) {
+ return mucNick;
} else if (!conversation.getJid().isBareJid()) {
return conversation.getJid().getResource();
} else {
@@ 456,6 478,14 @@ public class MucOptions {
}
public String getActualNick() {
+ if (this.self.getNick() != null) {
+ return this.self.getNick();
+ } else {
+ return this.getProposedNick();
+ }
+ }
+
+ public String getActualName() {
if (this.self.getName() != null) {
return this.self.getName();
} else {
@@ 507,7 537,7 @@ public class MucOptions {
private List<User> getFallbackUsersFromCryptoTargets() {
List<User> users = new ArrayList<>();
for (Jid jid : conversation.getAcceptedCryptoTargets()) {
- User user = new User(this, null);
+ User user = new User(this, null, null);
user.setRealJid(jid);
users.add(user);
}
@@ 581,10 611,18 @@ public class MucOptions {
}
public Jid createJoinJid(String nick) {
+ return createJoinJid(nick, true);
+ }
+
+ private Jid createJoinJid(String nick, boolean tryFix) {
try {
return conversation.getJid().withResource(nick);
} catch (final IllegalArgumentException e) {
- return null;
+ try {
+ return tryFix ? createJoinJid(gnu.inet.encoding.Punycode.encode(nick), false) : null;
+ } catch (final gnu.inet.encoding.PunycodeException e2) {
+ return null;
+ }
}
}
@@ 748,20 786,26 @@ public class MucOptions {
private Affiliation affiliation = Affiliation.NONE;
private Jid realJid;
private Jid fullJid;
+ private String nick;
private long pgpKeyId = 0;
private Avatar avatar;
private final MucOptions options;
private ChatState chatState = Config.DEFAULT_CHAT_STATE;
- public User(MucOptions options, Jid fullJid) {
+ public User(MucOptions options, Jid fullJid, final String nick) {
this.options = options;
this.fullJid = fullJid;
+ this.nick = nick == null ? getName() : nick;
}
public String getName() {
return fullJid == null ? null : fullJid.getResource();
}
+ public String getNick() {
+ return nick;
+ }
+
public Role getRole() {
return this.role;
}
@@ 869,7 913,7 @@ public class MucOptions {
@Override
public String toString() {
- return "[fulljid:" + fullJid + ",realjid:" + realJid + ",affiliation" + affiliation.toString() + "]";
+ return "[fulljid:" + fullJid + ",realjid:" + realJid + ",nick:" + nick + ",affiliation" + affiliation.toString() + "]";
}
public boolean realJidMatchesAccount() {
M src/main/java/eu/siacs/conversations/parser/AbstractParser.java => src/main/java/eu/siacs/conversations/parser/AbstractParser.java +9 -3
@@ 132,10 132,10 @@ public abstract class AbstractParser {
}
public static MucOptions.User parseItem(Conversation conference, Element item) {
- return parseItem(conference,item, null);
+ return parseItem(conference,item,null,null);
}
- public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid) {
+ public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid, final String nickname) {
final String local = conference.getJid().getLocal();
final String domain = conference.getJid().getDomain().toEscapedString();
String affiliation = item.getAttribute("affiliation");
@@ 149,7 149,13 @@ public abstract class AbstractParser {
}
}
Jid realJid = item.getAttributeAsJid("jid");
- MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid);
+ if (fullJid != null) nick = fullJid.getResource();
+ try {
+ if (nickname != null && nick != null && !nick.equals(nickname) && gnu.inet.encoding.Punycode.decode(nick).equals(nickname)) {
+ nick = nickname;
+ }
+ } catch (final gnu.inet.encoding.PunycodeException e) { }
+ MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid, nick);
if (InvalidJid.isValid(realJid)) {
user.setRealJid(realJid);
}
M src/main/java/eu/siacs/conversations/parser/PresenceParser.java => src/main/java/eu/siacs/conversations/parser/PresenceParser.java +3 -2
@@ 63,6 63,7 @@ public class PresenceParser extends AbstractParser implements
if (!from.isBareJid()) {
final String type = packet.getAttribute("type");
final Element x = packet.findChild("x", Namespace.MUC_USER);
+ final Element nick = packet.findChild("nick", Namespace.NICK);
Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
final List<String> codes = getStatusCodes(x);
if (type == null) {
@@ 70,7 71,7 @@ public class PresenceParser extends AbstractParser implements
Element item = x.findChild("item");
if (item != null && !from.isBareJid()) {
mucOptions.setError(MucOptions.Error.NONE);
- MucOptions.User user = parseItem(conversation, item, from);
+ MucOptions.User user = parseItem(conversation, item, from, nick == null ? null : nick.getContent());
if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || (codes.contains(MucOptions.STATUS_CODE_ROOM_CREATED) && jid.equals(InvalidJid.getNullForInvalid(item.getAttributeAsJid("jid"))))) {
if (mucOptions.setOnline()) {
mXmppConnectionService.getAvatarService().clear(mucOptions);
@@ 174,7 175,7 @@ public class PresenceParser extends AbstractParser implements
} else if (!from.isBareJid()){
Element item = x.findChild("item");
if (item != null) {
- mucOptions.updateUser(parseItem(conversation, item, from));
+ mucOptions.updateUser(parseItem(conversation, item, from, nick == null ? null : nick.getContent()));
}
MucOptions.User user = mucOptions.deleteUser(from);
if (user != null) {
M src/main/java/eu/siacs/conversations/services/NotificationService.java => src/main/java/eu/siacs/conversations/services/NotificationService.java +5 -2
@@ 1817,11 1817,14 @@ public class NotificationService {
final String nick = conversation.getMucOptions().getActualNick();
final Pattern highlight = generateNickHighlightPattern(nick);
- if (message.getBody() == null || nick == null) {
+ final String name = conversation.getMucOptions().getActualName();
+ final Pattern highlightName = generateNickHighlightPattern(name);
+ if (message.getBody() == null || (nick == null && name == null)) {
return false;
}
final Matcher m = highlight.matcher(message.getBody());
- return (m.find() || message.isPrivateMessage());
+ final Matcher m2 = highlightName.matcher(message.getBody());
+ return (m.find() || m2.find() || message.isPrivateMessage());
} else {
return false;
}
M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +10 -8
@@ 3037,7 3037,7 @@ public class XmppConnectionService extends Service {
final Jid joinJid = mucOptions.getSelf().getFullJid();
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": joining conversation " + joinJid.toString());
- PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous() || onConferenceJoined != null);
+ PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous() || onConferenceJoined != null, mucOptions.getSelf().getNick());
packet.setTo(joinJid);
Element x = packet.addChild("x", "http://jabber.org/protocol/muc");
if (conversation.getMucOptions().getPassword() != null) {
@@ 3303,17 3303,18 @@ public class XmppConnectionService extends Service {
databaseBackend.updateConversation(conversation);
}
+ final String nick = self.getNick();
final Bookmark bookmark = conversation.getBookmark();
final String bookmarkedNick = bookmark == null ? null : bookmark.getNick();
- if (bookmark != null && (tookProposedNickFromBookmark || TextUtils.isEmpty(bookmarkedNick)) && !full.getResource().equals(bookmarkedNick)) {
+ if (bookmark != null && (tookProposedNickFromBookmark || TextUtils.isEmpty(bookmarkedNick)) && !nick.equals(bookmarkedNick)) {
final Account account = conversation.getAccount();
final String defaultNick = MucOptions.defaultNick(account);
- if (TextUtils.isEmpty(bookmarkedNick) && full.getResource().equals(defaultNick)) {
+ if (TextUtils.isEmpty(bookmarkedNick) && nick.equals(defaultNick)) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": do not overwrite empty bookmark nick with default nick for " + conversation.getJid().asBareJid());
return;
}
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": persist nick '" + full.getResource() + "' into bookmark for " + conversation.getJid().asBareJid());
- bookmark.setNick(full.getResource());
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": persist nick '" + nick + "' into bookmark for " + conversation.getJid().asBareJid());
+ bookmark.setNick(nick);
createBookmark(bookmark.getAccount(), bookmark);
}
}
@@ 3339,7 3340,7 @@ public class XmppConnectionService extends Service {
}
});
- final PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, options.nonanonymous());
+ final PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, options.nonanonymous(), nick);
packet.setTo(joinJid);
sendPresencePacket(account, packet);
} else {
@@ 4183,7 4184,7 @@ public class XmppConnectionService extends Service {
if (conversation.getAccount() == account && conversation.getMode() == Conversational.MODE_MULTI) {
final MucOptions mucOptions = conversation.getMucOptions();
if (mucOptions.online()) {
- PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous());
+ PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous(), mucOptions.getSelf().getNick());
packet.setTo(mucOptions.getSelf().getFullJid());
connection.sendPresencePacket(packet);
}
@@ 5107,7 5108,8 @@ public class XmppConnectionService extends Service {
public void saveConversationAsBookmark(Conversation conversation, String name) {
final Account account = conversation.getAccount();
final Bookmark bookmark = new Bookmark(account, conversation.getJid().asBareJid());
- final String nick = conversation.getJid().getResource();
+ String nick = conversation.getMucOptions().getActualNick();
+ if (nick == null) nick = conversation.getJid().getResource();
if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
bookmark.setNick(nick);
}
M src/main/java/eu/siacs/conversations/ui/ConversationFragment.java => src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +9 -7
@@ 991,10 991,13 @@ public class ConversationFragment extends XmppFragment
} else if (multi && conversation.getNextCounterpart() != null) {
this.binding.textinput.setHint(R.string.send_message);
this.binding.textInputHint.setVisibility(View.VISIBLE);
+ final MucOptions.User user = conversation.getMucOptions().findUserByName(conversation.getNextCounterpart().getResource());
+ String nick = user == null ? null : user.getNick();
+ if (nick == null) nick = conversation.getNextCounterpart().getResource();
this.binding.textInputHint.setText(
getString(
R.string.send_private_message_to,
- conversation.getNextCounterpart().getResource()));
+ nick));
binding.conversationViewPager.setCurrentItem(0);
} else if (multi && !conversation.getMucOptions().participating()) {
this.binding.textInputHint.setVisibility(View.GONE);
@@ 3889,7 3892,7 @@ public class ConversationFragment extends XmppFragment
}
List<String> completions = new ArrayList<>();
for (MucOptions.User user : conversation.getMucOptions().getUsers()) {
- String name = user.getName();
+ String name = user.getNick();
if (name != null && name.startsWith(incomplete)) {
completions.add(name + (firstWord ? ": " : " "));
}
@@ 4093,10 4096,9 @@ public class ConversationFragment extends XmppFragment
if (mucOptions.participating()
|| ((Conversation) message.getConversation()).getNextCounterpart()
!= null) {
- if (!mucOptions.isUserInRoom(user)
- && mucOptions.findUserByRealJid(
- tcp == null ? null : tcp.asBareJid())
- == null) {
+ MucOptions.User mucUser = mucOptions.findUserByFullJid(user);
+ MucOptions.User tcpMucUser = mucOptions.findUserByRealJid(tcp == null ? null : tcp.asBareJid());
+ if (mucUser == null && tcpMucUser == null) {
Toast.makeText(
getActivity(),
activity.getString(
@@ 4105,7 4107,7 @@ public class ConversationFragment extends XmppFragment
Toast.LENGTH_SHORT)
.show();
}
- highlightInConference(user.getResource());
+ highlightInConference(mucUser == null ? (tcpMucUser == null ? user.getResource() : tcpMucUser.getNick()) : mucUser.getNick());
} else {
Toast.makeText(
getActivity(),
M src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java => src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java +1 -1
@@ 68,7 68,7 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ
final String needle = search.toLowerCase(Locale.getDefault());
ArrayList<MucOptions.User> filtered = new ArrayList<>();
for(MucOptions.User user : allUsers) {
- final String name = user.getName();
+ final String name = user.getNick();
final Contact contact = user.getContact();
if (name != null && name.toLowerCase(Locale.getDefault()).contains(needle) || contact != null && contact.getDisplayName().toLowerCase(Locale.getDefault()).contains(needle)) {
filtered.add(user);
M src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +6 -0
@@ 582,6 582,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
while (matcher.find()) {
body.setSpan(new StyleSpan(Typeface.BOLD), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
+
+ pattern = NotificationService.generateNickHighlightPattern(conversation.getMucOptions().getActualName());
+ matcher = pattern.matcher(body);
+ while (matcher.find()) {
+ body.setSpan(new StyleSpan(Typeface.BOLD), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
}
Matcher matcher = Emoticons.getEmojiPattern(body).matcher(body);
M src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java +2 -2
@@ 71,7 71,7 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
viewHolder.binding.getRoot().setOnClickListener(v -> {
final XmppActivity activity = XmppActivity.find(v);
if (activity != null) {
- activity.highlightInMuc(user.getConversation(), user.getName());
+ activity.highlightInMuc(user.getConversation(), user.getNick());
}
});
viewHolder.binding.getRoot().setTag(user);
@@ 80,7 80,7 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
selectedUser = user;
return false;
});
- final String name = user.getName();
+ final String name = user.getNick();
final Contact contact = user.getContact();
if (contact != null) {
final String displayName = contact.getDisplayName();
M src/main/java/eu/siacs/conversations/ui/adapter/UserPreviewAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/UserPreviewAdapter.java +1 -1
@@ 38,7 38,7 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
viewHolder.binding.getRoot().setOnClickListener(v -> {
final XmppActivity activity = XmppActivity.find(v);
if (activity != null) {
- activity.highlightInMuc(user.getConversation(), user.getName());
+ activity.highlightInMuc(user.getConversation(), user.getNick());
}
});
viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
M src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java => src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java +1 -1
@@ 43,7 43,7 @@ public final class MucDetailsContextMenuHelper {
} else if (user.getRealJid() != null) {
name = user.getRealJid().asBareJid().toString();
} else {
- name = user.getName();
+ name = user.getNick();
}
menu.setHeaderTitle(name);
MucDetailsContextMenuHelper.configureMucDetailsContextMenu(activity, menu, user.getConversation(), user);
M src/main/java/eu/siacs/conversations/utils/UIHelper.java => src/main/java/eu/siacs/conversations/utils/UIHelper.java +6 -2
@@ 462,7 462,7 @@ public class UIHelper {
if (contact != null) {
return contact.getDisplayName();
} else {
- final String name = user.getName();
+ final String name = user.getNick();
if (name != null) {
return name;
}
@@ 540,6 540,10 @@ public class UIHelper {
if (contact != null) {
return contact.getDisplayName();
} else {
+ if (conversation instanceof Conversation) {
+ final MucOptions.User user = ((Conversation) conversation).getMucOptions().findUserByFullJid(message.getCounterpart());
+ if (user != null) return getDisplayName(user);
+ }
return getDisplayedMucCounterpart(message.getCounterpart());
}
} else {
@@ 547,7 551,7 @@ public class UIHelper {
}
} else {
if (conversation instanceof Conversation && conversation.getMode() == Conversation.MODE_MULTI) {
- return ((Conversation) conversation).getMucOptions().getSelf().getName();
+ return ((Conversation) conversation).getMucOptions().getSelf().getNick();
} else {
final Account account = conversation.getAccount();
final Jid jid = account.getJid();