Merge pull request #359 from vanitasvitae/messageRetraction

XEP-0424: Message Retraction
This commit is contained in:
Florian Schmaus 2020-05-14 22:34:37 +02:00 committed by GitHub
commit 17161dd3ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 527 additions and 0 deletions

View File

@ -122,6 +122,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
| [Message Markup](messagemarkup.md) | [XEP-0394](https://xmpp.org/extensions/xep-0394.html) | 0.1.0 | Style message bodies while keeping body and markup information separated. |
| DNS Queries over XMPP (DoX) | [XEP-0418](https://xmpp.org/extensions/xep-0418.html) | 0.1.0 | Send DNS queries and responses over XMPP. |
| Message Fastening | [XEP-0422](https://xmpp.org/extensions/xep-0422.html) | 0.1.1 | Mark payloads on a message to be logistically fastened to a previous message. |
| Message Retraction | [XEP-0424](https://xmpp.org/extensions/xep-0424.html) | 0.2.0 | Mark messages as retracted. |
| Fallback Indication | [XEP-0428](https://xmpp.org/extensions/xep-0428.html) | 0.1.0 | Declare body elements of a message as ignorable fallback for naive legacy clients. |
Unofficial XMPP Extensions

View File

@ -0,0 +1,128 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction;
import java.util.Map;
import java.util.WeakHashMap;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.message_fastening.element.FasteningElement;
import org.jivesoftware.smackx.message_retraction.element.RetractElement;
import org.jivesoftware.smackx.sid.element.OriginIdElement;
/**
* Smacks API for XEP-0424: Message Retraction.
*
* To enable / disable auto-announcing support for this feature, call {@link #setEnabledByDefault(boolean)}.
* Auto-announcing is enabled by default.
*
* To retract a message, call {@link #retractMessage(OriginIdElement)}, passing in the {@link OriginIdElement Origin ID}
* of the message to be retracted.
*/
public final class MessageRetractionManager extends Manager {
private static final Map<XMPPConnection, MessageRetractionManager> INSTANCES = new WeakHashMap<>();
private static boolean ENABLED_BY_DEFAULT = false;
static {
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
@Override
public void connectionCreated(XMPPConnection connection) {
if (ENABLED_BY_DEFAULT) {
getInstanceFor(connection).announceSupport();
}
}
});
}
private MessageRetractionManager(XMPPConnection connection) {
super(connection);
}
public static synchronized MessageRetractionManager getInstanceFor(XMPPConnection connection) {
MessageRetractionManager manager = INSTANCES.get(connection);
if (manager == null) {
manager = new MessageRetractionManager(connection);
INSTANCES.put(connection, manager);
}
return manager;
}
/**
* Enable or disable auto-announcing support for Message Retraction.
* Default is disabled.
*
* @param enabled enabled
*/
public static synchronized void setEnabledByDefault(boolean enabled) {
ENABLED_BY_DEFAULT = enabled;
}
/**
* Announce support for Message Retraction to the server.
*
* @see <a href="https://xmpp.org/extensions/xep-0424.html#disco">XEP-0424: Message Retraction: §2. Discovering Support</a>
*/
public void announceSupport() {
ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(RetractElement.NAMESPACE);
}
/**
* Stop announcing support for Message Retraction.
*/
public void stopAnnouncingSupport() {
ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(RetractElement.NAMESPACE);
}
/**
* Append a {@link RetractElement} wrapped inside a {@link FasteningElement} which contains
* the {@link OriginIdElement Origin-ID} of the message that will be retracted to the given {@link MessageBuilder}.
*
* @param retractedMessageId {@link OriginIdElement OriginID} of the message that the user wants to retract
* @param carrierMessageBuilder message used to transmit the message retraction to the recipient
*/
public void addRetractionElementToMessage(OriginIdElement retractedMessageId, MessageBuilder carrierMessageBuilder) {
FasteningElement fasteningElement = FasteningElement.builder()
.setOriginId(retractedMessageId)
.addWrappedPayload(new RetractElement())
.build();
fasteningElement.applyTo(carrierMessageBuilder);
}
/**
* Retract a message by appending a {@link RetractElement} wrapped inside a {@link FasteningElement} which contains
* the {@link OriginIdElement Origin-ID} of the message that will be retracted to a new message and send it to the
* server.
*
* @param retractedMessageId {@link OriginIdElement OriginID} of the message that the user wants to retract
* @throws SmackException.NotConnectedException in case the connection is not connected.
* @throws InterruptedException if the thread gets interrupted.
*/
public void retractMessage(OriginIdElement retractedMessageId)
throws SmackException.NotConnectedException, InterruptedException {
MessageBuilder message = connection().getStanzaFactory().buildMessageStanza();
addRetractionElementToMessage(retractedMessageId, message);
connection().sendStanza(message.build());
}
}

View File

@ -0,0 +1,44 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.element;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
public class RetractElement implements ExtensionElement {
private static final String NAMESPACE_WITHOUT_VERSION = "urn:xmpp:message-retract";
private static final String NAMESPACE_0 = NAMESPACE_WITHOUT_VERSION + ":0";
public static final String NAMESPACE = NAMESPACE_0;
public static final String ELEMENT = "retract";
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
return new XmlStringBuilder(this).closeEmptyElement();
}
}

View File

@ -0,0 +1,65 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.element;
import java.util.Date;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.sid.element.OriginIdElement;
public class RetractedElement implements ExtensionElement {
public static final String ELEMENT = "retracted";
public static final String ATTR_STAMP = "stamp";
private final Date stamp;
private final OriginIdElement originId;
public RetractedElement(Date stamp, OriginIdElement originId) {
this.stamp = stamp;
this.originId = originId;
}
public Date getStamp() {
return stamp;
}
public OriginIdElement getOriginId() {
return originId;
}
@Override
public String getNamespace() {
return RetractElement.NAMESPACE;
}
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
return new XmlStringBuilder(this)
.attribute(ATTR_STAMP, getStamp())
.rightAngleBracket()
.append(getOriginId())
.closeElement(this);
}
}

View File

@ -0,0 +1,25 @@
/**
*
* Copyright 2019 Paul Schaub
*
* 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.
*/
/**
* XEP-0424: Message Retraction. Element classes.
*
* @see <a href="https://xmpp.org/extensions/xep-0424.html">XEP-0424: Message
* Retraction</a>
*
*/
package org.jivesoftware.smackx.message_retraction.element;

View File

@ -0,0 +1,25 @@
/**
*
* Copyright 2019 Paul Schaub
*
* 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.
*/
/**
* XEP-0424: Message Retraction.
*
* @see <a href="https://xmpp.org/extensions/xep-0424.html">XEP-0424: Message
* Retraction</a>
*
*/
package org.jivesoftware.smackx.message_retraction;

View File

@ -0,0 +1,34 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.provider;
import java.io.IOException;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.message_retraction.element.RetractElement;
public class RetractElementProvider extends ExtensionElementProvider<RetractElement> {
@Override
public RetractElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
return new RetractElement();
}
}

