Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/iNPUTmice/Conversations.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2018-12-07 22:21:01 +0300
committerDaniel Gultsch <daniel@gultsch.de>2018-12-07 22:21:01 +0300
commit3bc24088724448f1bc491130edb87372586b5a73 (patch)
treec179b2e647b6faf5450bdb66ac608bde8eb168e9
parent92f4f5b8656fff418169a2652b4404c36477777e (diff)
some very basic MIX code (join/leave) that reutilizes MUC UImix
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java13
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java3
-rw-r--r--src/main/java/eu/siacs/conversations/parser/AbstractParser.java14
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java89
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java93
-rw-r--r--src/main/java/eu/siacs/conversations/xml/Namespace.java2
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java17
7 files changed, 207 insertions, 24 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index 2a751d95e..da840c145 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -16,6 +16,7 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.utils.JidHelper;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.forms.Field;
@@ -111,6 +112,10 @@ public class MucOptions {
return MessageArchiveService.Version.has(getFeatures());
}
+ public boolean isMix() {
+ return hasFeature(Namespace.MIX_CORE);
+ }
+
public boolean updateConfiguration(ServiceDiscoveryResult serviceDiscoveryResult) {
this.serviceDiscoveryResult = serviceDiscoveryResult;
String name;
@@ -716,6 +721,10 @@ public class MucOptions {
this.role = Role.of(role);
}
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
public Affiliation getAffiliation() {
return this.affiliation;
}
@@ -724,6 +733,10 @@ public class MucOptions {
this.affiliation = Affiliation.of(affiliation);
}
+ public void setAffiliation(Affiliation affiliation) {
+ this.affiliation = affiliation;
+ }
+
public long getPgpKeyId() {
if (this.pgpKeyId != 0) {
return this.pgpKeyId;
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index d320168bb..5833c198c 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -39,7 +39,8 @@ public abstract class AbstractGenerator {
Namespace.BOOKMARKS+"+notify",
"urn:xmpp:ping",
"jabber:iq:version",
- "http://jabber.org/protocol/chatstates"
+ "http://jabber.org/protocol/chatstates",
+ Namespace.MIX_CORE
};
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
"urn:xmpp:chat-markers:0",
diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
index 05297d74d..4598bd0f7 100644
--- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
@@ -5,12 +5,14 @@ import java.text.SimpleDateFormat;
import java.util.Locale;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
import rocks.xmpp.addr.Jid;
@@ -97,6 +99,18 @@ public abstract class AbstractParser {
return item.findChildContent("data", "urn:xmpp:avatar:data");
}
+ public static MucOptions.User parseParticipant(Conversation conversation, Element item) {
+ Element participant = item.findChild("participant", Namespace.MIX_CORE);
+ final String id = item.getAttribute("id");
+ final Jid jid = participant == null ? null : participant.getAttributeAsJid("jid");
+ Jid fullJid = conversation.getJid().asBareJid().withResource(id);
+ MucOptions.User user = new MucOptions.User(conversation.getMucOptions(), fullJid);
+ user.setRealJid(jid);
+ user.setAffiliation(MucOptions.Affiliation.MEMBER);
+ user.setRole(MucOptions.Role.PARTICIPANT);
+ return user;
+ }
+
public static MucOptions.User parseItem(Conversation conference, Element item) {
return parseItem(conference,item, null);
}
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 42b921bd1..557d61dda 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -49,10 +49,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
super(service);
}
- private static String extractStanzaId(Element packet, boolean isTypeGroupChat, Conversation conversation) {
+ private static String extractStanzaId(MessagePacket packet, boolean isTypeGroupChat, Conversation conversation) {
final Jid by;
final boolean safeToExtract;
if (isTypeGroupChat) {
+ if (conversation.getMucOptions().isMix()) {
+ return packet.getId();
+ }
by = conversation.getJid().asBareJid();
safeToExtract = conversation.getMucOptions().hasFeature(Namespace.STANZA_IDS);
} else {
@@ -221,6 +224,32 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final Element storage = i == null ? null : i.findChild("storage", Namespace.BOOKMARKS);
mXmppConnectionService.processBookmarks(account, storage);
}
+ } else if ("urn:xmpp:mix:nodes:participants".equals(node)) {
+ Conversation conversation = mXmppConnectionService.find(account, from.asBareJid());
+ if (conversation == null) {
+ Log.d(Config.LOGTAG,"not finding proper conversation for participant event");
+ return;
+ }
+ for(Element item : items.getChildren()) {
+ if ("item".equals(item.getName())) {
+ MucOptions.User user = AbstractParser.parseParticipant(conversation, item);
+ if (conversation.getMucOptions().updateUser(user)) {
+ mXmppConnectionService.getAvatarService().clear(conversation);
+ }
+ Log.d(Config.LOGTAG,"updating user with full jid="+user.getFullJid());
+ //Log.d(Config.LOGTAG,item.toString());
+ } else if ("retract".equals(item.getName())) {
+ String id = item.getAttribute("id");
+ if (id != null) {
+ Jid jid = conversation.getJid().asBareJid().withResource(id);
+ MucOptions.User user = conversation.getMucOptions().deleteUser(jid);
+ Log.d(Config.LOGTAG,account.getJid().asBareJid()+": retracting user "+jid);
+ if (user != null) {
+ mXmppConnectionService.getAvatarService().clear(conversation);
+ }
+ }
+ }
+ }
}
}
@@ -387,20 +416,34 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
if (isTypeGroupChat) {
- if (conversation.getMucOptions().isSelf(counterpart)) {
- status = Message.STATUS_SEND_RECEIVED;
- isCarbon = true; //not really carbon but received from another resource
- if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status, serverMsgId)) {
- return;
- } else if (remoteMsgId == null || Config.IGNORE_ID_REWRITE_IN_MUC) {
- Message message = conversation.findSentMessageWithBody(packet.getBody());
- if (message != null) {
- mXmppConnectionService.markMessage(message, status);
+ if (conversation.getMucOptions().isMix()) {
+ if (account.getJid().asBareJid().equals(extractJid(packet))) {
+ status = Message.STATUS_SEND_RECEIVED;
+ isCarbon = true;
+ Element mix = packet.findChild("mix",Namespace.MIX_CORE);
+ String submissionId = mix == null ? null : mix.findChildContent("submission-id");
+ if (submissionId != null && mXmppConnectionService.markMessage(conversation, submissionId, status, serverMsgId)) {
return;
}
+ } else {
+ status = Message.STATUS_RECEIVED;
}
} else {
- status = Message.STATUS_RECEIVED;
+ if (conversation.getMucOptions().isSelf(counterpart)) {
+ status = Message.STATUS_SEND_RECEIVED;
+ isCarbon = true; //not really carbon but received from another resource
+ if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status, serverMsgId)) {
+ return;
+ } else if (remoteMsgId == null || Config.IGNORE_ID_REWRITE_IN_MUC) {
+ Message message = conversation.findSentMessageWithBody(packet.getBody());
+ if (message != null) {
+ mXmppConnectionService.markMessage(message, status);
+ return;
+ }
+ }
+ } else {
+ status = Message.STATUS_RECEIVED;
+ }
}
}
final Message message;
@@ -491,14 +534,18 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
message.markable = packet.hasChild("markable", "urn:xmpp:chat-markers:0");
if (conversationMultiMode) {
message.setMucUser(conversation.getMucOptions().findUserByFullJid(counterpart));
- final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
- Jid trueCounterpart;
- if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
- trueCounterpart = message.getTrueCounterpart();
- } else if (query != null && query.safeToExtractTrueCounterpart()) {
- trueCounterpart = getTrueCounterpart(mucUserElement, fallback);
+ final Jid trueCounterpart;
+ if (conversation.getMucOptions().isMix()) {
+ trueCounterpart = extractJid(packet);
} else {
- trueCounterpart = fallback;
+ final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
+ if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
+ trueCounterpart = message.getTrueCounterpart();
+ } else if (query != null && query.safeToExtractTrueCounterpart()) {
+ trueCounterpart = getTrueCounterpart(mucUserElement, fallback);
+ } else {
+ trueCounterpart = fallback;
+ }
}
if (trueCounterpart != null && trueCounterpart.asBareJid().equals(account.getJid().asBareJid())) {
status = isTypeGroupChat ? Message.STATUS_SEND_RECEIVED : Message.STATUS_SEND;
@@ -809,6 +856,12 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
+ private static Jid extractJid(MessagePacket message) {
+ Element mix = message.findChild("mix",Namespace.MIX_CORE);
+ String jid = mix == null ? null : mix.findChildContent("jid");
+ return jid == null ? null : Jid.of(jid);
+ }
+
private void dismissNotification(Account account, Jid counterpart, MessageArchiveService.Query query) {
Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid());
if (conversation != null && (query == null || query.isCatchup())) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index dad6c558f..20a6f944b 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -1846,7 +1846,11 @@ public class XmppConnectionService extends Service {
pushBookmarks(bookmark.getAccount());
}
}
- leaveMuc(conversation);
+ if (conversation.getMucOptions().isMix()) {
+ leaveMix(conversation);
+ } else {
+ leaveMuc(conversation);
+ }
} else {
if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
stopPresenceUpdatesTo(conversation.getContact());
@@ -2295,8 +2299,8 @@ public class XmppConnectionService extends Service {
conversation.setHasMessagesLeftOnServer(false);
fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() {
- private void join(Conversation conversation) {
- Account account = conversation.getAccount();
+ private void joinMuc(Conversation conversation) {
+ Account account = conversation.getAccount();
final MucOptions mucOptions = conversation.getMucOptions();
final Jid joinJid = mucOptions.getSelf().getFullJid();
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": joining conversation " + joinJid.toString());
@@ -2333,6 +2337,32 @@ public class XmppConnectionService extends Service {
}
}
sendUnsentMessages(conversation);
+ }
+
+ private void joinMix(Conversation conversation) {
+ IqPacket clientJoin = new IqPacket(IqPacket.TYPE.SET);
+ Element join = clientJoin.addChild("client-join",Namespace.MIX_PAM).setAttribute("channel",conversation.getJid().asBareJid().toEscapedString()).addChild("join",Namespace.MIX_CORE);
+ join.addChild("subscribe").setAttribute("node","urn:xmpp:mix:nodes:messages");
+ join.addChild("subscribe").setAttribute("node","urn:xmpp:mix:nodes:participants");
+ sendIqPacket(account, clientJoin, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ conversation.getMucOptions().setOnline();
+ //Log.d(Config.LOGTAG,packet.toString());
+ }
+ });
+ fetchMixParticipants(conversation);
+ if (conversation.getMucOptions().mamSupport()) {
+ getMessageArchiveService().catchupMUC(conversation);
+ }
+ }
+
+ private void join(Conversation conversation) {
+ if (conversation.getMucOptions().isMix()) {
+ joinMix(conversation);
+ } else {
+ joinMuc(conversation);
+ }
}
@Override
@@ -2360,6 +2390,29 @@ public class XmppConnectionService extends Service {
}
}
+ private void fetchMixParticipants(final Conversation conversation) {
+ IqPacket fetch = new IqPacket(IqPacket.TYPE.GET);
+ fetch.setTo(conversation.getJid().asBareJid());
+ fetch.addChild("pubsub",Namespace.PUBSUB).addChild("items").setAttribute("node","urn:xmpp:mix:nodes:participants");
+ sendIqPacket(conversation.getAccount(), fetch, (account, response) -> {
+ if (response.getType() == IqPacket.TYPE.RESULT) {
+ Element pubsub = response.findChild("pubsub",Namespace.PUBSUB);
+ Element items = pubsub == null ? null : pubsub.findChild("items");
+ if (items != null) {
+ final MucOptions mucOptions = conversation.getMucOptions();
+ for(Element item : items.getChildren()) {
+ if ("item".equals(item.getName())) {
+ MucOptions.User user = AbstractParser.parseParticipant(conversation, item);
+ Log.d(Config.LOGTAG,account.getJid().asBareJid()+": adding user with full jid="+user.getFullJid()+" after fetch");
+ mucOptions.updateUser(user);
+ }
+ }
+ }
+ getAvatarService().clear(conversation);
+ }
+ });
+ }
+
private void fetchConferenceMembers(final Conversation conversation) {
final Account account = conversation.getAccount();
final AxolotlService axolotlService = account.getAxolotlService();
@@ -2527,6 +2580,14 @@ public class XmppConnectionService extends Service {
return true;
}
+ public void leaveMix(Conversation conversation) {
+ IqPacket request = new IqPacket(IqPacket.TYPE.SET);
+ Element clientLeave = request.addChild("client-leave",Namespace.MIX_PAM).setAttribute("channel",conversation.getJid().asBareJid().toEscapedString());
+ clientLeave.addChild("leave",Namespace.MIX_CORE);
+ sendIqPacket(conversation.getAccount(), request, (account, packet) -> Log.d(Config.LOGTAG,packet.toString()));
+
+ }
+
public void leaveMuc(Conversation conversation) {
leaveMuc(conversation, false);
}
@@ -2574,6 +2635,32 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": creating adhoc conference with " + jids.toString());
if (account.getStatus() == Account.State.ONLINE) {
try {
+
+ List<String> mixServers = account.getXmppConnection().getMixServers();
+ if (mixServers.size() > 0) {
+ Log.d(Config.LOGTAG,"found mix servers: "+mixServers.get(0));
+ IqPacket mixCreate = new IqPacket(IqPacket.TYPE.SET);
+ mixCreate.setTo(Jid.of(mixServers.get(0)));
+ mixCreate.addChild("create",Namespace.MIX_CORE);//.setAttribute("channel",CryptoHelper.pronounceable(getRNG()));
+ Log.d(Config.LOGTAG,mixCreate.toString());
+ sendIqPacket(account, mixCreate, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ final Element create = packet.findChild("create",Namespace.MIX_CORE);
+ final String channel = create == null ? null : create.getAttribute("channel");
+ if (channel != null) {
+ Jid jid = Jid.of(channel,packet.getFrom(), null);
+ findOrCreateConversation(account, jid, true, false);
+ }
+ } else {
+ Log.d(Config.LOGTAG, packet.toString());
+ }
+ }
+ });
+ return false;
+ }
+
String server = findConferenceServer(account);
if (server == null) {
if (callback != null) {
diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java
index 501acf89c..904637a26 100644
--- a/src/main/java/eu/siacs/conversations/xml/Namespace.java
+++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java
@@ -24,4 +24,6 @@ public final class Namespace {
public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0";
public static final String BOOKMARKS = "storage:bookmarks";
public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0";
+ public static final String MIX_CORE = "urn:xmpp:mix:core:0";
+ public static final String MIX_PAM = "urn:xmpp:mix:pam:0";
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 94833a3b3..e7684b9f1 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -1360,6 +1360,7 @@ public class XmppConnection implements Runnable {
}
public void sendMessagePacket(final MessagePacket packet) {
+ Log.d(Config.LOGTAG,packet.toString());
this.sendPacket(packet);
}
@@ -1543,12 +1544,12 @@ public class XmppConnection implements Runnable {
return servers;
}
- public List<String> getMucServers() {
+ private List<String> getGroupChatService(final String namespace) {
List<String> servers = new ArrayList<>();
synchronized (this.disco) {
for (final Entry<Jid, ServiceDiscoveryResult> cursor : disco.entrySet()) {
final ServiceDiscoveryResult value = cursor.getValue();
- if (value.getFeatures().contains("http://jabber.org/protocol/muc")
+ if (value.getFeatures().contains(namespace)
&& value.hasIdentity("conference", "text")
&& !value.getFeatures().contains("jabber:iq:gateway")
&& !value.hasIdentity("conference", "irc")) {
@@ -1559,6 +1560,14 @@ public class XmppConnection implements Runnable {
return servers;
}
+ public List<String> getMixServers() {
+ return getGroupChatService(Namespace.MIX_CORE);
+ }
+
+ public List<String> getMucServers() {
+ return getGroupChatService("http://jabber.org/protocol/muc");
+ }
+
public String getMucServer() {
List<String> servers = getMucServers();
return servers.size() > 0 ? servers.get(0) : null;
@@ -1801,6 +1810,10 @@ public class XmppConnection implements Runnable {
return MessageArchiveService.Version.has(getAccountFeatures());
}
+ public boolean mixPam() {
+ return hasDiscoFeature(account.getJid().asBareJid(), Namespace.MIX_PAM);
+ }
+
public List<String> getAccountFeatures() {
ServiceDiscoveryResult result = connection.disco.get(account.getJid().asBareJid());
return result == null ? Collections.emptyList() : result.getFeatures();