1package eu.siacs.conversations.entities;
2
3import android.content.Context;
4import androidx.annotation.NonNull;
5import androidx.annotation.Nullable;
6import com.google.common.base.Strings;
7import com.google.common.collect.ImmutableList;
8import eu.siacs.conversations.utils.StringUtils;
9import eu.siacs.conversations.utils.UIHelper;
10import eu.siacs.conversations.xml.Element;
11import eu.siacs.conversations.xmpp.Jid;
12import im.conversations.android.xmpp.model.bookmark.Storage;
13import im.conversations.android.xmpp.model.bookmark2.Extensions;
14import java.lang.ref.WeakReference;
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.List;
19import java.util.Locale;
20import java.util.Map;
21
22public class Bookmark extends Element implements ListItem {
23
24 private final Account account;
25 private WeakReference<Conversation> conversation;
26 private Jid jid;
27 protected Extensions extensions = new Extensions();
28
29 public Bookmark(final Account account, final Jid jid) {
30 super("conference");
31 this.jid = jid;
32 this.setAttribute("jid", jid);
33 this.account = account;
34 }
35
36 public Bookmark(Account account) {
37 super("conference");
38 this.account = account;
39 }
40
41 public static Map<Jid, Bookmark> parseFromStorage(
42 final Storage storage, final Account account) {
43 // TODO refactor to use extensions. get rid of the 'old' handling
44 if (storage == null) {
45 return Collections.emptyMap();
46 }
47 final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
48 for (final Element item : storage.getChildren()) {
49 if (item.getName().equals("conference")) {
50 final Bookmark bookmark = Bookmark.parse(item, account);
51 if (bookmark != null) {
52 final Bookmark old = bookmarks.put(bookmark.jid, bookmark);
53 if (old != null
54 && old.getBookmarkName() != null
55 && bookmark.getBookmarkName() == null) {
56 bookmark.setBookmarkName(old.getBookmarkName());
57 }
58 }
59 }
60 }
61 return bookmarks;
62 }
63
64 public static Bookmark parse(Element element, Account account) {
65 Bookmark bookmark = new Bookmark(account);
66 bookmark.setAttributes(element.getAttributes());
67 bookmark.setChildren(element.getChildren());
68 bookmark.jid = Jid.Invalid.getNullForInvalid(bookmark.getAttributeAsJid("jid"));
69 if (bookmark.jid == null) {
70 return null;
71 }
72 return bookmark;
73 }
74
75 public Extensions getExtensions() {
76 return extensions;
77 }
78
79 public void addGroup(final String group) {
80 addChild("group", "jabber:iq:roster").setContent(group);
81 extensions.addChild("group", "jabber:iq:roster").setContent(group);
82 }
83
84 public void setGroups(List<String> groups) {
85 final List<Element> children = ImmutableList.copyOf(getChildren());
86 for (final Element el : children) {
87 if (el.getName().equals("group")) {
88 removeChild(el);
89 }
90 }
91
92 final List<Element> extChildren = ImmutableList.copyOf(extensions.getChildren());
93 for (final Element el : extChildren) {
94 if (el.getName().equals("group")) {
95 extensions.removeChild(el);
96 }
97 }
98
99 for (final String group : groups) {
100 addGroup(group);
101 }
102 }
103
104 public void setAutojoin(boolean autojoin) {
105 if (autojoin) {
106 this.setAttribute("autojoin", "true");
107 } else {
108 this.setAttribute("autojoin", "false");
109 }
110 }
111
112 @Override
113 public int compareTo(final @NonNull ListItem another) {
114 if (getJid().isDomainJid() && !another.getJid().isDomainJid()) {
115 return -1;
116 } else if (!getJid().isDomainJid() && another.getJid().isDomainJid()) {
117 return 1;
118 }
119
120 if (getDisplayName().equals(another.getDisplayName())) {
121 return getJid().compareTo(another.getJid());
122 }
123
124 return this.getDisplayName().compareToIgnoreCase(
125 another.getDisplayName());
126 }
127
128 @Override
129 public String getDisplayName() {
130 final Conversation c = getConversation();
131 final String name = getBookmarkName();
132 if (c != null) {
133 return c.getName().toString();
134 } else if (printableValue(name, false)) {
135 return name.trim();
136 } else {
137 Jid jid = this.getJid();
138 return jid != null && jid.getLocal() != null ? jid.getLocal() : "";
139 }
140 }
141
142 public static boolean printableValue(@Nullable String value, boolean permitNone) {
143 return value != null && !value.trim().isEmpty() && (permitNone || !"None".equals(value));
144 }
145
146 public static boolean printableValue(@Nullable String value) {
147 return printableValue(value, true);
148 }
149
150 @Override
151 public Jid getJid() {
152 return this.jid;
153 }
154
155 public Jid getFullJid() {
156 return getFullJid(getNick(), true);
157 }
158
159 private Jid getFullJid(final String nick, boolean tryFix) {
160 try {
161 return jid == null || nick == null || nick.trim().isEmpty() ? jid : jid.withResource(nick);
162 } catch (final IllegalArgumentException e) {
163 try {
164 return tryFix ? getFullJid(gnu.inet.encoding.Punycode.encode(nick), false) : null;
165 } catch (final Exception e2) {
166 return null;
167 }
168 }
169 }
170
171 public List<Tag> getGroupTags() {
172 ArrayList<Tag> tags = new ArrayList<>();
173
174 for (Element element : getChildren()) {
175 if (element.getName().equals("group") && element.getContent() != null) {
176 String group = element.getContent();
177 tags.add(new Tag(group));
178 }
179 }
180
181 return tags;
182 }
183
184 @Override
185 public List<Tag> getTags(Context context) {
186 ArrayList<Tag> tags = new ArrayList<>();
187 tags.add(new Tag("Channel"));
188 tags.addAll(getGroupTags());
189 return tags;
190 }
191
192 public String getNick() {
193 return Strings.emptyToNull(this.findChildContent("nick"));
194 }
195
196 public void setNick(String nick) {
197 Element element = this.findChild("nick");
198 if (element == null) {
199 element = this.addChild("nick");
200 }
201 element.setContent(nick);
202 }
203
204 public boolean autojoin() {
205 return this.getAttributeAsBoolean("autojoin");
206 }
207
208 public String getPassword() {
209 return this.findChildContent("password");
210 }
211
212 public void setPassword(String password) {
213 Element element = this.findChild("password");
214 if (element != null) {
215 element.setContent(password);
216 }
217 }
218
219 @Override
220 public boolean match(Context context, String needle) {
221 if (needle == null) {
222 return true;
223 }
224 needle = needle.toLowerCase(Locale.US);
225 String[] parts = needle.split("[,\\s]+");
226 if (parts.length > 1) {
227 for (String part : parts) {
228 if (!match(context, part)) {
229 return false;
230 }
231 }
232 return true;
233 } else if (parts.length > 0) {
234 final Jid jid = getJid();
235 return (jid != null && jid.toString().contains(parts[0])) ||
236 getDisplayName().toLowerCase(Locale.US).contains(parts[0]) ||
237 matchInTag(context, parts[0]);
238 } else {
239 final Jid jid = getJid();
240 return (jid != null && jid.toString().contains(needle)) ||
241 getDisplayName().toLowerCase(Locale.US).contains(needle);
242 }
243 }
244
245 private boolean matchInTag(Context context, String needle) {
246 needle = needle.toLowerCase(Locale.US);
247 for (Tag tag : getTags(context)) {
248 if (tag.getName().toLowerCase(Locale.US).contains(needle)) {
249 return true;
250 }
251 }
252 return false;
253 }
254
255 public Account getAccount() {
256 return this.account;
257 }
258
259 public synchronized Conversation getConversation() {
260 return this.conversation != null ? this.conversation.get() : null;
261 }
262
263 public synchronized void setConversation(Conversation conversation) {
264 if (this.conversation != null) {
265 this.conversation.clear();
266 }
267 if (conversation == null) {
268 this.conversation = null;
269 } else {
270 this.conversation = new WeakReference<>(conversation);
271 }
272 }
273
274 public String getBookmarkName() {
275 return this.getAttribute("name");
276 }
277
278 public boolean setBookmarkName(String name) {
279 String before = getBookmarkName();
280 if (name != null) {
281 this.setAttribute("name", name);
282 } else {
283 this.removeAttribute("name");
284 }
285 return StringUtils.changed(before, name);
286 }
287
288 @Override
289 public int getAvatarBackgroundColor() {
290 return UIHelper.getColorForName(
291 jid != null ? jid.asBareJid().toString() : getDisplayName());
292 }
293
294 @Override
295 public String getAvatarName() {
296 return getDisplayName();
297 }
298
299 public void setExtensions(Extensions extensions) {
300 this.extensions = extensions;
301 }
302}