View File

@ -0,0 +1,52 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.provider;
import java.io.IOException;
import java.util.Date;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.message_retraction.element.RetractedElement;
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
import org.jivesoftware.smackx.sid.element.OriginIdElement;
import org.jivesoftware.smackx.sid.provider.OriginIdProvider;
public class RetractedElementProvider extends ExtensionElementProvider<RetractedElement> {
@Override
public RetractedElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
throws XmlPullParserException, IOException, SmackParsingException {
Date date = ParserUtils.getDateFromXep82String(parser.getAttributeValue("", RetractedElement.ATTR_STAMP));
OriginIdElement originIdElement = null;
while (originIdElement == null) {
XmlPullParser.TagEvent tag = parser.nextTag();
if (tag == XmlPullParser.TagEvent.START_ELEMENT
&& OriginIdElement.ELEMENT.equals(parser.getName())
&& StableUniqueStanzaIdManager.NAMESPACE.equals(parser.getNamespace())) {
originIdElement = OriginIdProvider.INSTANCE.parse(parser);
}
}
return new RetractedElement(date, originIdElement);
}
}

View File

@ -0,0 +1,25 @@
/**
*
* Copyright 2019 Paul Schaub
*
* 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.
*/
/**
* XEP-0424: Message Retraction. Provider classes.
*
* @see <a href="https://xmpp.org/extensions/xep-0424.html">XEP-0424: Message
* Retraction</a>
*
*/
package org.jivesoftware.smackx.message_retraction.provider;

View File

@ -299,6 +299,18 @@
<className>org.jivesoftware.smackx.message_fastening.provider.FasteningElementProvider</className>
</extensionProvider>
<!-- XEP-0424: Message Retraction -->
<extensionProvider>
<elementName>retract</elementName>
<namespace>urn:xmpp:message-retract:0</namespace>
<className>org.jivesoftware.smackx.message_retraction.provider.RetractElementProvider</className>
</extensionProvider>
<extensionProvider>
<elementName>retracted</elementName>
<namespace>urn:xmpp:message-retract:0</namespace>
<className>org.jivesoftware.smackx.message_retraction.provider.RetractedElementProvider</className>
</extensionProvider>
<!-- XEP-0428: Fallback Indication -->
<extensionProvider>
<elementName>fallback</elementName>

View File

@ -0,0 +1,52 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.element;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.test.util.SmackTestUtil;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.message_retraction.provider.RetractElementProvider;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
public class RetractElementTest {
@Test
public void serializationTest() {
RetractElement retractElement = new RetractElement();
String expectedXml = "<retract xmlns='urn:xmpp:message-retract:0'/>";
assertXmlSimilar(expectedXml, retractElement.toXML());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void deserializationTest(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
String xml = "<retract xmlns='urn:xmpp:message-retract:0'/>";
RetractElement element = SmackTestUtil.parse(xml, RetractElementProvider.class, parserKind);
assertNotNull(element);
}
}

View File

@ -0,0 +1,64 @@
/**
*
* Copyright 2020 Paul Schaub
*
* 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.message_retraction.element;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.test.util.SmackTestUtil;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.message_retraction.provider.RetractedElementProvider;
import org.jivesoftware.smackx.sid.element.OriginIdElement;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.jxmpp.util.XmppDateTime;
public class RetractedElementTest {
@Test
public void serializationTest() throws ParseException {
Date stamp = XmppDateTime.parseXEP0082Date("2019-09-20T23:08:25.000+00:00");
OriginIdElement originId = new OriginIdElement("origin-id-1");
RetractedElement retractedElement = new RetractedElement(stamp, originId);
String expectedXml = "" +
"<retracted stamp='2019-09-20T23:08:25.000+00:00' xmlns='urn:xmpp:message-retract:0'>\n" +
" <origin-id xmlns='urn:xmpp:sid:0' id='origin-id-1'/>\n" +
"</retracted>";
assertXmlSimilar(expectedXml, retractedElement.toXML());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void deserializationTest(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
String xml = "" +
"<retracted stamp='2019-09-20T23:08:25.000+00:00' xmlns='urn:xmpp:message-retract:0'>\n" +
" <origin-id xmlns='urn:xmpp:sid:0' id='origin-id-1'/>\n" +
"</retracted>";
RetractedElement element = SmackTestUtil.parse(xml, RetractedElementProvider.class, parserKind);
assertNotNull(element.getOriginId());
}
}