1package eu.siacs.conversations.xmpp.manager;
2
3import android.text.TextUtils;
4import android.util.Log;
5import androidx.annotation.NonNull;
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.Account;
12import eu.siacs.conversations.entities.Bookmark;
13import eu.siacs.conversations.entities.Conversation;
14import eu.siacs.conversations.entities.MucOptions;
15import eu.siacs.conversations.services.XmppConnectionService;
16import eu.siacs.conversations.xmpp.XmppConnection;
17
18public class BookmarkManager extends AbstractManager {
19
20 private final XmppConnectionService service;
21
22 public BookmarkManager(final XmppConnectionService service, final XmppConnection connection) {
23 super(service, connection);
24 this.service = service;
25 }
26
27 public void request() {
28 if (getManager(NativeBookmarkManager.class).hasFeature()) {
29 getManager(NativeBookmarkManager.class).fetch();
30 } else if (getManager(LegacyBookmarkManager.class).hasConversion()) {
31 final var account = getAccount();
32 Log.d(
33 Config.LOGTAG,
34 account.getJid() + ": not fetching bookmarks. waiting for server to push");
35 } else {
36 getManager(PrivateStorageManager.class).fetchBookmarks();
37 }
38 }
39
40 public void save(final Conversation conversation, final String name) {
41 final Account account = conversation.getAccount();
42 final Bookmark bookmark = new Bookmark(account, conversation.getJid().asBareJid());
43 final String nick = conversation.getJid().getResource();
44 if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
45 bookmark.setNick(nick);
46 }
47 if (!TextUtils.isEmpty(name)) {
48 bookmark.setBookmarkName(name);
49 }
50 bookmark.setAutojoin(true);
51 this.create(bookmark);
52 bookmark.setConversation(conversation);
53 }
54
55 public void create(final Bookmark bookmark) {
56 final var account = getAccount();
57 account.putBookmark(bookmark);
58 final ListenableFuture<Void> future;
59 if (getManager(NativeBookmarkManager.class).hasFeature()) {
60 future = getManager(NativeBookmarkManager.class).publish(bookmark);
61 } else if (getManager(LegacyBookmarkManager.class).hasConversion()) {
62 future = getManager(LegacyBookmarkManager.class).publish(account.getBookmarks());
63 } else {
64 future =
65 getManager(PrivateStorageManager.class)
66 .publishBookmarks(account.getBookmarks());
67 }
68 Futures.addCallback(
69 future,
70 new FutureCallback<>() {
71 @Override
72 public void onSuccess(Void result) {
73 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": created bookmark");
74 }
75
76 @Override
77 public void onFailure(@NonNull Throwable t) {
78 Log.d(
79 Config.LOGTAG,
80 account.getJid().asBareJid() + ": could not create bookmark",
81 t);
82 }
83 },
84 MoreExecutors.directExecutor());
85 }
86
87 public void delete(final Bookmark bookmark) {
88 final var account = getAccount();
89 account.removeBookmark(bookmark);
90 final ListenableFuture<Void> future;
91 if (getManager(NativeBookmarkManager.class).hasFeature()) {
92 future = getManager(NativeBookmarkManager.class).retract(bookmark.getJid().asBareJid());
93 } else if (getManager(LegacyBookmarkManager.class).hasConversion()) {
94 future = getManager(LegacyBookmarkManager.class).publish(account.getBookmarks());
95 } else {
96 future =
97 getManager(PrivateStorageManager.class)
98 .publishBookmarks(account.getBookmarks());
99 }
100 Futures.addCallback(
101 future,
102 new FutureCallback<>() {
103 @Override
104 public void onSuccess(Void result) {
105 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted bookmark");
106 }
107
108 @Override
109 public void onFailure(@NonNull Throwable t) {
110 Log.d(
111 Config.LOGTAG,
112 account.getJid().asBareJid() + ": could not delete bookmark",
113 t);
114 }
115 },
116 MoreExecutors.directExecutor());
117 }
118
119 public void ensureBookmarkIsAutoJoin(final Conversation conversation) {
120 final var account = getAccount();
121 final var existingBookmark = conversation.getBookmark();
122 if (existingBookmark == null) {
123 final var bookmark = new Bookmark(account, conversation.getJid().asBareJid());
124 bookmark.setAutojoin(true);
125 create(bookmark);
126 } else {
127 if (existingBookmark.autojoin()) {
128 return;
129 }
130 existingBookmark.setAutojoin(true);
131 create(existingBookmark);
132 }
133 }
134
135 public void processModifiedBookmark(final Bookmark bookmark, final boolean pep) {
136 final var existing = this.service.find(bookmark);
137 if (existing != null) {
138 if (existing.getMode() != Conversation.MODE_MULTI) {
139 return;
140 }
141 bookmark.setConversation(existing);
142 if (pep && !bookmark.autojoin()) {
143 Log.d(
144 Config.LOGTAG,
145 getAccount().getJid().asBareJid()
146 + ": archiving conference ("
147 + existing.getJid()
148 + ") after receiving pep");
149 service.archiveConversation(existing, false);
150 } else {
151 final MucOptions mucOptions = existing.getMucOptions();
152 if (mucOptions.getError() == MucOptions.Error.NICK_IN_USE) {
153 final String current = mucOptions.getActualNick();
154 final String proposed = mucOptions.getProposedNickPure();
155 if (current != null && !current.equals(proposed)) {
156 Log.d(
157 Config.LOGTAG,
158 getAccount().getJid().asBareJid()
159 + ": proposed nick changed after bookmark push "
160 + current
161 + "->"
162 + proposed);
163 getManager(MultiUserChatManager.class).join(existing);
164 }
165 } else {
166 getManager(MultiUserChatManager.class).checkMucRequiresRename(existing);
167 }
168 }
169 } else if (bookmark.autojoin()) {
170 final var fresh =
171 this.service.findOrCreateConversation(
172 getAccount(), bookmark.getFullJid(), true, true, false);
173 bookmark.setConversation(fresh);
174 }
175 }
176}