fetch roster. process result
This commit is contained in:
parent
9e7bbcc272
commit
6b232f7a5a
|
@ -1,6 +1,7 @@
|
||||||
package eu.siacs.conversations.xml;
|
package eu.siacs.conversations.xml;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
@ -177,15 +178,15 @@ public class Element {
|
||||||
|
|
||||||
public Jid getAttributeAsJid(String name) {
|
public Jid getAttributeAsJid(String name) {
|
||||||
final String jid = this.getAttribute(name);
|
final String jid = this.getAttribute(name);
|
||||||
if (jid != null && !jid.isEmpty()) {
|
if (Strings.isNullOrEmpty(jid)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return Jid.ofEscaped(jid);
|
return Jid.ofEscaped(jid);
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
return InvalidJid.of(jid, this instanceof MessagePacket);
|
return InvalidJid.of(jid, this instanceof MessagePacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Hashtable<String, String> getAttributes() {
|
public Hashtable<String, String> getAttributes() {
|
||||||
return this.attributes;
|
return this.attributes;
|
||||||
|
@ -215,6 +216,7 @@ public class Element {
|
||||||
return elementOutput.toString();
|
return elementOutput.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO should ultimately be removed once everything is an extension
|
||||||
public final String getName() {
|
public final String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.room.TypeConverters;
|
||||||
import im.conversations.android.database.dao.AccountDao;
|
import im.conversations.android.database.dao.AccountDao;
|
||||||
import im.conversations.android.database.dao.MessageDao;
|
import im.conversations.android.database.dao.MessageDao;
|
||||||
import im.conversations.android.database.dao.PresenceDao;
|
import im.conversations.android.database.dao.PresenceDao;
|
||||||
|
import im.conversations.android.database.dao.RosterDao;
|
||||||
import im.conversations.android.database.entity.AccountEntity;
|
import im.conversations.android.database.entity.AccountEntity;
|
||||||
import im.conversations.android.database.entity.BlockedItemEntity;
|
import im.conversations.android.database.entity.BlockedItemEntity;
|
||||||
import im.conversations.android.database.entity.ChatEntity;
|
import im.conversations.android.database.entity.ChatEntity;
|
||||||
|
@ -71,4 +72,6 @@ public abstract class ConversationsDatabase extends RoomDatabase {
|
||||||
public abstract PresenceDao presenceDao();
|
public abstract PresenceDao presenceDao();
|
||||||
|
|
||||||
public abstract MessageDao messageDao();
|
public abstract MessageDao messageDao();
|
||||||
|
|
||||||
|
public abstract RosterDao rosterDao();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package im.conversations.android.database.dao;
|
||||||
|
|
||||||
|
import androidx.room.Dao;
|
||||||
|
import androidx.room.Insert;
|
||||||
|
import androidx.room.Query;
|
||||||
|
import androidx.room.Transaction;
|
||||||
|
import im.conversations.android.database.entity.RosterItemEntity;
|
||||||
|
import im.conversations.android.database.model.Account;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
public abstract class RosterDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
protected abstract void insert(Collection<RosterItemEntity> rosterItems);
|
||||||
|
|
||||||
|
@Query("DELETE FROM roster WHERE accountId=:account")
|
||||||
|
protected abstract void clear(final long account);
|
||||||
|
|
||||||
|
@Query("UPDATE account SET rosterVersion=:version WHERE id=:account")
|
||||||
|
protected abstract void setRosterVersion(final long account, final String version);
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void setRoster(
|
||||||
|
final Account account,
|
||||||
|
final String version,
|
||||||
|
final Collection<RosterItemEntity> rosterItems) {
|
||||||
|
clear(account.id);
|
||||||
|
insert(rosterItems);
|
||||||
|
setRosterVersion(account.id, version);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,10 @@ import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
import im.conversations.android.database.model.Subscription;
|
import com.google.common.collect.Collections2;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "roster",
|
tableName = "roster",
|
||||||
|
@ -27,11 +30,26 @@ public class RosterItemEntity {
|
||||||
|
|
||||||
@NonNull public Long accountId;
|
@NonNull public Long accountId;
|
||||||
|
|
||||||
@NonNull public String address;
|
@NonNull public Jid address;
|
||||||
|
|
||||||
public Subscription subscription;
|
public Item.Subscription subscription;
|
||||||
|
|
||||||
public boolean ask;
|
public boolean isPendingOut;
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
|
public static RosterItemEntity of(final long accountId, final Item item) {
|
||||||
|
final var entity = new RosterItemEntity();
|
||||||
|
entity.accountId = accountId;
|
||||||
|
entity.address = item.getJid();
|
||||||
|
entity.subscription = item.getSubscription();
|
||||||
|
entity.isPendingOut = item.isPendingOut();
|
||||||
|
entity.name = item.getItemName();
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<RosterItemEntity> of(
|
||||||
|
final long accountId, final Collection<Item> items) {
|
||||||
|
return Collections2.transform(items, i -> of(accountId, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package im.conversations.android.database.model;
|
|
||||||
|
|
||||||
public enum Subscription {
|
|
||||||
NONE,
|
|
||||||
TO,
|
|
||||||
FROM,
|
|
||||||
BOTH
|
|
||||||
}
|
|
|
@ -1,13 +1,49 @@
|
||||||
package im.conversations.android.xmpp.model.roster;
|
package im.conversations.android.xmpp.model.roster;
|
||||||
|
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import im.conversations.android.annotation.XmlElement;
|
import im.conversations.android.annotation.XmlElement;
|
||||||
import im.conversations.android.xmpp.model.Extension;
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
@XmlElement
|
@XmlElement
|
||||||
public class Item extends Extension {
|
public class Item extends Extension {
|
||||||
|
|
||||||
|
public static final List<Subscription> RESULT_SUBSCRIPTIONS =
|
||||||
|
Arrays.asList(Subscription.NONE, Subscription.TO, Subscription.FROM, Subscription.BOTH);
|
||||||
|
|
||||||
public Item() {
|
public Item() {
|
||||||
super("item", Namespace.ROSTER);
|
super("item", Namespace.ROSTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
return getAttributeAsJid("jid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getItemName() {
|
||||||
|
return this.getAttribute("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPendingOut() {
|
||||||
|
return "subscribe".equalsIgnoreCase(this.getAttribute("ask"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Subscription getSubscription() {
|
||||||
|
final String value = this.getAttribute("subscription");
|
||||||
|
try {
|
||||||
|
return value == null ? null : Subscription.valueOf(value.toLowerCase(Locale.ROOT));
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Subscription {
|
||||||
|
NONE,
|
||||||
|
TO,
|
||||||
|
FROM,
|
||||||
|
BOTH,
|
||||||
|
REMOVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,8 @@ public class Query extends Extension {
|
||||||
public void setVersion(final String rosterVersion) {
|
public void setVersion(final String rosterVersion) {
|
||||||
this.setAttribute("ver", rosterVersion);
|
this.setAttribute("ver", rosterVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return this.getAttribute("ver");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@ package im.conversations.android.xmpp.processor;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
|
import im.conversations.android.database.entity.RosterItemEntity;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.roster.Item;
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
import im.conversations.android.xmpp.model.roster.Query;
|
import im.conversations.android.xmpp.model.roster.Query;
|
||||||
|
@ -52,9 +54,10 @@ public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid
|
||||||
Log.d(Config.LOGTAG, account.address + ": fetching roster version " + rosterVersion);
|
Log.d(Config.LOGTAG, account.address + ": fetching roster version " + rosterVersion);
|
||||||
rosterQuery.setVersion(rosterVersion);
|
rosterQuery.setVersion(rosterVersion);
|
||||||
}
|
}
|
||||||
connection.sendIqPacket(
|
connection.sendIqPacket(iqPacket, this::handleFetchRosterResult);
|
||||||
iqPacket,
|
}
|
||||||
result -> {
|
|
||||||
|
private void handleFetchRosterResult(final IqPacket result) {
|
||||||
if (result.getType() != IqPacket.TYPE.RESULT) {
|
if (result.getType() != IqPacket.TYPE.RESULT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -63,8 +66,17 @@ public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid
|
||||||
// No query in result means further modifications are sent via pushes
|
// No query in result means further modifications are sent via pushes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO delete entire roster
|
final var account = getAccount();
|
||||||
for (final Item item : query.getExtensions(Item.class)) {}
|
final var database = getDatabase();
|
||||||
});
|
final var version = query.getVersion();
|
||||||
|
final var items = query.getExtensions(Item.class);
|
||||||
|
// In a roster result (Section 2.1.4), the client MUST ignore values of the c'subscription'
|
||||||
|
// attribute other than "none", "to", "from", or "both".
|
||||||
|
final var validItems =
|
||||||
|
Collections2.filter(
|
||||||
|
items,
|
||||||
|
i -> i != null && Item.RESULT_SUBSCRIPTIONS.contains(i.getSubscription()));
|
||||||
|
final var entities = RosterItemEntity.of(account.id, validItems);
|
||||||
|
database.rosterDao().setRoster(account, version, entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue