rudimentary XEP-0490 implementation
This commit is contained in:
parent
38e9533be4
commit
dd73b01ab1
|
@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -437,6 +438,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
|||
return null;
|
||||
}
|
||||
|
||||
public Message findReceivedWithRemoteId(final String id) {
|
||||
synchronized (this.messages) {
|
||||
for (final Message message : this.messages) {
|
||||
if (message.getStatus() == Message.STATUS_RECEIVED && id.equals(message.getRemoteMsgId())) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Message findMessageWithServerMsgId(String id) {
|
||||
synchronized (this.messages) {
|
||||
for (Message message : this.messages) {
|
||||
|
@ -576,20 +588,20 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
|||
}
|
||||
}
|
||||
|
||||
public List<Message> markRead(String upToUuid) {
|
||||
final List<Message> unread = new ArrayList<>();
|
||||
public List<Message> markRead(final String upToUuid) {
|
||||
final ImmutableList.Builder<Message> unread = new ImmutableList.Builder<>();
|
||||
synchronized (this.messages) {
|
||||
for (Message message : this.messages) {
|
||||
for (final Message message : this.messages) {
|
||||
if (!message.isRead()) {
|
||||
message.markRead();
|
||||
unread.add(message);
|
||||
}
|
||||
if (message.getUuid().equals(upToUuid)) {
|
||||
return unread;
|
||||
return unread.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return unread;
|
||||
return unread.build();
|
||||
}
|
||||
|
||||
public Message getLatestMessage() {
|
||||
|
|
|
@ -2,6 +2,15 @@ package eu.siacs.conversations.generator;
|
|||
|
||||
import android.util.Base64;
|
||||
|
||||
import eu.siacs.conversations.BuildConfig;
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -12,54 +21,42 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import eu.siacs.conversations.BuildConfig;
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.utils.PhoneHelper;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
|
||||
|
||||
public abstract class AbstractGenerator {
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
|
||||
private static final SimpleDateFormat DATE_FORMAT =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
|
||||
private final String[] FEATURES = {
|
||||
Namespace.JINGLE,
|
||||
Namespace.JINGLE_APPS_FILE_TRANSFER,
|
||||
Namespace.JINGLE_TRANSPORTS_S5B,
|
||||
Namespace.JINGLE_TRANSPORTS_IBB,
|
||||
Namespace.JINGLE_ENCRYPTED_TRANSPORT,
|
||||
Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO,
|
||||
"http://jabber.org/protocol/muc",
|
||||
"jabber:x:conference",
|
||||
Namespace.OOB,
|
||||
"http://jabber.org/protocol/caps",
|
||||
"http://jabber.org/protocol/disco#info",
|
||||
"urn:xmpp:avatar:metadata+notify",
|
||||
Namespace.NICK + "+notify",
|
||||
"urn:xmpp:ping",
|
||||
"jabber:iq:version",
|
||||
"http://jabber.org/protocol/chatstates"
|
||||
Namespace.JINGLE,
|
||||
Namespace.JINGLE_APPS_FILE_TRANSFER,
|
||||
Namespace.JINGLE_TRANSPORTS_S5B,
|
||||
Namespace.JINGLE_TRANSPORTS_IBB,
|
||||
Namespace.JINGLE_ENCRYPTED_TRANSPORT,
|
||||
Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO,
|
||||
"http://jabber.org/protocol/muc",
|
||||
"jabber:x:conference",
|
||||
Namespace.OOB,
|
||||
"http://jabber.org/protocol/caps",
|
||||
"http://jabber.org/protocol/disco#info",
|
||||
"urn:xmpp:avatar:metadata+notify",
|
||||
Namespace.NICK + "+notify",
|
||||
"urn:xmpp:ping",
|
||||
"jabber:iq:version",
|
||||
"http://jabber.org/protocol/chatstates",
|
||||
Namespace.MDS_DISPLAYED + "+notify"
|
||||
};
|
||||
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
|
||||
"urn:xmpp:chat-markers:0",
|
||||
"urn:xmpp:receipts"
|
||||
};
|
||||
private final String[] MESSAGE_CORRECTION_FEATURES = {
|
||||
"urn:xmpp:message-correct:0"
|
||||
"urn:xmpp:chat-markers:0", "urn:xmpp:receipts"
|
||||
};
|
||||
private final String[] MESSAGE_CORRECTION_FEATURES = {"urn:xmpp:message-correct:0"};
|
||||
private final String[] PRIVACY_SENSITIVE = {
|
||||
"urn:xmpp:time" //XEP-0202: Entity Time leaks time zone
|
||||
"urn:xmpp:time" // XEP-0202: Entity Time leaks time zone
|
||||
};
|
||||
private final String[] VOIP_NAMESPACES = {
|
||||
Namespace.JINGLE_TRANSPORT_ICE_UDP,
|
||||
Namespace.JINGLE_FEATURE_AUDIO,
|
||||
Namespace.JINGLE_FEATURE_VIDEO,
|
||||
Namespace.JINGLE_APPS_RTP,
|
||||
Namespace.JINGLE_APPS_DTLS,
|
||||
Namespace.JINGLE_MESSAGE
|
||||
Namespace.JINGLE_TRANSPORT_ICE_UDP,
|
||||
Namespace.JINGLE_FEATURE_AUDIO,
|
||||
Namespace.JINGLE_FEATURE_VIDEO,
|
||||
Namespace.JINGLE_APPS_RTP,
|
||||
Namespace.JINGLE_APPS_DTLS,
|
||||
Namespace.JINGLE_MESSAGE
|
||||
};
|
||||
protected XmppConnectionService mXmppConnectionService;
|
||||
|
||||
|
@ -90,7 +87,11 @@ public abstract class AbstractGenerator {
|
|||
|
||||
String getCapHash(final Account account) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("client/").append(getIdentityType()).append("//").append(getIdentityName()).append('<');
|
||||
s.append("client/")
|
||||
.append(getIdentityType())
|
||||
.append("//")
|
||||
.append(getIdentityName())
|
||||
.append('<');
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-1");
|
||||
|
|
|
@ -129,6 +129,10 @@ public class IqGenerator extends AbstractGenerator {
|
|||
return retrieve(Namespace.BOOKMARKS2, null);
|
||||
}
|
||||
|
||||
public IqPacket retrieveMds() {
|
||||
return retrieve(Namespace.MDS_DISPLAYED, null);
|
||||
}
|
||||
|
||||
public IqPacket publishNick(String nick) {
|
||||
final Element item = new Element("item");
|
||||
item.setAttribute("id", "current");
|
||||
|
@ -264,6 +268,24 @@ public class IqGenerator extends AbstractGenerator {
|
|||
return conference;
|
||||
}
|
||||
|
||||
public Element mdsDisplayed(final String stanzaId, final Conversation conversation) {
|
||||
final Jid by;
|
||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||
by = conversation.getJid().asBareJid();
|
||||
} else {
|
||||
by = conversation.getAccount().getJid().asBareJid();
|
||||
}
|
||||
return mdsDisplayed(stanzaId, by);
|
||||
}
|
||||
|
||||
private Element mdsDisplayed(final String stanzaId, final Jid by) {
|
||||
final Element displayed = new Element("displayed", Namespace.MDS_DISPLAYED);
|
||||
final Element stanzaIdElement = displayed.addChild("stanza-id", Namespace.STANZA_IDS);
|
||||
stanzaIdElement.setAttribute("id", stanzaId);
|
||||
stanzaIdElement.setAttribute("by", by);
|
||||
return displayed;
|
||||
}
|
||||
|
||||
public IqPacket publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
|
||||
final Set<PreKeyRecord> preKeyRecords, final int deviceId, Bundle publishOptions) {
|
||||
final Element item = new Element("item");
|
||||
|
|
|
@ -271,6 +271,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
}
|
||||
} else if (Namespace.MDS_DISPLAYED.equals(node) && account.getJid().asBareJid().equals(from)) {
|
||||
final Element item = items.findChild("item");
|
||||
mXmppConnectionService.processMdsItem(account, item);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + " received pubsub notification for node=" + node);
|
||||
}
|
||||
|
@ -985,12 +988,18 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
}
|
||||
}
|
||||
}
|
||||
Element displayed = packet.findChild("displayed", "urn:xmpp:chat-markers:0");
|
||||
final Element displayed = packet.findChild("displayed", "urn:xmpp:chat-markers:0");
|
||||
if (displayed != null) {
|
||||
final String id = displayed.getAttribute("id");
|
||||
final Jid sender = InvalidJid.getNullForInvalid(displayed.getAttributeAsJid("sender"));
|
||||
if (packet.fromAccount(account) && !selfAddressed) {
|
||||
dismissNotification(account, counterpart, query, id);
|
||||
final Conversation c =
|
||||
mXmppConnectionService.find(account, counterpart.asBareJid());
|
||||
final Message message =
|
||||
(c == null || id == null) ? null : c.findReceivedWithRemoteId(id);
|
||||
if (message != null && (query == null || query.isCatchup())) {
|
||||
mXmppConnectionService.markReadUpTo(c, message);
|
||||
}
|
||||
if (query == null) {
|
||||
activateGracePeriod(account);
|
||||
}
|
||||
|
@ -1012,7 +1021,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
final boolean trueJidMatchesAccount = account.getJid().asBareJid().equals(trueJid == null ? null : trueJid.asBareJid());
|
||||
if (trueJidMatchesAccount || conversation.getMucOptions().isSelf(counterpart)) {
|
||||
if (!message.isRead() && (query == null || query.isCatchup())) { //checking if message is unread fixes race conditions with reflections
|
||||
mXmppConnectionService.markRead(conversation);
|
||||
mXmppConnectionService.markReadUpTo(conversation, message);
|
||||
}
|
||||
} else if (!counterpart.isBareJid() && trueJid != null) {
|
||||
final ReadByMarker readByMarker = ReadByMarker.from(counterpart, trueJid);
|
||||
|
|
|
@ -49,6 +49,7 @@ import android.util.Pair;
|
|||
import androidx.annotation.BoolRes;
|
||||
import androidx.annotation.IntegerRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.util.Consumer;
|
||||
|
@ -56,6 +57,8 @@ import androidx.core.util.Consumer;
|
|||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.jxmpp.stringprep.libidn.LibIdnXmppStringprep;
|
||||
|
@ -152,6 +155,7 @@ import eu.siacs.conversations.utils.XmppUri;
|
|||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.LocalizedContent;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import eu.siacs.conversations.xmpp.InvalidJid;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
import eu.siacs.conversations.xmpp.OnBindListener;
|
||||
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
|
||||
|
@ -368,6 +372,12 @@ public class XmppConnectionService extends Service {
|
|||
} else if (!account.getXmppConnection().getFeatures().bookmarksConversion()) {
|
||||
fetchBookmarks(account);
|
||||
}
|
||||
|
||||
if (connection.getFeatures().mds()) {
|
||||
fetchMessageDisplayedSynchronization(account);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG,account.getJid()+": server has no support for mds");
|
||||
}
|
||||
final boolean flexible = account.getXmppConnection().getFeatures().flexibleOfflineMessageRetrieval();
|
||||
final boolean catchup = getMessageArchiveService().inCatchup(account);
|
||||
final boolean trackOfflineMessageRetrieval;
|
||||
|
@ -392,6 +402,7 @@ public class XmppConnectionService extends Service {
|
|||
unifiedPushBroker.renewUnifiedPushEndpointsOnBind(account);
|
||||
}
|
||||
};
|
||||
|
||||
private final AtomicLong mLastExpiryRun = new AtomicLong(0);
|
||||
private final LruCache<Pair<String, String>, ServiceDiscoveryResult> discoCache = new LruCache<>(20);
|
||||
private final OnStatusChanged statusListener = new OnStatusChanged() {
|
||||
|
@ -1902,18 +1913,88 @@ public class XmppConnectionService extends Service {
|
|||
|
||||
public void fetchBookmarks2(final Account account) {
|
||||
final IqPacket retrieve = mIqGenerator.retrieveBookmarks();
|
||||
sendIqPacket(account, retrieve, new OnIqPacketReceived() {
|
||||
@Override
|
||||
public void onIqPacketReceived(final Account account, final IqPacket response) {
|
||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||
final Element pubsub = response.findChild("pubsub", Namespace.PUBSUB);
|
||||
final Map<Jid, Bookmark> bookmarks = Bookmark.parseFromPubsub(pubsub, account);
|
||||
processBookmarksInitial(account, bookmarks, true);
|
||||
}
|
||||
sendIqPacket(account, retrieve, (a, response) -> {
|
||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||
final Element pubsub = response.findChild("pubsub", Namespace.PUBSUB);
|
||||
final Map<Jid, Bookmark> bookmarks = Bookmark.parseFromPubsub(pubsub, a);
|
||||
processBookmarksInitial(a, bookmarks, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchMessageDisplayedSynchronization(final Account account) {
|
||||
Log.d(Config.LOGTAG, account.getJid() + ": retrieve mds");
|
||||
final var retrieve = mIqGenerator.retrieveMds();
|
||||
sendIqPacket(
|
||||
account,
|
||||
retrieve,
|
||||
(a, response) -> {
|
||||
if (response.getType() != IqPacket.TYPE.RESULT) {
|
||||
return;
|
||||
}
|
||||
final var pubSub = response.findChild("pubsub", Namespace.PUBSUB);
|
||||
final Element items = pubSub == null ? null : pubSub.findChild("items");
|
||||
if (items == null
|
||||
|| !Namespace.MDS_DISPLAYED.equals(items.getAttribute("node"))) {
|
||||
return;
|
||||
}
|
||||
for (final Element child : items.getChildren()) {
|
||||
if ("item".equals(child.getName())) {
|
||||
processMdsItem(account, child);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void processMdsItem(final Account account, final Element item) {
|
||||
final Jid jid =
|
||||
item == null ? null : InvalidJid.getNullForInvalid(item.getAttributeAsJid("id"));
|
||||
if (jid == null) {
|
||||
return;
|
||||
}
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": processing mds item for " + jid);
|
||||
final Element displayed = item.findChild("displayed", Namespace.MDS_DISPLAYED);
|
||||
final Element stanzaId =
|
||||
displayed == null ? null : displayed.findChild("stanza-id", Namespace.STANZA_IDS);
|
||||
final String id = stanzaId == null ? null : stanzaId.getAttribute("id");
|
||||
final Conversation conversation = find(account, jid);
|
||||
if (id != null && conversation != null) {
|
||||
markReadUpToStanzaId(conversation, id);
|
||||
}
|
||||
}
|
||||
|
||||
public void markReadUpToStanzaId(final Conversation conversation, final String stanzaId) {
|
||||
final Message message = conversation.findMessageWithServerMsgId(stanzaId);
|
||||
if (message == null) { // do we want to check if isRead?
|
||||
return;
|
||||
}
|
||||
markReadUpTo(conversation, message);
|
||||
}
|
||||
|
||||
public void markReadUpTo(final Conversation conversation, final Message message) {
|
||||
final boolean isDismissNotification = isDismissNotification(message);
|
||||
final var uuid = message.getUuid();
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
conversation.getAccount().getJid().asBareJid()
|
||||
+ ": mark "
|
||||
+ conversation.getJid().asBareJid()
|
||||
+ " as read up to "
|
||||
+ uuid);
|
||||
markRead(conversation, uuid, isDismissNotification);
|
||||
}
|
||||
|
||||
private static boolean isDismissNotification(final Message message) {
|
||||
Message next = message.next();
|
||||
while (next != null) {
|
||||
if (message.getStatus() == Message.STATUS_RECEIVED) {
|
||||
return false;
|
||||
}
|
||||
next = next.next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void processBookmarksInitial(Account account, Map<Jid, Bookmark> bookmarks, final boolean pep) {
|
||||
final Set<Jid> previousBookmarks = account.getBookmarkedJids();
|
||||
final boolean synchronizeWithBookmarks = synchronizeWithBookmarks();
|
||||
|
@ -2050,7 +2131,7 @@ public class XmppConnectionService extends Service {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error publishing bookmarks (retry=" + retry + ") " + response);
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error publishing "+node+" (retry=" + retry + ") " + response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4534,24 +4615,101 @@ public class XmppConnectionService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
public void sendReadMarker(final Conversation conversation, String upToUuid) {
|
||||
final boolean isPrivateAndNonAnonymousMuc = conversation.getMode() == Conversation.MODE_MULTI && conversation.isPrivateAndNonAnonymous();
|
||||
public void sendReadMarker(final Conversation conversation, final String upToUuid) {
|
||||
final boolean isPrivateAndNonAnonymousMuc =
|
||||
conversation.getMode() == Conversation.MODE_MULTI
|
||||
&& conversation.isPrivateAndNonAnonymous();
|
||||
final List<Message> readMessages = this.markRead(conversation, upToUuid, true);
|
||||
if (readMessages.size() > 0) {
|
||||
updateConversationUi();
|
||||
if (readMessages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final Message markable = Conversation.getLatestMarkableMessage(readMessages, isPrivateAndNonAnonymousMuc);
|
||||
if (confirmMessages()
|
||||
&& markable != null
|
||||
&& (markable.trusted() || isPrivateAndNonAnonymousMuc)
|
||||
&& markable.getRemoteMsgId() != null) {
|
||||
Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": sending read marker to " + markable.getCounterpart().toString());
|
||||
final Account account = conversation.getAccount();
|
||||
final MessagePacket packet = mMessageGenerator.confirm(markable);
|
||||
final var account = conversation.getAccount();
|
||||
final var connection = account.getXmppConnection();
|
||||
updateConversationUi();
|
||||
final var last =
|
||||
Iterables.getLast(
|
||||
Collections2.filter(
|
||||
readMessages,
|
||||
m ->
|
||||
!m.isPrivateMessage()
|
||||
&& m.getStatus() == Message.STATUS_RECEIVED),
|
||||
null);
|
||||
if (last == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean sendDisplayedMarker =
|
||||
confirmMessages()
|
||||
&& (last.trusted() || isPrivateAndNonAnonymousMuc)
|
||||
&& last.getRemoteMsgId() != null
|
||||
&& (last.markable || isPrivateAndNonAnonymousMuc);
|
||||
final boolean serverAssist =
|
||||
connection != null && connection.getFeatures().mdsServerAssist();
|
||||
|
||||
final String stanzaId = last.getServerMsgId();
|
||||
|
||||
if (sendDisplayedMarker && serverAssist) {
|
||||
final var mdsDisplayed = mIqGenerator.mdsDisplayed(stanzaId, conversation);
|
||||
final MessagePacket packet = mMessageGenerator.confirm(last);
|
||||
packet.addChild(mdsDisplayed);
|
||||
if (!last.isPrivateMessage()) {
|
||||
packet.setTo(packet.getTo().asBareJid());
|
||||
}
|
||||
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": server assisted "+packet);
|
||||
this.sendMessagePacket(account, packet);
|
||||
} else {
|
||||
publishMds(last);
|
||||
// read markers will be sent after MDS to flush the CSI stanza queue
|
||||
if (sendDisplayedMarker) {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
conversation.getAccount().getJid().asBareJid()
|
||||
+ ": sending displayed marker to "
|
||||
+ last.getCounterpart().toString());
|
||||
final MessagePacket packet = mMessageGenerator.confirm(last);
|
||||
this.sendMessagePacket(account, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void publishMds(@Nullable final Message message) {
|
||||
final String stanzaId = message == null ? null : message.getServerMsgId();
|
||||
if (Strings.isNullOrEmpty(stanzaId)) {
|
||||
return;
|
||||
}
|
||||
final Conversation conversation;
|
||||
final var conversational = message.getConversation();
|
||||
if (conversational instanceof Conversation c) {
|
||||
conversation = c;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
final var account = conversation.getAccount();
|
||||
final var connection = account.getXmppConnection();
|
||||
if (connection == null || !connection.getFeatures().mds()) {
|
||||
return;
|
||||
}
|
||||
final Jid itemId;
|
||||
if (message.isPrivateMessage()) {
|
||||
itemId = message.getCounterpart();
|
||||
} else {
|
||||
itemId = conversation.getJid().asBareJid();
|
||||
}
|
||||
Log.d(Config.LOGTAG,"publishing mds for "+itemId+"/"+stanzaId);
|
||||
publishMds(account, itemId, stanzaId, conversation);
|
||||
}
|
||||
|
||||
private void publishMds(
|
||||
final Account account, final Jid itemId, final String stanzaId, final Conversation conversation) {
|
||||
final var item = mIqGenerator.mdsDisplayed(stanzaId, conversation);
|
||||
pushNodeAndEnforcePublishOptions(
|
||||
account,
|
||||
Namespace.MDS_DISPLAYED,
|
||||
item,
|
||||
itemId.toEscapedString(),
|
||||
PublishOptions.persistentWhitelistAccessMaxItems());
|
||||
}
|
||||
|
||||
public MemorizingTrustManager getMemorizingTrustManager() {
|
||||
return this.mMemorizingTrustManager;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ public final class Namespace {
|
|||
public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls";
|
||||
public static final String PUBSUB = "http://jabber.org/protocol/pubsub";
|
||||
public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB + "#publish-options";
|
||||
public static final String PUBSUB_CONFIG_NODE_MAX = PUBSUB + "#config-node-max";
|
||||
public static final String PUBSUB_ERROR = PUBSUB + "#errors";
|
||||
public static final String PUBSUB_OWNER = PUBSUB + "#owner";
|
||||
public static final String NICK = "http://jabber.org/protocol/nick";
|
||||
|
@ -76,4 +77,6 @@ public final class Namespace {
|
|||
public static final String REPORTING_REASON_SPAM = "urn:xmpp:reporting:spam";
|
||||
public static final String SDP_OFFER_ANSWER = "urn:ietf:rfc:3264";
|
||||
public static final String HASHES = "urn:xmpp:hashes:2";
|
||||
public static final String MDS_DISPLAYED = "urn:xmpp:mds:displayed:0";
|
||||
public static final String MDS_SERVER_ASSIST = "urn:xmpp:mds:server-assist:0";
|
||||
}
|
||||
|
|
|
@ -2968,6 +2968,10 @@ public class XmppConnection implements Runnable {
|
|||
return hasDiscoFeature(account.getJid().asBareJid(), Namespace.PUBSUB_PUBLISH_OPTIONS);
|
||||
}
|
||||
|
||||
public boolean pepConfigNodeMax() {
|
||||
return hasDiscoFeature(account.getJid().asBareJid(), Namespace.PUBSUB_CONFIG_NODE_MAX);
|
||||
}
|
||||
|
||||
public boolean pepOmemoWhitelisted() {
|
||||
return hasDiscoFeature(
|
||||
account.getJid().asBareJid(), AxolotlService.PEP_OMEMO_WHITELISTED);
|
||||
|
@ -3068,5 +3072,13 @@ public class XmppConnection implements Runnable {
|
|||
public boolean externalServiceDiscovery() {
|
||||
return hasDiscoFeature(account.getDomain(), Namespace.EXTERNAL_SERVICE_DISCOVERY);
|
||||
}
|
||||
|
||||
public boolean mds() {
|
||||
return pepPublishOptions() && pepConfigNodeMax();
|
||||
}
|
||||
|
||||
public boolean mdsServerAssist() {
|
||||
return hasDiscoFeature(account.getJid().asBareJid(), Namespace.MDS_DISPLAYED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ public class PublishOptions {
|
|||
options.putString("pubsub#access_model", "whitelist");
|
||||
options.putString("pubsub#send_last_published_item", "never");
|
||||
options.putString("pubsub#max_items", "max");
|
||||
|
||||
options.putString("pubsub#notify_delete", "true");
|
||||
options.putString("pubsub#notify_retract", "true"); //one could also set notify=true on the retract
|
||||
|
||||
|
|
Loading…
Reference in a new issue