Bookmark.java

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