diff --git a/documentation/extensions/muc.md b/documentation/extensions/muc.md index b20d7cb16..207fcd83d 100644 --- a/documentation/extensions/muc.md +++ b/documentation/extensions/muc.md @@ -17,6 +17,19 @@ text-based conference rooms. **XEP related:** [XEP-45](http://www.xmpp.org/extensions/xep-0045.html) +For all examples in this document, assume that the following variables exists: + +```java +// Create the XMPP address (JID) of the MUC. +EntityBareJid mucJid = JidCreate.bareFrom("myroom@conference.jabber.org"); + +// Create the nickname. +Resourcepart nickname = Resourcepart.from("testbot"); + +// A other use (we may invite him to a MUC). +FullJid otherJid = JidCreate.fullFromm("user3@host.org/Smack"); +``` + Create a new Room ----------------- @@ -52,10 +65,10 @@ In this example we can see how to create an instant room: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Get a MultiUserChat using MultiUserChatManager -MultiUserChat muc = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc = manager.getMultiUserChat(mucJid); // Create the room and send an empty configuration form to make this an instant room -muc.create("testbot").makeInstant(); +muc.create(nickname).makeInstant(); ``` In this example we can see how to create a reserved room. The form is @@ -66,13 +79,13 @@ completed with default values: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Create a MultiUserChat using an XMPPConnection for a room -MultiUserChat muc = = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc = = manager.getMultiUserChat(mucJid); // Prepare a list of owners of the new room Set owners = JidUtil.jidSetFrom(new String[] { "me@example.org", "juliet@example.org" }); // Create the room -muc.create("testbot") +muc.create(nickname) .getConfigFormManger() .setRoomOwners(owners) .submitConfigurationForm(); @@ -116,11 +129,11 @@ In this example we can see how to join a room with a given nickname: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Create a MultiUserChat using an XMPPConnection for a room -MultiUserChat muc2 = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc2 = manager.getMultiUserChat(mucJid); // User2 joins the new room // The room service will decide the amount of history to send -muc2.join("testbot2"); +muc2.join(nickname); ``` In this example we can see how to join a room with a given nickname and @@ -131,11 +144,11 @@ password: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Create a MultiUserChat using an XMPPConnection for a room -MultiUserChat muc2 = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc2 = manager.getMultiUserChat(mucJid); // User2 joins the new room using a password // The room service will decide the amount of history to send -muc2.join("testbot2", "password"); +muc2.join(nickname, "password"); ``` In this example we can see how to join a room with a given nickname specifying @@ -146,13 +159,13 @@ the amount of history to receive: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Create a MultiUserChat using an XMPPConnection for a room -MultiUserChat muc2 = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc2 = manager.getMultiUserChat(mucJid); // User2 joins the new room using a password and specifying // the amount of history to receive. In this example we are requesting the last 5 messages. DiscussionHistory history = new DiscussionHistory(); history.setMaxStanzas(5); -muc2.join("testbot2", "password", history, conn1.getPacketReplyTimeout()); +muc2.join(nickname, "password", history, conn1.getPacketReplyTimeout()); ``` Manage room invitations @@ -193,9 +206,9 @@ for possible rejections: MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); // Create a MultiUserChat using an XMPPConnection for a room -MultiUserChat muc2 = manager.getMultiUserChat("myroom@conference.jabber.org"); +MultiUserChat muc2 = manager.getMultiUserChat(mucJid); -muc2.join("testbot2"); +muc2.join(nickname); // User2 listens for invitation rejections muc2.addInvitationRejectionListener(new InvitationRejectionListener() { public void invitationDeclined(String invitee, String reason) { @@ -203,7 +216,7 @@ muc2.addInvitationRejectionListener(new InvitationRejectionListener() { } }); // User2 invites user3 to join to the room -muc2.invite("user3@host.org/Smack", "Meet me in this excellent room"); +muc2.invite(otherJid, "Meet me in this excellent room"); ``` In this example we can see how to listen for room invitations and decline @@ -212,9 +225,9 @@ invitations: ```java // User3 listens for MUC invitations MultiUserChatManager.getInstanceFor(connection).addInvitationListener(new InvitationListener() { - public void invitationReceived(XMPPConnection conn, String room, String inviter, String reason, String password) { + public void invitationReceived(XMPPConnection conn, String room, EntityFullJid inviter, String reason, String password) { // Reject the invitation - MultiUserChat.decline(conn, room, inviter, "I'm busy right now"); + MultiUserChat.decline(conn, room, inviter.asBareJid()s, "I'm busy right now"); } }); ``` @@ -241,7 +254,7 @@ In this example we can see how to discover support of MUC: ```java // Discover whether user3@host.org supports MUC or not -boolean supports = MultiUserChatManager.getInstanceFor(connection).isServiceEnabled("user3@host.org/Smack"); +boolean supports = MultiUserChatManager.getInstanceFor(connection).isServiceEnabled(otherJid); ``` Discover joined rooms diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java index 2a1ea14b7..bd4c722fc 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java @@ -25,6 +25,7 @@ import java.util.Locale; import org.jivesoftware.smack.SmackException; import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; @@ -85,6 +86,18 @@ public class ParserUtils { return JidCreate.entityBareFrom(jidString); } + public static EntityFullJid getFullJidAttribute(XmlPullParser parser) throws XmppStringprepException { + return getFullJidAttribute(parser, JID); + } + + public static EntityFullJid getFullJidAttribute(XmlPullParser parser, String name) throws XmppStringprepException { + final String jidString = parser.getAttributeValue("", name); + if (jidString == null) { + return null; + } + return JidCreate.entityFullFrom(jidString); + } + public static Resourcepart getResourcepartAttribute(XmlPullParser parser, String name) throws XmppStringprepException { final String resourcepartString = parser.getAttributeValue("", name); if (resourcepartString == null) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationListener.java index cec5de04c..4c9289050 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationListener.java @@ -19,6 +19,8 @@ package org.jivesoftware.smackx.muc; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.muc.packet.MUCUser; +import org.jxmpp.jid.EntityFullJid; /** * A listener that is fired anytime an invitation to join a MUC room is received. @@ -39,8 +41,9 @@ public interface InvitationListener { * @param reason the reason why the inviter sent the invitation. * @param password the password to use when joining the room. * @param message the message used by the inviter to send the invitation. + * @param invitation the raw invitation received with the message. */ - public abstract void invitationReceived(XMPPConnection conn, MultiUserChat room, String inviter, String reason, - String password, Message message); + public abstract void invitationReceived(XMPPConnection conn, MultiUserChat room, EntityFullJid inviter, String reason, + String password, Message message, MUCUser.Invite invitation); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationRejectionListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationRejectionListener.java index 153373dee..622b3f201 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationRejectionListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/InvitationRejectionListener.java @@ -17,6 +17,10 @@ package org.jivesoftware.smackx.muc; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.muc.packet.MUCUser; +import org.jxmpp.jid.EntityBareJid; + /** * A listener that is fired anytime an invitee declines or rejects an invitation. * @@ -29,7 +33,9 @@ public interface InvitationRejectionListener { * * @param invitee the invitee that declined the invitation. (e.g. hecate@shakespeare.lit). * @param reason the reason why the invitee declined the invitation. + * @param message the message used to decline the invitation. + * @param rejection the raw decline found in the message. */ - public abstract void invitationDeclined(String invitee, String reason); + public abstract void invitationDeclined(EntityBareJid invitee, String reason, Message message, MUCUser.Decline rejection); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index 172977689..c34391ed1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -251,14 +251,16 @@ public class MultiUserChat { // rejection listeners if the message includes an invitation rejection. declinesListener = new StanzaListener() { public void processPacket(Stanza packet) { + Message message = (Message) packet; // Get the MUC User extension MUCUser mucUser = MUCUser.from(packet); + MUCUser.Decline rejection = mucUser.getDecline(); // Check if the MUCUser informs that the invitee has declined the invitation - if (mucUser.getDecline() == null) { + if (rejection == null) { return; } // Fire event for invitation rejection listeners - fireInvitationRejectionListeners(mucUser.getDecline().getFrom(), mucUser.getDecline().getReason()); + fireInvitationRejectionListeners(message, rejection); } }; @@ -874,7 +876,7 @@ public class MultiUserChat { * @throws NotConnectedException * @throws InterruptedException */ - public void invite(String user, String reason) throws NotConnectedException, InterruptedException { + public void invite(EntityBareJid user, String reason) throws NotConnectedException, InterruptedException { invite(new Message(), user, reason); } @@ -891,15 +893,13 @@ public class MultiUserChat { * @throws NotConnectedException * @throws InterruptedException */ - public void invite(Message message, String user, String reason) throws NotConnectedException, InterruptedException { + public void invite(Message message, EntityBareJid user, String reason) throws NotConnectedException, InterruptedException { // TODO listen for 404 error code when inviter supplies a non-existent JID message.setTo(room); // Create the MUCUser packet that will include the invitation MUCUser mucUser = new MUCUser(); - MUCUser.Invite invite = new MUCUser.Invite(); - invite.setTo(user); - invite.setReason(reason); + MUCUser.Invite invite = new MUCUser.Invite(reason, user); mucUser.setInvite(invite); // Add the MUCUser packet that includes the invitation to the message message.addExtension(mucUser); @@ -935,14 +935,16 @@ public class MultiUserChat { * @param invitee the user being invited. * @param reason the reason for the rejection */ - private void fireInvitationRejectionListeners(String invitee, String reason) { + private void fireInvitationRejectionListeners(Message message, MUCUser.Decline rejection) { + EntityBareJid invitee = rejection.getFrom(); + String reason = rejection.getReason(); InvitationRejectionListener[] listeners; synchronized (invitationRejectionListeners) { listeners = new InvitationRejectionListener[invitationRejectionListeners.size()]; invitationRejectionListeners.toArray(listeners); } for (InvitationRejectionListener listener : listeners) { - listener.invitationDeclined(invitee, reason); + listener.invitationDeclined(invitee, reason, message, rejection); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java index b09a13ba1..a183570cd 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2014 Florian Schmaus + * Copyright © 2014-2016 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ import org.jivesoftware.smackx.muc.MultiUserChatException.NotAMucServiceExceptio import org.jivesoftware.smackx.muc.packet.MUCInitialPresence; import org.jivesoftware.smackx.muc.packet.MUCUser; import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.EntityJid; @@ -139,9 +140,13 @@ public final class MultiUserChatManager extends Manager { } // Fire event for invitation listeners final MultiUserChat muc = getMultiUserChat(mucJid); + final XMPPConnection connection = connection(); + final MUCUser.Invite invite = mucUser.getInvite(); + final EntityFullJid from = invite.getFrom(); + final String reason = invite.getReason(); + final String password = mucUser.getPassword(); for (final InvitationListener listener : invitationsListeners) { - listener.invitationReceived(connection(), muc, mucUser.getInvite().getFrom(), - mucUser.getInvite().getReason(), mucUser.getPassword(), message); + listener.invitationReceived(connection, muc, from, reason, password, message, invite); } } } @@ -318,14 +323,12 @@ public final class MultiUserChatManager extends Manager { * @throws NotConnectedException * @throws InterruptedException */ - public void decline(EntityBareJid room, String inviter, String reason) throws NotConnectedException, InterruptedException { + public void decline(EntityBareJid room, EntityBareJid inviter, String reason) throws NotConnectedException, InterruptedException { Message message = new Message(room); // Create the MUCUser packet that will include the rejection MUCUser mucUser = new MUCUser(); - MUCUser.Decline decline = new MUCUser.Decline(); - decline.setTo(inviter); - decline.setReason(reason); + MUCUser.Decline decline = new MUCUser.Decline(reason, inviter); mucUser.setDecline(decline); // Add the MUCUser packet that includes the rejection message.addExtension(mucUser); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/packet/MUCUser.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/packet/MUCUser.java index dcaa2eab7..e8dcdd5e1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/packet/MUCUser.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/packet/MUCUser.java @@ -27,6 +27,8 @@ import java.util.Set; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; /** * Represents extended presence information about roles, affiliations, full JIDs, @@ -244,9 +246,23 @@ public class MUCUser implements ExtensionElement { public static class Invite implements NamedElement { public static final String ELEMENT ="invite"; - private String reason; - private String from; - private String to; + private final String reason; + private final EntityFullJid from; + private final EntityBareJid to; + + public Invite(String reason, EntityFullJid from) { + this(reason, from, null); + } + + public Invite(String reason, EntityBareJid to) { + this(reason, null, to); + } + + public Invite(String reason, EntityFullJid from, EntityBareJid to) { + this.reason = reason; + this.from = from; + this.to = to; + } /** * Returns the bare JID of the inviter or, optionally, the room JID. (e.g. @@ -254,7 +270,7 @@ public class MUCUser implements ExtensionElement { * * @return the room's occupant that sent the invitation. */ - public String getFrom() { + public EntityFullJid getFrom() { return from; } @@ -272,38 +288,10 @@ public class MUCUser implements ExtensionElement { * * @return the bare JID of the invitee. */ - public String getTo() { + public EntityBareJid getTo() { return to; } - /** - * Sets the bare JID of the inviter or, optionally, the room JID. (e.g. - * 'crone1@shakespeare.lit/desktop') - * - * @param from the bare JID of the inviter or, optionally, the room JID. - */ - public void setFrom(String from) { - this.from = from; - } - - /** - * Sets the message explaining the invitation. - * - * @param reason the message explaining the invitation. - */ - public void setReason(String reason) { - this.reason = reason; - } - - /** - * Sets the bare JID of the invitee. (e.g. 'hecate@shakespeare.lit') - * - * @param to the bare JID of the invitee. - */ - public void setTo(String to) { - this.to = to; - } - @Override public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(this); @@ -330,17 +318,27 @@ public class MUCUser implements ExtensionElement { public static class Decline implements NamedElement { public static final String ELEMENT = "decline"; - private String reason; - private String from; - private String to; + private final String reason; + private final EntityBareJid from; + private final EntityBareJid to; + + public Decline(String reason, EntityBareJid to) { + this(reason, null, to); + } + + public Decline(String reason, EntityBareJid from, EntityBareJid to) { + this.reason = reason; + this.from = from; + this.to = to; + } /** * Returns the bare JID of the invitee that rejected the invitation. (e.g. - * 'crone1@shakespeare.lit/desktop'). + * 'crone1@shakespeare.lit'). * * @return the bare JID of the invitee that rejected the invitation. */ - public String getFrom() { + public EntityBareJid getFrom() { return from; } @@ -358,38 +356,10 @@ public class MUCUser implements ExtensionElement { * * @return the bare JID of the inviter. */ - public String getTo() { + public EntityBareJid getTo() { return to; } - /** - * Sets the bare JID of the invitee that rejected the invitation. (e.g. - * 'crone1@shakespeare.lit/desktop'). - * - * @param from the bare JID of the invitee that rejected the invitation. - */ - public void setFrom(String from) { - this.from = from; - } - - /** - * Sets the message explaining why the invitation was rejected. - * - * @param reason the message explaining the reason for the rejection. - */ - public void setReason(String reason) { - this.reason = reason; - } - - /** - * Sets the bare JID of the inviter. (e.g. 'hecate@shakespeare.lit') - * - * @param to the bare JID of the inviter. - */ - public void setTo(String to) { - this.to = to; - } - @Override public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(this); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/provider/MUCUserProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/provider/MUCUserProvider.java index f59c872e4..638145e20 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/provider/MUCUserProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/provider/MUCUserProvider.java @@ -21,7 +21,10 @@ package org.jivesoftware.smackx.muc.provider; import java.io.IOException; import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smackx.muc.packet.MUCUser; +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -81,44 +84,44 @@ public class MUCUserProvider extends ExtensionElementProvider { } private static MUCUser.Invite parseInvite(XmlPullParser parser) throws XmlPullParserException, IOException { - boolean done = false; - MUCUser.Invite invite = new MUCUser.Invite(); - invite.setFrom(parser.getAttributeValue("", "from")); - invite.setTo(parser.getAttributeValue("", "to")); - while (!done) { + String reason = null; + EntityBareJid to = ParserUtils.getBareJidAttribute(parser, "to"); + EntityFullJid from = ParserUtils.getFullJidAttribute(parser, "from"); + + outerloop: while (true) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if (parser.getName().equals("reason")) { - invite.setReason(parser.nextText()); + reason = parser.nextText(); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("invite")) { - done = true; + break outerloop; } } } - return invite; + return new MUCUser.Invite(reason, from, to); } private static MUCUser.Decline parseDecline(XmlPullParser parser) throws XmlPullParserException, IOException { - boolean done = false; - MUCUser.Decline decline = new MUCUser.Decline(); - decline.setFrom(parser.getAttributeValue("", "from")); - decline.setTo(parser.getAttributeValue("", "to")); - while (!done) { + String reason = null; + EntityBareJid to = ParserUtils.getBareJidAttribute(parser, "to"); + EntityBareJid from = ParserUtils.getBareJidAttribute(parser, "from"); + + outerloop: while (true) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if (parser.getName().equals("reason")) { - decline.setReason(parser.nextText()); + reason = parser.nextText(); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("decline")) { - done = true; + break outerloop; } } } - return decline; + return new MUCUser.Decline(reason, from, to); } } diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/user/Workgroup.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/user/Workgroup.java index 97565db8a..857ba075b 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/user/Workgroup.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/user/Workgroup.java @@ -58,6 +58,7 @@ import org.jivesoftware.smackx.workgroup.settings.WorkgroupProperties; import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.Jid; @@ -132,8 +133,8 @@ public class Workgroup { MultiUserChatManager.getInstanceFor(connection).addInvitationListener( new org.jivesoftware.smackx.muc.InvitationListener() { @Override - public void invitationReceived(XMPPConnection conn, org.jivesoftware.smackx.muc.MultiUserChat room, String inviter, - String reason, String password, Message message) { + public void invitationReceived(XMPPConnection conn, org.jivesoftware.smackx.muc.MultiUserChat room, EntityFullJid inviter, + String reason, String password, Message message, MUCUser.Invite invitation) { inQueue = false; queuePosition = -1; queueRemainingTime = -1;