parse more presence metadata
This commit is contained in:
parent
2e5e2ff6fe
commit
8be8d7df8f
|
@ -10,6 +10,7 @@ import im.conversations.android.database.entity.PresenceEntity;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
import im.conversations.android.database.model.PresenceShow;
|
import im.conversations.android.database.model.PresenceShow;
|
||||||
import im.conversations.android.database.model.PresenceType;
|
import im.conversations.android.database.model.PresenceType;
|
||||||
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.parts.Resourcepart;
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
@ -37,7 +38,10 @@ public abstract class PresenceDao {
|
||||||
@NonNull final Resourcepart resource,
|
@NonNull final Resourcepart resource,
|
||||||
@Nullable final PresenceType type,
|
@Nullable final PresenceType type,
|
||||||
@Nullable final PresenceShow show,
|
@Nullable final PresenceShow show,
|
||||||
@Nullable final String status) {
|
@Nullable final String status,
|
||||||
|
@Nullable final String vCardPhoto,
|
||||||
|
@Nullable final String occupantId,
|
||||||
|
@Nullable final MultiUserChat multiUserChat) {
|
||||||
if (resource.equals(Resourcepart.EMPTY)
|
if (resource.equals(Resourcepart.EMPTY)
|
||||||
&& Arrays.asList(PresenceType.ERROR, PresenceType.UNAVAILABLE).contains(type)) {
|
&& Arrays.asList(PresenceType.ERROR, PresenceType.UNAVAILABLE).contains(type)) {
|
||||||
deletePresences(account.id, address);
|
deletePresences(account.id, address);
|
||||||
|
@ -49,7 +53,17 @@ public abstract class PresenceDao {
|
||||||
// unavailable presence only delete previous nothing left to do
|
// unavailable presence only delete previous nothing left to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var entity = PresenceEntity.of(account.id, address, resource, type, show, status);
|
final var entity =
|
||||||
|
PresenceEntity.of(
|
||||||
|
account.id,
|
||||||
|
address,
|
||||||
|
resource,
|
||||||
|
type,
|
||||||
|
show,
|
||||||
|
status,
|
||||||
|
vCardPhoto,
|
||||||
|
occupantId,
|
||||||
|
multiUserChat);
|
||||||
insert(entity);
|
insert(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import im.conversations.android.database.model.PresenceShow;
|
||||||
import im.conversations.android.database.model.PresenceType;
|
import im.conversations.android.database.model.PresenceType;
|
||||||
import im.conversations.android.xmpp.model.muc.Affiliation;
|
import im.conversations.android.xmpp.model.muc.Affiliation;
|
||||||
import im.conversations.android.xmpp.model.muc.Role;
|
import im.conversations.android.xmpp.model.muc.Role;
|
||||||
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
import org.jxmpp.jid.parts.Resourcepart;
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
@ -70,9 +71,13 @@ public class PresenceEntity {
|
||||||
long account,
|
long account,
|
||||||
@NonNull BareJid address,
|
@NonNull BareJid address,
|
||||||
@NonNull Resourcepart resource,
|
@NonNull Resourcepart resource,
|
||||||
PresenceType type,
|
final PresenceType type,
|
||||||
PresenceShow show,
|
final PresenceShow show,
|
||||||
String status) {
|
final String status,
|
||||||
|
final String vCardPhoto,
|
||||||
|
final String occupantId,
|
||||||
|
final MultiUserChat multiUserChat) {
|
||||||
|
final var mucItem = multiUserChat == null ? null : multiUserChat.getItem();
|
||||||
final var entity = new PresenceEntity();
|
final var entity = new PresenceEntity();
|
||||||
entity.accountId = account;
|
entity.accountId = account;
|
||||||
entity.address = address;
|
entity.address = address;
|
||||||
|
@ -80,6 +85,14 @@ public class PresenceEntity {
|
||||||
entity.type = type;
|
entity.type = type;
|
||||||
entity.show = show;
|
entity.show = show;
|
||||||
entity.status = status;
|
entity.status = status;
|
||||||
|
entity.vCardPhoto = vCardPhoto;
|
||||||
|
if (mucItem != null) {
|
||||||
|
entity.occupantId = occupantId;
|
||||||
|
entity.mucUserAffiliation = mucItem.getAffiliation();
|
||||||
|
entity.mucUserRole = mucItem.getRole();
|
||||||
|
entity.mucUserJid = mucItem.getJid();
|
||||||
|
entity.mucUserSelf = multiUserChat.getStatus().contains(110);
|
||||||
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ public class Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ServiceRecord> resolveNoSrvRecords(DNSName dnsName, boolean includeCName) {
|
private static List<ServiceRecord> resolveNoSrvRecords(DNSName dnsName, boolean includeCName) {
|
||||||
List<ServiceRecord> results = new ArrayList<>();
|
var results = new ImmutableList.Builder<ServiceRecord>();
|
||||||
try {
|
try {
|
||||||
for (A a : resolveWithFallback(dnsName, A.class, false).getAnswersOrEmptySet()) {
|
for (A a : resolveWithFallback(dnsName, A.class, false).getAnswersOrEmptySet()) {
|
||||||
results.add(ServiceRecord.createDefault(dnsName, a.getInetAddress()));
|
results.add(ServiceRecord.createDefault(dnsName, a.getInetAddress()));
|
||||||
|
@ -238,17 +238,17 @@ public class Resolver {
|
||||||
resolveWithFallback(dnsName, AAAA.class, false).getAnswersOrEmptySet()) {
|
resolveWithFallback(dnsName, AAAA.class, false).getAnswersOrEmptySet()) {
|
||||||
results.add(ServiceRecord.createDefault(dnsName, aaaa.getInetAddress()));
|
results.add(ServiceRecord.createDefault(dnsName, aaaa.getInetAddress()));
|
||||||
}
|
}
|
||||||
if (results.size() == 0 && includeCName) {
|
if (results.build().isEmpty() && includeCName) {
|
||||||
for (CNAME cname :
|
for (CNAME cname :
|
||||||
resolveWithFallback(dnsName, CNAME.class, false).getAnswersOrEmptySet()) {
|
resolveWithFallback(dnsName, CNAME.class, false).getAnswersOrEmptySet()) {
|
||||||
results.addAll(resolveNoSrvRecords(cname.name, false));
|
results.addAll(resolveNoSrvRecords(cname.name, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
LOGGER.info("Error resolving fallback records", throwable);
|
LOGGER.info("Error resolving fallback records", throwable);
|
||||||
}
|
}
|
||||||
results.add(ServiceRecord.createDefault(dnsName));
|
results.add(ServiceRecord.createDefault(dnsName));
|
||||||
return results;
|
return results.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResolverResult<SRV> resolveWithFallback(
|
private static ResolverResult<SRV> resolveWithFallback(
|
||||||
|
|
|
@ -99,5 +99,7 @@ public final class Namespace {
|
||||||
public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0";
|
public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0";
|
||||||
public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls";
|
public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls";
|
||||||
public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push";
|
public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push";
|
||||||
|
public static final String VCARD_TEMP = "vcard-temp";
|
||||||
|
public static final String VCARD_TEMP_UPDATE = "vcard-temp:x:update";
|
||||||
public static final String VERSION = "jabber:iq:version";
|
public static final String VERSION = "jabber:iq:version";
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
import im.conversations.android.xmpp.manager.ExternalDiscoManager;
|
import im.conversations.android.xmpp.manager.ExternalDiscoManager;
|
||||||
import im.conversations.android.xmpp.manager.HttpUploadManager;
|
import im.conversations.android.xmpp.manager.HttpUploadManager;
|
||||||
import im.conversations.android.xmpp.manager.JingleConnectionManager;
|
import im.conversations.android.xmpp.manager.JingleConnectionManager;
|
||||||
|
import im.conversations.android.xmpp.manager.MultiUserChatManager;
|
||||||
import im.conversations.android.xmpp.manager.NickManager;
|
import im.conversations.android.xmpp.manager.NickManager;
|
||||||
import im.conversations.android.xmpp.manager.PepManager;
|
import im.conversations.android.xmpp.manager.PepManager;
|
||||||
import im.conversations.android.xmpp.manager.PresenceManager;
|
import im.conversations.android.xmpp.manager.PresenceManager;
|
||||||
|
@ -45,6 +46,7 @@ public final class Managers {
|
||||||
.put(
|
.put(
|
||||||
JingleConnectionManager.class,
|
JingleConnectionManager.class,
|
||||||
new JingleConnectionManager(context, connection))
|
new JingleConnectionManager(context, connection))
|
||||||
|
.put(MultiUserChatManager.class, new MultiUserChatManager(context, connection))
|
||||||
.put(NickManager.class, new NickManager(context, connection))
|
.put(NickManager.class, new NickManager(context, connection))
|
||||||
.put(PepManager.class, new PepManager(context, connection))
|
.put(PepManager.class, new PepManager(context, connection))
|
||||||
.put(PresenceManager.class, new PresenceManager(context, connection))
|
.put(PresenceManager.class, new PresenceManager(context, connection))
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package im.conversations.android.xmpp.manager;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class MultiUserChatManager extends AbstractManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MultiUserChatManager.class);
|
||||||
|
|
||||||
|
public MultiUserChatManager(Context context, XmppConnection connection) {
|
||||||
|
super(context, connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enter(final BareJid room) {
|
||||||
|
final var presence = new Presence();
|
||||||
|
presence.setTo(JidCreate.fullFrom(room, Resourcepart.fromOrThrowUnchecked("c3-test-user")));
|
||||||
|
presence.addExtension(new MultiUserChat());
|
||||||
|
LOGGER.info("sending {} ", presence);
|
||||||
|
connection.sendPresencePacket(presence);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package im.conversations.android.xmpp.model.muc.user;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
import im.conversations.android.xmpp.model.muc.Affiliation;
|
||||||
|
import im.conversations.android.xmpp.model.muc.Role;
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Item extends Extension {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(Item.class);
|
||||||
|
|
||||||
|
public Item() {
|
||||||
|
super(Item.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Affiliation getAffiliation() {
|
||||||
|
final var affiliation = this.getAttribute("affiliation");
|
||||||
|
if (Strings.isNullOrEmpty(affiliation)) {
|
||||||
|
return Affiliation.NONE;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Affiliation.valueOf(affiliation.toUpperCase(Locale.ROOT));
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
LOGGER.warn("could not parse affiliation {}", affiliation);
|
||||||
|
return Affiliation.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role getRole() {
|
||||||
|
final var role = this.getAttribute("role");
|
||||||
|
if (Strings.isNullOrEmpty(role)) {
|
||||||
|
return Role.NONE;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Role.valueOf(role.toUpperCase(Locale.ROOT));
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
LOGGER.warn("could not parse role {}", role);
|
||||||
|
return Role.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNick() {
|
||||||
|
return this.getAttribute("nick");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
final var jid = this.getAttribute("jid");
|
||||||
|
if (Strings.isNullOrEmpty(jid)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JidCreate.from(jid);
|
||||||
|
} catch (final XmppStringprepException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
package im.conversations.android.xmpp.model.muc.user;
|
package im.conversations.android.xmpp.model.muc.user;
|
||||||
|
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
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.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@XmlElement(name = "x")
|
@XmlElement(name = "x")
|
||||||
public class MultiUserChat extends Extension {
|
public class MultiUserChat extends Extension {
|
||||||
|
@ -9,4 +12,14 @@ public class MultiUserChat extends Extension {
|
||||||
public MultiUserChat() {
|
public MultiUserChat() {
|
||||||
super(MultiUserChat.class);
|
super(MultiUserChat.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Item getItem() {
|
||||||
|
return this.getExtension(Item.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Integer> getStatus() {
|
||||||
|
return Collections2.filter(
|
||||||
|
Collections2.transform(getExtensions(Status.class), Status::getCode),
|
||||||
|
Objects::nonNull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package im.conversations.android.xmpp.model.muc.user;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Status extends Extension {
|
||||||
|
|
||||||
|
public Status() {
|
||||||
|
super(Status.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return this.getOptionalIntAttribute("code").orNull();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.vcard;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class VCard extends Extension {
|
||||||
|
|
||||||
|
public VCard() {
|
||||||
|
super(VCard.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.VCARD_TEMP)
|
||||||
|
package im.conversations.android.xmpp.model.vcard;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
||||||
|
import im.conversations.android.xml.Namespace;
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.vcard.update;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Photo extends Extension {
|
||||||
|
|
||||||
|
public Photo() {
|
||||||
|
super(Photo.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package im.conversations.android.xmpp.model.vcard.update;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement(name = "x")
|
||||||
|
public class VCardUpdate extends Extension {
|
||||||
|
|
||||||
|
public VCardUpdate() {
|
||||||
|
super(VCardUpdate.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Photo getPhoto() {
|
||||||
|
return this.getExtension(Photo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHash() {
|
||||||
|
final var photo = getPhoto();
|
||||||
|
return photo == null ? null : photo.getContent();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.VCARD_TEMP_UPDATE)
|
||||||
|
package im.conversations.android.xmpp.model.vcard.update;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
||||||
|
import im.conversations.android.xml.Namespace;
|
|
@ -3,10 +3,14 @@ package im.conversations.android.xmpp.processor;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import im.conversations.android.database.model.PresenceShow;
|
import im.conversations.android.database.model.PresenceShow;
|
||||||
import im.conversations.android.database.model.PresenceType;
|
import im.conversations.android.database.model.PresenceType;
|
||||||
|
import im.conversations.android.xml.Namespace;
|
||||||
import im.conversations.android.xmpp.Entity;
|
import im.conversations.android.xmpp.Entity;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
|
import im.conversations.android.xmpp.model.occupant.OccupantId;
|
||||||
import im.conversations.android.xmpp.model.stanza.Presence;
|
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||||
|
import im.conversations.android.xmpp.model.vcard.update.VCardUpdate;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -38,9 +42,35 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum
|
||||||
}
|
}
|
||||||
final var show = PresenceShow.of(presencePacket.findChildContent("show"));
|
final var show = PresenceShow.of(presencePacket.findChildContent("show"));
|
||||||
final var status = presencePacket.findChildContent("status");
|
final var status = presencePacket.findChildContent("status");
|
||||||
getDatabase().presenceDao().set(getAccount(), address, resource, type, show, status);
|
|
||||||
|
|
||||||
// TODO store presence info (vCard + muc#user stuff + occupantId)
|
final var vCardUpdate = presencePacket.getExtension(VCardUpdate.class);
|
||||||
|
final var vCardPhoto = vCardUpdate == null ? null : vCardUpdate.getHash();
|
||||||
|
final var muc = presencePacket.getExtension(MultiUserChat.class);
|
||||||
|
|
||||||
|
final String occupantId;
|
||||||
|
if (muc != null && presencePacket.hasExtension(OccupantId.class)) {
|
||||||
|
if (getManager(DiscoManager.class)
|
||||||
|
.hasFeature(Entity.discoItem(address), Namespace.OCCUPANT_ID)) {
|
||||||
|
occupantId = presencePacket.getExtension(OccupantId.class).getId();
|
||||||
|
} else {
|
||||||
|
occupantId = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
occupantId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDatabase()
|
||||||
|
.presenceDao()
|
||||||
|
.set(
|
||||||
|
getAccount(),
|
||||||
|
address,
|
||||||
|
resource,
|
||||||
|
type,
|
||||||
|
show,
|
||||||
|
status,
|
||||||
|
vCardPhoto,
|
||||||
|
occupantId,
|
||||||
|
muc);
|
||||||
|
|
||||||
// TODO do this only for contacts?
|
// TODO do this only for contacts?
|
||||||
fetchCapabilities(presencePacket);
|
fetchCapabilities(presencePacket);
|
||||||
|
|
Loading…
Reference in a new issue