store bookmarks in pep if conversion xep is running
This commit is contained in:
parent
46574d6e11
commit
dc5e7e5d95
|
@ -36,6 +36,7 @@ public abstract class AbstractGenerator {
|
||||||
"http://jabber.org/protocol/disco#info",
|
"http://jabber.org/protocol/disco#info",
|
||||||
"urn:xmpp:avatar:metadata+notify",
|
"urn:xmpp:avatar:metadata+notify",
|
||||||
"http://jabber.org/protocol/nick+notify",
|
"http://jabber.org/protocol/nick+notify",
|
||||||
|
Namespace.BOOKMARKS+"+notify",
|
||||||
"urn:xmpp:ping",
|
"urn:xmpp:ping",
|
||||||
"jabber:iq:version",
|
"jabber:iq:version",
|
||||||
"http://jabber.org/protocol/chatstates"
|
"http://jabber.org/protocol/chatstates"
|
||||||
|
@ -50,20 +51,17 @@ public abstract class AbstractGenerator {
|
||||||
private final String[] PRIVACY_SENSITIVE = {
|
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[] OTR = {
|
|
||||||
"urn:xmpp:otr:0"
|
|
||||||
};
|
|
||||||
private String mVersion = null;
|
private String mVersion = null;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
protected XmppConnectionService mXmppConnectionService;
|
protected XmppConnectionService mXmppConnectionService;
|
||||||
|
|
||||||
protected AbstractGenerator(XmppConnectionService service) {
|
AbstractGenerator(XmppConnectionService service) {
|
||||||
this.mXmppConnectionService = service;
|
this.mXmppConnectionService = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getIdentityVersion() {
|
String getIdentityVersion() {
|
||||||
if (mVersion == null) {
|
if (mVersion == null) {
|
||||||
this.mVersion = PhoneHelper.getVersionName(mXmppConnectionService);
|
this.mVersion = PhoneHelper.getVersionName(mXmppConnectionService);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.entities.Bookmark;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.DownloadableFile;
|
import eu.siacs.conversations.entities.DownloadableFile;
|
||||||
import eu.siacs.conversations.services.MessageArchiveService;
|
import eu.siacs.conversations.services.MessageArchiveService;
|
||||||
|
@ -138,6 +139,13 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
return publish("urn:xmpp:avatar:data", item);
|
return publish("urn:xmpp:avatar:data", item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IqPacket publishElement(final String namespace,final Element element, final Bundle options) {
|
||||||
|
final Element item = new Element("item");
|
||||||
|
item.setAttribute("id","current");
|
||||||
|
item.addChild(element);
|
||||||
|
return publish(namespace, item, options);
|
||||||
|
}
|
||||||
|
|
||||||
public IqPacket publishAvatarMetadata(final Avatar avatar) {
|
public IqPacket publishAvatarMetadata(final Avatar avatar) {
|
||||||
final Element item = new Element("item");
|
final Element item = new Element("item");
|
||||||
item.setAttribute("id", avatar.sha1sum);
|
item.setAttribute("id", avatar.sha1sum);
|
||||||
|
|
|
@ -212,6 +212,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
AxolotlService axolotlService = account.getAxolotlService();
|
AxolotlService axolotlService = account.getAxolotlService();
|
||||||
axolotlService.registerDevices(from, deviceIds);
|
axolotlService.registerDevices(from, deviceIds);
|
||||||
mXmppConnectionService.updateAccountUi();
|
mXmppConnectionService.updateAccountUi();
|
||||||
|
} else if (Namespace.BOOKMARKS.equals(node)) {
|
||||||
|
Log.d(Config.LOGTAG,"received bookmarks from "+from);
|
||||||
|
if (account.getJid().asBareJid().equals(from)) {
|
||||||
|
final Element i = items.findChild("item");
|
||||||
|
final Element storage = i == null ? null : i.findChild("storage", Namespace.BOOKMARKS);
|
||||||
|
mXmppConnectionService.processBookmarks(account,storage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +226,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
if (packet.getType() == MessagePacket.TYPE_ERROR) {
|
if (packet.getType() == MessagePacket.TYPE_ERROR) {
|
||||||
Jid from = packet.getFrom();
|
Jid from = packet.getFrom();
|
||||||
if (from != null) {
|
if (from != null) {
|
||||||
Message message = mXmppConnectionService.markMessage(account,
|
mXmppConnectionService.markMessage(account,
|
||||||
from.asBareJid(),
|
from.asBareJid(),
|
||||||
packet.getId(),
|
packet.getId(),
|
||||||
Message.STATUS_SEND_FAILED,
|
Message.STATUS_SEND_FAILED,
|
||||||
|
|
|
@ -139,6 +139,7 @@ import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||||
import eu.siacs.conversations.xmpp.mam.MamReference;
|
import eu.siacs.conversations.xmpp.mam.MamReference;
|
||||||
import eu.siacs.conversations.xmpp.pep.Avatar;
|
import eu.siacs.conversations.xmpp.pep.Avatar;
|
||||||
|
import eu.siacs.conversations.xmpp.pep.PublishOptions;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
||||||
|
@ -296,7 +297,9 @@ public class XmppConnectionService extends Service {
|
||||||
account.getRoster().clearPresences();
|
account.getRoster().clearPresences();
|
||||||
mJingleConnectionManager.cancelInTransmission();
|
mJingleConnectionManager.cancelInTransmission();
|
||||||
fetchRosterFromServer(account);
|
fetchRosterFromServer(account);
|
||||||
|
if (!account.getXmppConnection().getFeatures().bookmarksConversion()) {
|
||||||
fetchBookmarks(account);
|
fetchBookmarks(account);
|
||||||
|
}
|
||||||
final boolean flexible = account.getXmppConnection().getFeatures().flexibleOfflineMessageRetrieval();
|
final boolean flexible = account.getXmppConnection().getFeatures().flexibleOfflineMessageRetrieval();
|
||||||
final boolean catchup = getMessageArchiveService().inCatchup(account);
|
final boolean catchup = getMessageArchiveService().inCatchup(account);
|
||||||
if (flexible && catchup) {
|
if (flexible && catchup) {
|
||||||
|
@ -681,7 +684,7 @@ public class XmppConnectionService extends Service {
|
||||||
pingNow |= processAccountState(account,
|
pingNow |= processAccountState(account,
|
||||||
interactive,
|
interactive,
|
||||||
"ui".equals(action),
|
"ui".equals(action),
|
||||||
CryptoHelper.getAccountFingerprint(account,PhoneHelper.getAndroidId(this)).equals(pushedAccountHash),
|
CryptoHelper.getAccountFingerprint(account, PhoneHelper.getAndroidId(this)).equals(pushedAccountHash),
|
||||||
pingCandidates);
|
pingCandidates);
|
||||||
}
|
}
|
||||||
if (pingNow) {
|
if (pingNow) {
|
||||||
|
@ -978,7 +981,7 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||||
Log.d(Config.LOGTAG,"starting file observer");
|
Log.d(Config.LOGTAG, "starting file observer");
|
||||||
new Thread(fileObserver::startWatching).start();
|
new Thread(fileObserver::startWatching).start();
|
||||||
}
|
}
|
||||||
if (Config.supportOpenPgp()) {
|
if (Config.supportOpenPgp()) {
|
||||||
|
@ -1035,7 +1038,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restartFileObserver() {
|
public void restartFileObserver() {
|
||||||
Log.d(Config.LOGTAG,"restarting file observer");
|
Log.d(Config.LOGTAG, "restarting file observer");
|
||||||
new Thread(fileObserver::restartWatching).start();
|
new Thread(fileObserver::restartWatching).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,15 +1332,21 @@ public class XmppConnectionService extends Service {
|
||||||
public void fetchBookmarks(final Account account) {
|
public void fetchBookmarks(final Account account) {
|
||||||
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
||||||
final Element query = iqPacket.query("jabber:iq:private");
|
final Element query = iqPacket.query("jabber:iq:private");
|
||||||
query.addChild("storage", "storage:bookmarks");
|
query.addChild("storage", Namespace.BOOKMARKS);
|
||||||
final OnIqPacketReceived callback = new OnIqPacketReceived() {
|
final OnIqPacketReceived callback = (a, response) -> {
|
||||||
|
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
final Element query1 = response.query();
|
||||||
|
final Element storage = query1.findChild("storage", "storage:bookmarks");
|
||||||
|
processBookmarks(a, storage);
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": could not fetch bookmarks");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sendIqPacket(account, iqPacket, callback);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
public void processBookmarks(Account account, Element storage) {
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
|
||||||
final Element query = packet.query();
|
|
||||||
final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
|
final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
|
||||||
final Element storage = query.findChild("storage", "storage:bookmarks");
|
|
||||||
final boolean autojoin = respectAutojoin();
|
final boolean autojoin = respectAutojoin();
|
||||||
if (storage != null) {
|
if (storage != null) {
|
||||||
for (final Element item : storage.getChildren()) {
|
for (final Element item : storage.getChildren()) {
|
||||||
|
@ -1358,16 +1367,18 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account.setBookmarks(new CopyOnWriteArrayList<>(bookmarks.values()));
|
account.setBookmarks(new CopyOnWriteArrayList<>(bookmarks.values()));
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not fetch bookmarks");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sendIqPacket(account, iqPacket, callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushBookmarks(Account account) {
|
public void pushBookmarks(Account account) {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks");
|
if (account.getXmppConnection().getFeatures().bookmarksConversion()) {
|
||||||
|
pushBookmarksPep(account);
|
||||||
|
} else {
|
||||||
|
pushBookmarksPrivateXml(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushBookmarksPrivateXml(Account account) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks via private xml");
|
||||||
IqPacket iqPacket = new IqPacket(IqPacket.TYPE.SET);
|
IqPacket iqPacket = new IqPacket(IqPacket.TYPE.SET);
|
||||||
Element query = iqPacket.query("jabber:iq:private");
|
Element query = iqPacket.query("jabber:iq:private");
|
||||||
Element storage = query.addChild("storage", "storage:bookmarks");
|
Element storage = query.addChild("storage", "storage:bookmarks");
|
||||||
|
@ -1377,6 +1388,49 @@ public class XmppConnectionService extends Service {
|
||||||
sendIqPacket(account, iqPacket, mDefaultIqHandler);
|
sendIqPacket(account, iqPacket, mDefaultIqHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pushBookmarksPep(Account account) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks via pep");
|
||||||
|
Element storage = new Element("storage", "storage:bookmarks");
|
||||||
|
for (Bookmark bookmark : account.getBookmarks()) {
|
||||||
|
storage.addChild(bookmark);
|
||||||
|
}
|
||||||
|
pushNodeAndEnforcePublishOptions(account,Namespace.BOOKMARKS,storage, PublishOptions.persistentWhitelistAccess());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void pushNodeAndEnforcePublishOptions(final Account account, final String node, final Element element, final Bundle options) {
|
||||||
|
pushNodeAndEnforcePublishOptions(account, node, element, options, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushNodeAndEnforcePublishOptions(final Account account, final String node, final Element element, final Bundle options, final boolean retry) {
|
||||||
|
IqPacket packet = mIqGenerator.publishElement(node, element, options);
|
||||||
|
Log.d(Config.LOGTAG,packet.toString());
|
||||||
|
sendIqPacket(account, packet, (a, response) -> {
|
||||||
|
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Element error = response.getType() == IqPacket.TYPE.ERROR ? response.findChild("error") : null;
|
||||||
|
final boolean preconditionNotMet = error != null && error.hasChild("precondition-not-met", Namespace.PUBSUB_ERROR);
|
||||||
|
if (retry && preconditionNotMet) {
|
||||||
|
pushNodeConfiguration(account, node, options, new OnConfigurationPushed() {
|
||||||
|
@Override
|
||||||
|
public void onPushSucceeded() {
|
||||||
|
pushNodeAndEnforcePublishOptions(account, node, element, options, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPushFailed() {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": unable to push node configuration ("+node+")");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": error publishing bookmarks (retry="+Boolean.toString(retry)+") "+response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void restoreFromDatabase() {
|
private void restoreFromDatabase() {
|
||||||
synchronized (this.conversations) {
|
synchronized (this.conversations) {
|
||||||
final Map<String, Account> accountLookupTable = new Hashtable<>();
|
final Map<String, Account> accountLookupTable = new Hashtable<>();
|
||||||
|
@ -2553,6 +2607,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushNodeConfiguration(Account account, final Jid jid, final String node, final Bundle options, final OnConfigurationPushed callback) {
|
public void pushNodeConfiguration(Account account, final Jid jid, final String node, final Bundle options, final OnConfigurationPushed callback) {
|
||||||
|
Log.d(Config.LOGTAG,"pushing node configuration");
|
||||||
sendIqPacket(account, mIqGenerator.requestPubsubConfiguration(jid, node), new OnIqPacketReceived() {
|
sendIqPacket(account, mIqGenerator.requestPubsubConfiguration(jid, node), new OnIqPacketReceived() {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
|
|
@ -20,4 +20,6 @@ public final class Namespace {
|
||||||
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline";
|
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline";
|
||||||
public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind";
|
public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind";
|
||||||
public static final String P1_S3_FILE_TRANSFER = "p1:s3filetransfer";
|
public static final String P1_S3_FILE_TRANSFER = "p1:s3filetransfer";
|
||||||
|
public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0";
|
||||||
|
public static final String BOOKMARKS = "storage:bookmarks";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1754,6 +1754,10 @@ public class XmppConnection implements Runnable {
|
||||||
return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:carbons:2");
|
return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:carbons:2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean bookmarksConversion() {
|
||||||
|
return hasDiscoFeature(account.getJid().asBareJid(),Namespace.BOOKMARKS_CONVERSION) && pepPublishOptions();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean blocking() {
|
public boolean blocking() {
|
||||||
return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING);
|
return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,11 @@ public class PublishOptions {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bundle persistentWhitelistAccess() {
|
||||||
|
final Bundle options = new Bundle();
|
||||||
|
options.putString("pubsub#persist_items","true");
|
||||||
|
options.putString("pubsub#access_model","whitelist");
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue