1package eu.siacs.conversations.xmpp.manager;
2
3import android.util.Log;
4import androidx.annotation.NonNull;
5import com.google.common.collect.ImmutableMap;
6import com.google.common.util.concurrent.FutureCallback;
7import com.google.common.util.concurrent.Futures;
8import com.google.common.util.concurrent.ListenableFuture;
9import com.google.common.util.concurrent.MoreExecutors;
10import eu.siacs.conversations.Config;
11import eu.siacs.conversations.entities.Bookmark;
12import eu.siacs.conversations.services.XmppConnectionService;
13import eu.siacs.conversations.xml.Namespace;
14import eu.siacs.conversations.xmpp.Jid;
15import eu.siacs.conversations.xmpp.XmppConnection;
16import im.conversations.android.xmpp.NodeConfiguration;
17import im.conversations.android.xmpp.model.bookmark2.Conference;
18import im.conversations.android.xmpp.model.bookmark2.Nick;
19import im.conversations.android.xmpp.model.pubsub.Items;
20import im.conversations.android.xmpp.model.pubsub.event.Retract;
21import java.util.Collection;
22import java.util.Collections;
23import java.util.Map;
24
25public class BookmarkManager extends AbstractBookmarkManager {
26
27 public BookmarkManager(final XmppConnectionService service, XmppConnection connection) {
28 super(service, connection);
29 }
30
31 public void fetch() {
32 final var future = getManager(PepManager.class).fetchItems(Conference.class);
33 Futures.addCallback(
34 future,
35 new FutureCallback<>() {
36 @Override
37 public void onSuccess(final Map<String, Conference> bookmarks) {
38 final var builder = new ImmutableMap.Builder<Jid, Bookmark>();
39 for (final var entry : bookmarks.entrySet()) {
40 final Bookmark bookmark =
41 Bookmark.parseFromItem(
42 entry.getKey(), entry.getValue(), getAccount());
43 if (bookmark == null) {
44 continue;
45 }
46 builder.put(bookmark.getJid(), bookmark);
47 }
48 processBookmarksInitial(builder.buildKeepingLast(), true);
49 }
50
51 @Override
52 public void onFailure(@NonNull final Throwable throwable) {
53 Log.d(Config.LOGTAG, "Could not fetch bookmarks", throwable);
54 }
55 },
56 MoreExecutors.directExecutor());
57 }
58
59 public void handleItems(final Items items) {
60 this.handleItems(items.getItemMap(Conference.class));
61 this.handleRetractions(items.getRetractions());
62 }
63
64 private void handleRetractions(final Collection<Retract> retractions) {
65 final var account = getAccount();
66 for (final var retract : retractions) {
67 final Jid id = Jid.Invalid.getNullForInvalid(retract.getAttributeAsJid("id"));
68 if (id != null) {
69 account.removeBookmark(id);
70 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted bookmark for " + id);
71 processDeletedBookmark(id);
72 service.updateConversationUi();
73 }
74 }
75 }
76
77 private void handleItems(final Map<String, Conference> items) {
78 final var account = getAccount();
79 for (final var item : items.entrySet()) {
80 // TODO parseFromItem can be included in this Manager
81 final Bookmark bookmark =
82 Bookmark.parseFromItem(item.getKey(), item.getValue(), account);
83 if (bookmark == null) {
84 continue;
85 }
86 account.putBookmark(bookmark);
87 service.processModifiedBookmark(bookmark);
88 service.updateConversationUi();
89 }
90 }
91
92 public ListenableFuture<Void> publishBookmark(final Jid address, final boolean autoJoin) {
93 return publishBookmark(address, autoJoin, null);
94 }
95
96 public ListenableFuture<Void> publishBookmark(
97 final Jid address, final boolean autoJoin, final String nick) {
98 final var itemId = address.toString();
99 final var conference = new Conference();
100 conference.setAutoJoin(autoJoin);
101 if (nick != null) {
102 conference.addExtension(new Nick()).setContent(nick);
103 }
104 return Futures.transform(
105 getManager(PepManager.class)
106 .publish(conference, itemId, NodeConfiguration.WHITELIST_MAX_ITEMS),
107 result -> null,
108 MoreExecutors.directExecutor());
109 }
110
111 public ListenableFuture<Void> retractBookmark(final Jid address) {
112 final var itemId = address.toString();
113 return Futures.transform(
114 getManager(PepManager.class).retract(itemId, Namespace.BOOKMARKS2),
115 result -> null,
116 MoreExecutors.directExecutor());
117 }
118
119 private void deleteAllItems() {
120 final var account = getAccount();
121 final var previous = account.getBookmarkedJids();
122 account.setBookmarks(Collections.emptyMap());
123 processDeletedBookmarks(previous);
124 }
125
126 public void handleDelete() {
127 Log.d(Config.LOGTAG, getAccount().getJid().asBareJid() + ": deleted bookmarks node");
128 this.deleteAllItems();
129 }
130
131 public void handlePurge() {
132 Log.d(Config.LOGTAG, getAccount().getJid().asBareJid() + ": purged bookmarks");
133 this.deleteAllItems();
134 }
135}