mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-25 15:52:06 +01:00
Add MucBookmarkAutojoinManager
Also add MucConfigFormManager and improve the MUC API (SMACK-648). Bump to jxmpp 0.5.0-alpha3. Improve and extend PrivateDataManager and BookmarkManager.
This commit is contained in:
parent
265e5c69d5
commit
f274581c27
15 changed files with 690 additions and 102 deletions
|
@ -38,8 +38,8 @@ the _**MultiUserChat**_ instance where nickname is the nickname to use when
|
||||||
joining the room.
|
joining the room.
|
||||||
|
|
||||||
Depending on the type of room that you want to create you will have to use
|
Depending on the type of room that you want to create you will have to use
|
||||||
different configuration forms. In order to create an Instant room just send
|
different configuration forms. In order to create an Instant room just use
|
||||||
**sendConfigurationForm(Form form)** where form is an empty form. But if you
|
`MucCreateConfigFormHandle.makeInstant()`. But if you
|
||||||
want to create a Reserved room then you should first get the room's
|
want to create a Reserved room then you should first get the room's
|
||||||
configuration form, complete the form and finally send it back to the server.
|
configuration form, complete the form and finally send it back to the server.
|
||||||
|
|
||||||
|
@ -54,12 +54,8 @@ MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
|
||||||
// Get a MultiUserChat using MultiUserChatManager
|
// Get a MultiUserChat using MultiUserChatManager
|
||||||
MultiUserChat muc = manager.getMultiUserChat("myroom@conference.jabber.org");
|
MultiUserChat muc = manager.getMultiUserChat("myroom@conference.jabber.org");
|
||||||
|
|
||||||
// Create the room
|
// Create the room and send an empty configuration form to make this an instant room
|
||||||
muc.create("testbot");
|
muc.create("testbot").makeInstant();
|
||||||
|
|
||||||
// Send an empty room configuration form which indicates that we want
|
|
||||||
// an instant room
|
|
||||||
muc.sendConfigurationForm(new Form(DataForm.Type.submit));
|
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example we can see how to create a reserved room. The form is
|
In this example we can see how to create a reserved room. The form is
|
||||||
|
@ -72,27 +68,14 @@ MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
|
||||||
// Create a MultiUserChat using an XMPPConnection for a room
|
// Create a MultiUserChat using an XMPPConnection for a room
|
||||||
MultiUserChat muc = = manager.getMultiUserChat("myroom@conference.jabber.org");
|
MultiUserChat muc = = manager.getMultiUserChat("myroom@conference.jabber.org");
|
||||||
|
|
||||||
// Create the room
|
// Prepare a list of owners of the new room
|
||||||
muc.create("testbot");
|
Set<Jid> owners = JidUtil.jidSetFrom(new String[] { "me@example.org", "juliet@example.org" });
|
||||||
|
|
||||||
// Get the the room's configuration form
|
// Create the room
|
||||||
Form form = muc.getConfigurationForm();
|
muc.create("testbot")
|
||||||
// Create a new form to submit based on the original form
|
.getConfigFormManger()
|
||||||
Form submitForm = form.createAnswerForm();
|
.setRoomOwners(owners)
|
||||||
// Add default answers to the form to submit
|
.submitConfigurationForm();
|
||||||
for (Iterator fields = form.getFields(); fields.hasNext();) {
|
|
||||||
FormField field = (FormField) fields.next();
|
|
||||||
if (!FormField.type.hidden.equals(field.getType()) && field.getVariable() != null) {
|
|
||||||
// Sets the default value as the answer
|
|
||||||
submitForm.setDefaultAnswer(field.getVariable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sets the new owner of the room
|
|
||||||
List owners = new ArrayList();
|
|
||||||
owners.add("johndoe@jabber.org");
|
|
||||||
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
|
|
||||||
// Send the completed form (with default values) to the server to configure the room
|
|
||||||
muc.sendConfigurationForm(submitForm);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Join a room
|
Join a room
|
||||||
|
|
|
@ -28,6 +28,8 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smackx.iqprivate.PrivateDataManager;
|
import org.jivesoftware.smackx.iqprivate.PrivateDataManager;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,8 +111,8 @@ public final class BookmarkManager {
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public void addBookmarkedConference(String name, String jid, boolean isAutoJoin,
|
public void addBookmarkedConference(String name, BareJid jid, boolean isAutoJoin,
|
||||||
String nickname, String password) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
|
Resourcepart nickname, String password) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
|
||||||
{
|
{
|
||||||
retrieveBookmarks();
|
retrieveBookmarks();
|
||||||
BookmarkedConference bookmark
|
BookmarkedConference bookmark
|
||||||
|
@ -144,12 +146,12 @@ public final class BookmarkManager {
|
||||||
* @throws IllegalArgumentException thrown when the conference being removed is a shared
|
* @throws IllegalArgumentException thrown when the conference being removed is a shared
|
||||||
* conference
|
* conference
|
||||||
*/
|
*/
|
||||||
public void removeBookmarkedConference(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
public void removeBookmarkedConference(BareJid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
retrieveBookmarks();
|
retrieveBookmarks();
|
||||||
Iterator<BookmarkedConference> it = bookmarks.getBookmarkedConferences().iterator();
|
Iterator<BookmarkedConference> it = bookmarks.getBookmarkedConferences().iterator();
|
||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
BookmarkedConference conference = it.next();
|
BookmarkedConference conference = it.next();
|
||||||
if(conference.getJid().equalsIgnoreCase(jid)) {
|
if(conference.getJid().equals(jid)) {
|
||||||
if(conference.isShared()) {
|
if(conference.isShared()) {
|
||||||
throw new IllegalArgumentException("Conference is shared and can't be removed");
|
throw new IllegalArgumentException("Conference is shared and can't be removed");
|
||||||
}
|
}
|
||||||
|
@ -230,6 +232,22 @@ public final class BookmarkManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the service supports bookmarks using private data.
|
||||||
|
*
|
||||||
|
* @return true if the service supports private data, false otherwise.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @see PrivateDataManager#isSupported()
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public boolean isSupported() throws NoResponseException, NotConnectedException,
|
||||||
|
XMPPErrorException, InterruptedException {
|
||||||
|
return privateDataManager.isSupported();
|
||||||
|
}
|
||||||
|
|
||||||
private Bookmarks retrieveBookmarks() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
private Bookmarks retrieveBookmarks() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
synchronized(bookmarkLock) {
|
synchronized(bookmarkLock) {
|
||||||
if(bookmarks == null) {
|
if(bookmarks == null) {
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
package org.jivesoftware.smackx.bookmarks;
|
package org.jivesoftware.smackx.bookmarks;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Respresents a Conference Room bookmarked on the server using XEP-0048 Bookmark Storage XEP.
|
* Respresents a Conference Room bookmarked on the server using XEP-0048 Bookmark Storage XEP.
|
||||||
*
|
*
|
||||||
|
@ -26,17 +29,17 @@ public class BookmarkedConference implements SharedBookmark {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private boolean autoJoin;
|
private boolean autoJoin;
|
||||||
private final String jid;
|
private final BareJid jid;
|
||||||
|
|
||||||
private String nickname;
|
private Resourcepart nickname;
|
||||||
private String password;
|
private String password;
|
||||||
private boolean isShared;
|
private boolean isShared;
|
||||||
|
|
||||||
protected BookmarkedConference(String jid) {
|
protected BookmarkedConference(BareJid jid) {
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BookmarkedConference(String name, String jid, boolean autoJoin, String nickname,
|
protected BookmarkedConference(String name, BareJid jid, boolean autoJoin, Resourcepart nickname,
|
||||||
String password)
|
String password)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -78,7 +81,7 @@ public class BookmarkedConference implements SharedBookmark {
|
||||||
*
|
*
|
||||||
* @return the full JID of this conference room.
|
* @return the full JID of this conference room.
|
||||||
*/
|
*/
|
||||||
public String getJid() {
|
public BareJid getJid() {
|
||||||
return jid;
|
return jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,11 +91,11 @@ public class BookmarkedConference implements SharedBookmark {
|
||||||
*
|
*
|
||||||
* @return the nickname to use when joining, null may be returned.
|
* @return the nickname to use when joining, null may be returned.
|
||||||
*/
|
*/
|
||||||
public String getNickname() {
|
public Resourcepart getNickname() {
|
||||||
return nickname;
|
return nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setNickname(String nickname) {
|
protected void setNickname(Resourcepart nickname) {
|
||||||
this.nickname = nickname;
|
this.nickname = nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +119,7 @@ public class BookmarkedConference implements SharedBookmark {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BookmarkedConference conference = (BookmarkedConference)obj;
|
BookmarkedConference conference = (BookmarkedConference)obj;
|
||||||
return conference.getJid().equalsIgnoreCase(jid);
|
return conference.getJid().equals(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,9 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.bookmarks;
|
package org.jivesoftware.smackx.bookmarks;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
|
import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
|
||||||
import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider;
|
import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
@ -268,7 +271,7 @@ public class Bookmarks implements PrivateData {
|
||||||
private static BookmarkedConference getConferenceStorage(XmlPullParser parser) throws XmlPullParserException, IOException {
|
private static BookmarkedConference getConferenceStorage(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
String name = parser.getAttributeValue("", "name");
|
String name = parser.getAttributeValue("", "name");
|
||||||
String autojoin = parser.getAttributeValue("", "autojoin");
|
String autojoin = parser.getAttributeValue("", "autojoin");
|
||||||
String jid = parser.getAttributeValue("", "jid");
|
BareJid jid = ParserUtils.getBareJidAttribute(parser);
|
||||||
|
|
||||||
BookmarkedConference conf = new BookmarkedConference(jid);
|
BookmarkedConference conf = new BookmarkedConference(jid);
|
||||||
conf.setName(name);
|
conf.setName(name);
|
||||||
|
@ -279,7 +282,8 @@ public class Bookmarks implements PrivateData {
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
if (eventType == XmlPullParser.START_TAG && "nick".equals(parser.getName())) {
|
if (eventType == XmlPullParser.START_TAG && "nick".equals(parser.getName())) {
|
||||||
conf.setNickname(parser.nextText());
|
String nickString = parser.nextText();
|
||||||
|
conf.setNickname(Resourcepart.from(nickString));
|
||||||
}
|
}
|
||||||
else if (eventType == XmlPullParser.START_TAG && "password".equals(parser.getName())) {
|
else if (eventType == XmlPullParser.START_TAG && "password".equals(parser.getName())) {
|
||||||
conf.setPassword(parser.nextText());
|
conf.setPassword(parser.nextText());
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.XMPPError.Condition;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smackx.iqprivate.packet.DefaultPrivateData;
|
import org.jivesoftware.smackx.iqprivate.packet.DefaultPrivateData;
|
||||||
import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
|
import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
|
||||||
|
@ -184,6 +185,51 @@ public final class PrivateDataManager extends Manager {
|
||||||
connection().createPacketCollectorAndSend(privateDataSet).nextResultOrThrow();
|
connection().createPacketCollectorAndSend(privateDataSet).nextResultOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final PrivateData DUMMY_PRIVATE_DATA = new PrivateData() {
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return "smackDummyPrivateData";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return "https://igniterealtime.org/projects/smack/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
return '<' + getElementName() + " xmlns='" + getNamespace() + "'/>";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the service supports private data.
|
||||||
|
*
|
||||||
|
* @return true if the service supports private data, false otherwise.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public boolean isSupported() throws NoResponseException, NotConnectedException,
|
||||||
|
InterruptedException, XMPPErrorException {
|
||||||
|
// This is just a primitive hack, since XEP-49 does not specify a way to determine if the
|
||||||
|
// service supports it
|
||||||
|
try {
|
||||||
|
setPrivateData(DUMMY_PRIVATE_DATA);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XMPPErrorException e) {
|
||||||
|
if (e.getXMPPError().getCondition() == Condition.service_unavailable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An IQ provider to parse IQ results containing private data.
|
* An IQ provider to parse IQ results containing private data.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2015 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.muc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatException.MucConfigurationNotSupported;
|
||||||
|
import org.jivesoftware.smackx.xdata.Form;
|
||||||
|
import org.jivesoftware.smackx.xdata.FormField;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.jid.util.JidUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-User Chat configuration form manager is used to fill out and submit a {@link Form} used to
|
||||||
|
* configure rooms.
|
||||||
|
* <p>
|
||||||
|
* Room configuration needs either be done right after the room is created and still locked. Or at
|
||||||
|
* any later point (see <a href="http://xmpp.org/extensions/xep-0045.html#roomconfig">XEP-45 § 10.2
|
||||||
|
* Subsequent Room Configuration</a>). When done with the configuration, call
|
||||||
|
* {@link #submitConfigurationForm()}.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The manager may not provide all possible configuration options. If you want direct access to the
|
||||||
|
* configuraiton form, use {@link MultiUserChat#getConfigurationForm()} and
|
||||||
|
* {@link MultiUserChat#sendConfigurationForm(Form)}.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class MucConfigFormManager {
|
||||||
|
public static final String MUC_ROOMCONFIG_ROOMOWNERS = "muc#roomconfig_roomowners";
|
||||||
|
|
||||||
|
private final MultiUserChat multiUserChat;
|
||||||
|
private final Form answerForm;
|
||||||
|
private final List<Jid> owners;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new MUC config form manager.
|
||||||
|
* <p>
|
||||||
|
* Note that the answerForm needs to be filled out with the defaults.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param multiUserChat the MUC for this configuration form.
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NoResponseException
|
||||||
|
*/
|
||||||
|
MucConfigFormManager(MultiUserChat multiUserChat) throws NoResponseException,
|
||||||
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
this.multiUserChat = multiUserChat;
|
||||||
|
|
||||||
|
// Set the answer form
|
||||||
|
Form configForm = multiUserChat.getConfigurationForm();
|
||||||
|
this.answerForm = configForm.createAnswerForm();
|
||||||
|
// Add the default answers to the form to submit
|
||||||
|
for (FormField field : configForm.getFields()) {
|
||||||
|
if (field.getType() == FormField.Type.hidden
|
||||||
|
|| StringUtils.isNullOrEmpty(field.getVariable())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
answerForm.setDefaultAnswer(field.getVariable());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the local variables according to the fields found in the answer form
|
||||||
|
if (answerForm.hasField(MUC_ROOMCONFIG_ROOMOWNERS)) {
|
||||||
|
// Set 'owners' to the currently configured owners
|
||||||
|
List<String> ownerStrings = answerForm.getField(MUC_ROOMCONFIG_ROOMOWNERS).getValues();
|
||||||
|
owners = new ArrayList<>(ownerStrings.size());
|
||||||
|
JidUtil.jidsFrom(ownerStrings, owners, null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// roomowners not supported, this should barely be the case
|
||||||
|
owners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsRoomOwners() {
|
||||||
|
return owners != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MucConfigFormManager setRoomOwners(Collection<? extends Jid> newOwners) throws MucConfigurationNotSupported {
|
||||||
|
if (!supportsRoomOwners()) {
|
||||||
|
throw new MucConfigurationNotSupported(MUC_ROOMCONFIG_ROOMOWNERS);
|
||||||
|
}
|
||||||
|
owners.clear();
|
||||||
|
owners.addAll(newOwners);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void submitConfigurationForm() throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||||
|
InterruptedException {
|
||||||
|
if (owners != null) {
|
||||||
|
answerForm.setAnswer(MUC_ROOMCONFIG_ROOMOWNERS, JidUtil.toStringList(owners));
|
||||||
|
}
|
||||||
|
multiUserChat.sendConfigurationForm(answerForm);
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,9 @@ import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
import org.jivesoftware.smackx.iqregister.packet.Registration;
|
import org.jivesoftware.smackx.iqregister.packet.Registration;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatException.MucAlreadyJoinedException;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatException.MucNotJoinedException;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatException.MissingMucCreationAcknowledgeException;
|
||||||
import org.jivesoftware.smackx.muc.packet.Destroy;
|
import org.jivesoftware.smackx.muc.packet.Destroy;
|
||||||
import org.jivesoftware.smackx.muc.packet.MUCAdmin;
|
import org.jivesoftware.smackx.muc.packet.MUCAdmin;
|
||||||
import org.jivesoftware.smackx.muc.packet.MUCInitialPresence;
|
import org.jivesoftware.smackx.muc.packet.MUCInitialPresence;
|
||||||
|
@ -354,25 +357,30 @@ public class MultiUserChat {
|
||||||
* the room. {@link #sendConfigurationForm(Form)}
|
* the room. {@link #sendConfigurationForm(Form)}
|
||||||
*
|
*
|
||||||
* @param nickname the nickname to use.
|
* @param nickname the nickname to use.
|
||||||
|
* @return a handle to the MUC create configuration form API.
|
||||||
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
|
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
|
||||||
* the user is not allowed to create the room)
|
* the user is not allowed to create the room)
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws SmackException If the creation failed because of a missing acknowledge from the
|
|
||||||
* server, e.g. because the room already existed.
|
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws MucAlreadyJoinedException
|
||||||
|
* @throws MissingMucCreationAcknowledgeException
|
||||||
*/
|
*/
|
||||||
public synchronized void create(Resourcepart nickname) throws NoResponseException, XMPPErrorException, SmackException, InterruptedException {
|
public synchronized MucCreateConfigFormHandle create(Resourcepart nickname) throws NoResponseException,
|
||||||
|
XMPPErrorException, InterruptedException, MucAlreadyJoinedException,
|
||||||
|
NotConnectedException, MissingMucCreationAcknowledgeException {
|
||||||
if (joined) {
|
if (joined) {
|
||||||
throw new IllegalStateException("Creation failed - User already joined the room.");
|
throw new MucAlreadyJoinedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createOrJoin(nickname)) {
|
MucCreateConfigFormHandle mucCreateConfigFormHandle = createOrJoin(nickname);
|
||||||
|
if (mucCreateConfigFormHandle != null) {
|
||||||
// We successfully created a new room
|
// We successfully created a new room
|
||||||
return;
|
return mucCreateConfigFormHandle;
|
||||||
}
|
}
|
||||||
// We need to leave the room since it seems that the room already existed
|
// We need to leave the room since it seems that the room already existed
|
||||||
leave();
|
leave();
|
||||||
throw new SmackException("Creation failed - Missing acknowledge of room creation.");
|
throw new MissingMucCreationAcknowledgeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -380,15 +388,16 @@ public class MultiUserChat {
|
||||||
* discussion history and using the connections default reply timeout.
|
* discussion history and using the connections default reply timeout.
|
||||||
*
|
*
|
||||||
* @param nickname
|
* @param nickname
|
||||||
* @return true if the room creation was acknowledged by the service, false otherwise.
|
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
* @throws XMPPErrorException
|
* @throws XMPPErrorException
|
||||||
* @throws SmackException
|
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws MucAlreadyJoinedException
|
||||||
* @see #createOrJoin(Resourcepart, String, DiscussionHistory, long)
|
* @see #createOrJoin(Resourcepart, String, DiscussionHistory, long)
|
||||||
*/
|
*/
|
||||||
public synchronized boolean createOrJoin(Resourcepart nickname) throws NoResponseException, XMPPErrorException,
|
public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname) throws NoResponseException, XMPPErrorException,
|
||||||
SmackException, InterruptedException {
|
InterruptedException, MucAlreadyJoinedException, NotConnectedException {
|
||||||
return createOrJoin(nickname, null, null, connection.getPacketReplyTimeout());
|
return createOrJoin(nickname, null, null, connection.getPacketReplyTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,16 +411,18 @@ public class MultiUserChat {
|
||||||
* @param password the password to use.
|
* @param password the password to use.
|
||||||
* @param history the amount of discussion history to receive while joining a room.
|
* @param history the amount of discussion history to receive while joining a room.
|
||||||
* @param timeout the amount of time to wait for a reply from the MUC service(in milliseconds).
|
* @param timeout the amount of time to wait for a reply from the MUC service(in milliseconds).
|
||||||
* @return true if the room creation was acknowledged by the service, false otherwise.
|
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
|
||||||
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
|
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
|
||||||
* the user is not allowed to create the room)
|
* the user is not allowed to create the room)
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws MucAlreadyJoinedException if the MUC is already joined
|
||||||
|
* @throws NotConnectedException
|
||||||
*/
|
*/
|
||||||
public synchronized boolean createOrJoin(Resourcepart nickname, String password, DiscussionHistory history, long timeout)
|
public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname, String password, DiscussionHistory history, long timeout)
|
||||||
throws NoResponseException, XMPPErrorException, SmackException, InterruptedException {
|
throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, NotConnectedException {
|
||||||
if (joined) {
|
if (joined) {
|
||||||
throw new IllegalStateException("Creation failed - User already joined the room.");
|
throw new MucAlreadyJoinedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
Presence presence = enter(nickname, password, history, timeout);
|
Presence presence = enter(nickname, password, history, timeout);
|
||||||
|
@ -420,9 +431,78 @@ public class MultiUserChat {
|
||||||
MUCUser mucUser = MUCUser.from(presence);
|
MUCUser mucUser = MUCUser.from(presence);
|
||||||
if (mucUser != null && mucUser.getStatus().contains(Status.ROOM_CREATED_201)) {
|
if (mucUser != null && mucUser.getStatus().contains(Status.ROOM_CREATED_201)) {
|
||||||
// Room was created and the user has joined the room
|
// Room was created and the user has joined the room
|
||||||
return true;
|
return new MucCreateConfigFormHandle();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle used to configure a newly created room. As long as the room is not configured it will be locked, which
|
||||||
|
* means that no one is able to join. The room will become unlocked as soon it got configured. In order to create an
|
||||||
|
* instant room, use {@link #makeInstant()}.
|
||||||
|
* <p>
|
||||||
|
* For advanced configuration options, use {@link MultiUserChat#getConfigurationForm()}, get the answer form with
|
||||||
|
* {@link Form#createAnswerForm()}, fill it out and send it back to the room with
|
||||||
|
* {@link MultiUserChat#sendConfigurationForm(Form)}.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class MucCreateConfigFormHandle {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instant room. The default configuration will be accepted and the room will become unlocked, i.e.
|
||||||
|
* other users are able to join.
|
||||||
|
*
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @see <a href="http://www.xmpp.org/extensions/xep-0045.html#createroom-instant">XEP-45 § 10.1.2 Creating an
|
||||||
|
* Instant Room</a>
|
||||||
|
*/
|
||||||
|
public void makeInstant() throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||||
|
InterruptedException {
|
||||||
|
sendConfigurationForm(new Form(DataForm.Type.submit));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for {@link MultiUserChat#getConfigFormManager()}.
|
||||||
|
*
|
||||||
|
* @return a MUC configuration form manager for this room.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @see MultiUserChat#getConfigFormManager()
|
||||||
|
*/
|
||||||
|
public MucConfigFormManager getConfigFormManager() throws NoResponseException,
|
||||||
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
return MultiUserChat.this.getConfigFormManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or join a MUC if it is necessary, i.e. if not the MUC is not already joined.
|
||||||
|
*
|
||||||
|
* @param nickname the required nickname to use.
|
||||||
|
* @param password the optional password required to join
|
||||||
|
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public MucCreateConfigFormHandle createOrJoinIfNecessary(Resourcepart nickname, String password) throws NoResponseException,
|
||||||
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
if (isJoined()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return createOrJoin(nickname, password, null, connection.getPacketReplyTimeout());
|
||||||
|
}
|
||||||
|
catch (MucAlreadyJoinedException e) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -466,10 +546,11 @@ public class MultiUserChat {
|
||||||
* 404 error can occur if the room does not exist or is locked; or a
|
* 404 error can occur if the room does not exist or is locked; or a
|
||||||
* 407 error can occur if user is not on the member list; or a
|
* 407 error can occur if user is not on the member list; or a
|
||||||
* 409 error can occur if someone is already in the group chat with the same nickname.
|
* 409 error can occur if someone is already in the group chat with the same nickname.
|
||||||
* @throws SmackException if there was no response from the server.
|
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws NoResponseException if there was no response from the server.
|
||||||
*/
|
*/
|
||||||
public void join(Resourcepart nickname, String password) throws XMPPErrorException, SmackException, InterruptedException {
|
public void join(Resourcepart nickname, String password) throws XMPPErrorException, InterruptedException, NoResponseException, NotConnectedException {
|
||||||
join(nickname, password, null, connection.getPacketReplyTimeout());
|
join(nickname, password, null, connection.getPacketReplyTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +628,25 @@ public class MultiUserChat {
|
||||||
userHasLeft();
|
userHasLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link MucConfigFormManager} to configure this room.
|
||||||
|
* <p>
|
||||||
|
* Only room owners are able to configure a room.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return a MUC configuration form manager for this room.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0045.html#roomconfig">XEP-45 § 10.2 Subsequent Room Configuration</a>
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public MucConfigFormManager getConfigFormManager() throws NoResponseException,
|
||||||
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
return new MucConfigFormManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the room's configuration form that the room's owner can use or <tt>null</tt> if
|
* Returns the room's configuration form that the room's owner can use or <tt>null</tt> if
|
||||||
* no configuration is possible. The configuration form allows to set the room's language,
|
* no configuration is possible. The configuration form allows to set the room's language,
|
||||||
|
@ -570,14 +670,13 @@ public class MultiUserChat {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the completed configuration form to the server. The room will be configured
|
* Sends the completed configuration form to the server. The room will be configured
|
||||||
* with the new settings defined in the form. If the form is empty then the server
|
* with the new settings defined in the form.
|
||||||
* will create an instant room (will use default configuration).
|
|
||||||
*
|
*
|
||||||
* @param form the form with the new settings.
|
* @param form the form with the new settings.
|
||||||
* @throws XMPPErrorException if an error occurs setting the new rooms' configuration.
|
* @throws XMPPErrorException if an error occurs setting the new rooms' configuration.
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public void sendConfigurationForm(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
public void sendConfigurationForm(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
MUCOwner iq = new MUCOwner();
|
MUCOwner iq = new MUCOwner();
|
||||||
|
@ -868,13 +967,14 @@ public class MultiUserChat {
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws MucNotJoinedException
|
||||||
*/
|
*/
|
||||||
public void changeNickname(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
public void changeNickname(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, MucNotJoinedException {
|
||||||
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
||||||
// Check that we already have joined the room before attempting to change the
|
// Check that we already have joined the room before attempting to change the
|
||||||
// nickname.
|
// nickname.
|
||||||
if (!joined) {
|
if (!joined) {
|
||||||
throw new IllegalStateException("Must be logged into the room to change nickname.");
|
throw new MucNotJoinedException(this);
|
||||||
}
|
}
|
||||||
final FullJid jid = JidCreate.fullFrom(room, nickname);
|
final FullJid jid = JidCreate.fullFrom(room, nickname);
|
||||||
// We change the nickname by sending a presence packet where the "to"
|
// We change the nickname by sending a presence packet where the "to"
|
||||||
|
@ -905,14 +1005,14 @@ public class MultiUserChat {
|
||||||
* @param mode the mode type for the presence update.
|
* @param mode the mode type for the presence update.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws MucNotJoinedException
|
||||||
*/
|
*/
|
||||||
public void changeAvailabilityStatus(String status, Presence.Mode mode) throws NotConnectedException, InterruptedException {
|
public void changeAvailabilityStatus(String status, Presence.Mode mode) throws NotConnectedException, InterruptedException, MucNotJoinedException {
|
||||||
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
||||||
// Check that we already have joined the room before attempting to change the
|
// Check that we already have joined the room before attempting to change the
|
||||||
// availability status.
|
// availability status.
|
||||||
if (!joined) {
|
if (!joined) {
|
||||||
throw new IllegalStateException(
|
throw new MucNotJoinedException(this);
|
||||||
"Must be logged into the room to change the " + "availability status.");
|
|
||||||
}
|
}
|
||||||
// We change the availability status by sending a presence packet to the room with the
|
// We change the availability status by sending a presence packet to the room with the
|
||||||
// new presence status and mode
|
// new presence status and mode
|
||||||
|
@ -1689,11 +1789,11 @@ public class MultiUserChat {
|
||||||
*
|
*
|
||||||
* @return the next message if one is immediately available and
|
* @return the next message if one is immediately available and
|
||||||
* <tt>null</tt> otherwise.
|
* <tt>null</tt> otherwise.
|
||||||
* @throws MUCNotJoinedException
|
* @throws MucNotJoinedException
|
||||||
*/
|
*/
|
||||||
public Message pollMessage() throws MUCNotJoinedException {
|
public Message pollMessage() throws MucNotJoinedException {
|
||||||
if (messageCollector == null) {
|
if (messageCollector == null) {
|
||||||
throw new MUCNotJoinedException(this);
|
throw new MucNotJoinedException(this);
|
||||||
}
|
}
|
||||||
return messageCollector.pollResult();
|
return messageCollector.pollResult();
|
||||||
}
|
}
|
||||||
|
@ -1703,12 +1803,12 @@ public class MultiUserChat {
|
||||||
* (not return) until a message is available.
|
* (not return) until a message is available.
|
||||||
*
|
*
|
||||||
* @return the next message.
|
* @return the next message.
|
||||||
* @throws MUCNotJoinedException
|
* @throws MucNotJoinedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public Message nextMessage() throws MUCNotJoinedException, InterruptedException {
|
public Message nextMessage() throws MucNotJoinedException, InterruptedException {
|
||||||
if (messageCollector == null) {
|
if (messageCollector == null) {
|
||||||
throw new MUCNotJoinedException(this);
|
throw new MucNotJoinedException(this);
|
||||||
}
|
}
|
||||||
return messageCollector.nextResult();
|
return messageCollector.nextResult();
|
||||||
}
|
}
|
||||||
|
@ -1721,12 +1821,12 @@ public class MultiUserChat {
|
||||||
* @param timeout the maximum amount of time to wait for the next message.
|
* @param timeout the maximum amount of time to wait for the next message.
|
||||||
* @return the next message, or <tt>null</tt> if the timeout elapses without a
|
* @return the next message, or <tt>null</tt> if the timeout elapses without a
|
||||||
* message becoming available.
|
* message becoming available.
|
||||||
* @throws MUCNotJoinedException
|
* @throws MucNotJoinedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public Message nextMessage(long timeout) throws MUCNotJoinedException, InterruptedException {
|
public Message nextMessage(long timeout) throws MucNotJoinedException, InterruptedException {
|
||||||
if (messageCollector == null) {
|
if (messageCollector == null) {
|
||||||
throw new MUCNotJoinedException(this);
|
throw new MucNotJoinedException(this);
|
||||||
}
|
}
|
||||||
return messageCollector.nextResult(timeout);
|
return messageCollector.nextResult(timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2014-2015 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.muc;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
|
||||||
|
public abstract class MultiUserChatException extends SmackException {
|
||||||
|
|
||||||
|
protected MultiUserChatException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MultiUserChatException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
// This could eventually become an unchecked exception. But be aware that it's required in the
|
||||||
|
// control flow of MultiUserChat.createOrJoinIfNecessary
|
||||||
|
public static class MucAlreadyJoinedException extends MultiUserChatException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if the requested operation required the MUC to be joined by the
|
||||||
|
* client, while the client is currently joined.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class MucNotJoinedException extends MultiUserChatException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public MucNotJoinedException(MultiUserChat multiUserChat) {
|
||||||
|
super("Client not currently joined " + multiUserChat.getRoom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MissingMucCreationAcknowledgeException extends MultiUserChatException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if the MUC room does not support the requested configuration option.
|
||||||
|
*/
|
||||||
|
public static class MucConfigurationNotSupported extends MultiUserChatException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public MucConfigurationNotSupported(String configString) {
|
||||||
|
super("The MUC configuration '" + configString + "' is not supported by the MUC service");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2015 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.muc.bookmarkautojoin;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smackx.bookmarks.BookmarkManager;
|
||||||
|
import org.jivesoftware.smackx.bookmarks.BookmarkedConference;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatManager;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autojoin bookmarked Multi-User Chat conferences.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0048.html">XEP-48: Bookmarks</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class MucBookmarkAutojoinManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(MucBookmarkAutojoinManager.class.getName());
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, MucBookmarkAutojoinManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
private static boolean autojoinEnabledDefault = false;
|
||||||
|
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
@Override
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setAutojoinPerDefault(boolean autojoin) {
|
||||||
|
autojoinEnabledDefault = autojoin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized MucBookmarkAutojoinManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
MucBookmarkAutojoinManager mbam = INSTANCES.get(connection);
|
||||||
|
if (mbam == null) {
|
||||||
|
mbam = new MucBookmarkAutojoinManager(connection);
|
||||||
|
INSTANCES.put(connection, mbam);
|
||||||
|
}
|
||||||
|
return mbam;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MultiUserChatManager multiUserChatManager;
|
||||||
|
private final BookmarkManager bookmarkManager;
|
||||||
|
|
||||||
|
private boolean autojoinEnabled = autojoinEnabledDefault;
|
||||||
|
|
||||||
|
private MucBookmarkAutojoinManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
multiUserChatManager = MultiUserChatManager.getInstanceFor(connection);
|
||||||
|
bookmarkManager = BookmarkManager.getBookmarkManager(connection);
|
||||||
|
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||||
|
@Override
|
||||||
|
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||||
|
if (!autojoinEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO handle resumed case?
|
||||||
|
autojoinBookmarkedConferences();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutojoinEnabled(boolean autojoin) {
|
||||||
|
autojoinEnabled = autojoin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void autojoinBookmarkedConferences() {
|
||||||
|
List<BookmarkedConference> bookmarkedConferences;
|
||||||
|
try {
|
||||||
|
bookmarkedConferences = bookmarkManager.getBookmarkedConferences();
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.FINER, "Could not get MUC bookmarks", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not get MUC bookmarks", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
Resourcepart defaultNick = connection.getUser().getResourcepart();
|
||||||
|
|
||||||
|
for (BookmarkedConference bookmarkedConference : bookmarkedConferences) {
|
||||||
|
if (!bookmarkedConference.isAutoJoin()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Resourcepart nick = bookmarkedConference.getNickname();
|
||||||
|
if (nick == null) {
|
||||||
|
nick = defaultNick;
|
||||||
|
}
|
||||||
|
String password = bookmarkedConference.getPassword();
|
||||||
|
MultiUserChat muc = multiUserChatManager.getMultiUserChat(bookmarkedConference.getJid());
|
||||||
|
try {
|
||||||
|
MucCreateConfigFormHandle handle = muc.createOrJoinIfNecessary(nick, password);
|
||||||
|
if (handle != null) {
|
||||||
|
handle.makeInstant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.FINER, "Could not autojoin bookmarked MUC", e);
|
||||||
|
// abort here
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException e) {
|
||||||
|
// Do no abort, just log,
|
||||||
|
LOGGER.log(Level.WARNING, "Could not autojoin bookmarked MUC", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2014 Florian Schmaus
|
* Copyright 2015 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,23 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.muc;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if the requested operation required the MUC to be joined by the
|
* Manager to autojoin bookmarked Multi-User Chat conferences.
|
||||||
* client, while the client is currently joined.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MUCNotJoinedException extends SmackException {
|
package org.jivesoftware.smackx.muc.bookmarkautojoin;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -5204934585663465576L;
|
|
||||||
|
|
||||||
public MUCNotJoinedException(MultiUserChat multiUserChat) {
|
|
||||||
super("Client not currently joined " + multiUserChat.getRoom());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -353,6 +353,17 @@ public class Form {
|
||||||
return dataForm.getField(variable);
|
return dataForm.getField(variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a field with the given variable exists.
|
||||||
|
*
|
||||||
|
* @param variable the variable to check for.
|
||||||
|
* @return true if a field with the variable exists, false otherwise.
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public boolean hasField(String variable) {
|
||||||
|
return dataForm.hasField(variable);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the instructions that explain how to fill out the form and what the form is about.
|
* Returns the instructions that explain how to fill out the form and what the form is about.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<className>org.jivesoftware.smackx.disco.ServiceDiscoveryManager</className>
|
<className>org.jivesoftware.smackx.disco.ServiceDiscoveryManager</className>
|
||||||
<className>org.jivesoftware.smackx.xhtmlim.XHTMLManager</className>
|
<className>org.jivesoftware.smackx.xhtmlim.XHTMLManager</className>
|
||||||
<className>org.jivesoftware.smackx.muc.MultiUserChatManager</className>
|
<className>org.jivesoftware.smackx.muc.MultiUserChatManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.muc.bookmarkautojoin.MucBookmarkAutojoinManager</className>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>
|
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager</className>
|
<className>org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager</className>
|
||||||
<className>org.jivesoftware.smackx.filetransfer.FileTransferManager</className>
|
<className>org.jivesoftware.smackx.filetransfer.FileTransferManager</className>
|
||||||
|
|
|
@ -30,8 +30,7 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smackx.xdata.Form;
|
import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle;
|
||||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
@ -82,9 +81,9 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
boolean newlyCreated = mucAsSeenByOne.createOrJoin(Resourcepart.from("one-" + randomString));
|
MucCreateConfigFormHandle handle = mucAsSeenByOne.createOrJoin(Resourcepart.from("one-" + randomString));
|
||||||
if (newlyCreated) {
|
if (handle != null) {
|
||||||
mucAsSeenByOne.sendConfigurationForm(new Form(DataForm.Type.submit));
|
handle.makeInstant();
|
||||||
}
|
}
|
||||||
mucAsSeenByTwo.join(Resourcepart.from("two-" + randomString));
|
mucAsSeenByTwo.join(Resourcepart.from("two-" + randomString));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2015 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.muc;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.igniterealtime.smack.inttest.AbstractSmackLowLevelIntegrationTest;
|
||||||
|
import org.igniterealtime.smack.inttest.Configuration;
|
||||||
|
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||||
|
import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smackx.bookmarks.BookmarkManager;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle;
|
||||||
|
import org.jivesoftware.smackx.muc.bookmarkautojoin.MucBookmarkAutojoinManager;
|
||||||
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.jxmpp.jid.parts.Localpart;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
|
public class MultiUserChatLowLevelIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
|
public MultiUserChatLowLevelIntegrationTest(Configuration configuration, String testRunId) throws Exception {
|
||||||
|
super(configuration, testRunId);
|
||||||
|
performCheck(new ConnectionCallback() {
|
||||||
|
@Override
|
||||||
|
public void connectionCallback(XMPPTCPConnection connection) throws Exception {
|
||||||
|
if (MultiUserChatManager.getInstanceFor(connection).getServiceNames().isEmpty()) {
|
||||||
|
throw new TestNotPossibleException("MUC component not offered by service");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmackIntegrationTest
|
||||||
|
public void testMucBookmarksAutojoin(XMPPTCPConnection connection) throws InterruptedException,
|
||||||
|
TestNotPossibleException, XMPPException, SmackException, IOException {
|
||||||
|
final BookmarkManager bookmarkManager = BookmarkManager.getBookmarkManager(connection);
|
||||||
|
if (!bookmarkManager.isSupported()) {
|
||||||
|
throw new TestNotPossibleException("Private data storage not supported");
|
||||||
|
}
|
||||||
|
final MultiUserChatManager multiUserChatManager = MultiUserChatManager.getInstanceFor(connection);
|
||||||
|
final Resourcepart mucNickname = Resourcepart.from("Nick-" + StringUtils.randomString(6));
|
||||||
|
final String randomMucName = StringUtils.randomString(6);
|
||||||
|
final DomainBareJid mucComponent = multiUserChatManager.getServiceNames().get(0);
|
||||||
|
final MultiUserChat muc = multiUserChatManager.getMultiUserChat(JidCreate.bareFrom(
|
||||||
|
Localpart.from(randomMucName), mucComponent));
|
||||||
|
|
||||||
|
MucCreateConfigFormHandle handle = muc.createOrJoin(mucNickname);
|
||||||
|
if (handle != null) {
|
||||||
|
handle.makeInstant();
|
||||||
|
}
|
||||||
|
muc.leave();
|
||||||
|
|
||||||
|
bookmarkManager.addBookmarkedConference("Smack Inttest: " + testRunId, muc.getRoom(), true,
|
||||||
|
mucNickname, null);
|
||||||
|
|
||||||
|
connection.disconnect();
|
||||||
|
connection.connect().login();
|
||||||
|
|
||||||
|
// MucBookmarkAutojoinManager is also able to do its task automatically
|
||||||
|
// after every login, it's not determinstic when this will be finished.
|
||||||
|
// So we trigger it manually here.
|
||||||
|
MucBookmarkAutojoinManager.getInstanceFor(connection).autojoinBookmarkedConferences();
|
||||||
|
|
||||||
|
assertTrue(muc.isJoined());
|
||||||
|
|
||||||
|
// If the test went well, leave the MUC
|
||||||
|
muc.leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ allprojects {
|
||||||
ext {
|
ext {
|
||||||
shortVersion = '4.2.0-alpha2'
|
shortVersion = '4.2.0-alpha2'
|
||||||
isSnapshot = true
|
isSnapshot = true
|
||||||
jxmppVersion = '0.5.0-alpha2'
|
jxmppVersion = '0.5.0-alpha3'
|
||||||
smackMinAndroidSdk = 8
|
smackMinAndroidSdk = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue