mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-22 20:47:57 +01:00
Add support for XEP-0221: Data Forms Media Element
Fixes SMACK-824.
This commit is contained in:
parent
832b20a897
commit
c0183775fe
9 changed files with 428 additions and 0 deletions
|
@ -68,6 +68,7 @@ Smack Extensions and currently supported XEPs of smack-extensions
|
|||
| Entity Time | [XEP-0202](https://xmpp.org/extensions/xep-0202.html) | n/a | Allows entities to communicate their local time |
|
||||
| Delayed Delivery | [XEP-0203](https://xmpp.org/extensions/xep-0203.html) | n/a | Extension for communicating the fact that an XML stanza has been delivered with a delay. |
|
||||
| XMPP Over BOSH | [XEP-0206](https://xmpp.org/extensions/xep-0206.html) | n/a | Use Bidirectional-streams Over Synchronous HTTP (BOSH) to transport XMPP stanzas. |
|
||||
| Data Forms Media Element | [XEP-0221](https://xmpp.org/extensions/xep-0221.html) | n/a | Allows to include media data in XEP-0004 data forms. |
|
||||
| Attention | [XEP-0224](https://xmpp.org/extensions/xep-0224.html) | n/a | Getting attention of another user. |
|
||||
| Bits of Binary | [XEP-0231](https://xmpp.org/extensions/xep-0231.html) | n/a | Including or referring to small bits of binary data in an XML stanza. |
|
||||
| Best Practices for Resource Locking | [XEP-0296](https://xmpp.org/extensions/xep-0296.html) | n/a | Specifies best practices to be followed by Jabber/XMPP clients about when to lock into, and unlock away from, resources. |
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.mediaelement;
|
||||
|
||||
import org.jivesoftware.smackx.mediaelement.provider.MediaElementProvider;
|
||||
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProviderManager;
|
||||
|
||||
public class MediaElementManager {
|
||||
|
||||
static {
|
||||
FormFieldChildElementProviderManager.addFormFieldChildElementProvider(new MediaElementProvider());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.mediaelement.element;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.jivesoftware.smack.packet.FullyQualifiedElement;
|
||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||
import org.jivesoftware.smack.util.NumberUtil;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.FormFieldChildElement;
|
||||
|
||||
public class MediaElement implements FormFieldChildElement {
|
||||
|
||||
public static final String ELEMENT = "media";
|
||||
|
||||
public static final String NAMESPACE = "urn:xmpp:media-element";
|
||||
|
||||
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
|
||||
|
||||
private final int height;
|
||||
|
||||
private final int width;
|
||||
|
||||
private final List<Uri> uris;
|
||||
|
||||
public MediaElement(Builder builder) {
|
||||
this.height = builder.height;
|
||||
this.width = builder.width;
|
||||
this.uris = Collections.unmodifiableList(builder.uris);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public List<Uri> getUris() {
|
||||
return uris;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QName getQName() {
|
||||
return QNAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
|
||||
XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment);
|
||||
xml.optIntAttribute("height", height)
|
||||
.optIntAttribute("width", width)
|
||||
.rightAngleBracket();
|
||||
|
||||
xml.append(uris, xmlEnvironment);
|
||||
|
||||
xml.closeElement(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public MediaElement from(FormField formField) {
|
||||
return (MediaElement) formField.getFormFieldChildElement(QNAME);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private int height, width;
|
||||
|
||||
private List<Uri> uris = new ArrayList<>();
|
||||
|
||||
public Builder setHeightAndWidth(int height, int width) {
|
||||
this.height = NumberUtil.requireUShort16(height);
|
||||
this.width = NumberUtil.requireUShort16(width);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addUri(URI uri, String type) {
|
||||
return addUri(new Uri(uri, type));
|
||||
}
|
||||
|
||||
public Builder addUri(Uri uri) {
|
||||
uris.add(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MediaElement build() {
|
||||
return new MediaElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Uri implements FullyQualifiedElement {
|
||||
public static final String ELEMENT = "uri";
|
||||
|
||||
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
|
||||
|
||||
private final URI uri;
|
||||
private final String type;
|
||||
|
||||
public Uri(URI uri, String type) {
|
||||
this.uri = Objects.requireNonNull(uri);
|
||||
this.type = StringUtils.requireNotNullNorEmpty(type, "The 'type' argument must not be null or empty");
|
||||
}
|
||||
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QName getQName() {
|
||||
return QNAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
|
||||
XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment);
|
||||
xml.attribute("type", type)
|
||||
.rightAngleBracket();
|
||||
xml.escape(uri.toString());
|
||||
xml.closeElement(this);
|
||||
return xml;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Element classes for XEP-0221: Data Forms Media Element.
|
||||
*/
|
||||
package org.jivesoftware.smackx.mediaelement.element;
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smacks implementation of XEP-0221: Data Forms Media Element.
|
||||
*/
|
||||
package org.jivesoftware.smackx.mediaelement;
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.mediaelement.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||
import org.jivesoftware.smack.parsing.SmackParsingException.SmackUriSyntaxParsingException;
|
||||
import org.jivesoftware.smack.util.ParserUtils;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||
|
||||
import org.jivesoftware.smackx.mediaelement.element.MediaElement;
|
||||
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProvider;
|
||||
|
||||
public class MediaElementProvider extends FormFieldChildElementProvider<MediaElement> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(MediaElementProvider.class.getName());
|
||||
|
||||
@Override
|
||||
public QName getQName() {
|
||||
return MediaElement.QNAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws IOException, XmlPullParserException, SmackUriSyntaxParsingException {
|
||||
Integer height = ParserUtils.getIntegerAttribute(parser, "height");
|
||||
Integer width = ParserUtils.getIntegerAttribute(parser, "width");
|
||||
|
||||
MediaElement.Builder mediaElementBuilder = MediaElement.builder();
|
||||
if (height != null && width != null) {
|
||||
mediaElementBuilder.setHeightAndWidth(height, width);
|
||||
} else if (height != null || width != null) {
|
||||
LOGGER.warning("Only one of height and width set while parsing media element");
|
||||
}
|
||||
|
||||
outerloop: while (true) {
|
||||
XmlPullParser.TagEvent event = parser.nextTag();
|
||||
switch (event) {
|
||||
case START_ELEMENT:
|
||||
QName qname = parser.getQName();
|
||||
if (qname.equals(MediaElement.Uri.QNAME)) {
|
||||
MediaElement.Uri uri = parseUri(parser);
|
||||
mediaElementBuilder.addUri(uri);
|
||||
}
|
||||
break;
|
||||
case END_ELEMENT:
|
||||
if (parser.getDepth() == initialDepth) {
|
||||
break outerloop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mediaElementBuilder.build();
|
||||
}
|
||||
|
||||
private MediaElement.Uri parseUri(XmlPullParser parser)
|
||||
throws SmackUriSyntaxParsingException, XmlPullParserException, IOException {
|
||||
String type = parser.getAttributeValue("type");
|
||||
URI uri = ParserUtils.getUriFromNextText(parser);
|
||||
return new MediaElement.Uri(uri, type);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provider classes for XEP-0221: Data Forms Media Element.
|
||||
*/
|
||||
package org.jivesoftware.smackx.mediaelement.provider;
|
|
@ -2,6 +2,7 @@
|
|||
<startupClasses>
|
||||
<className>org.jivesoftware.smackx.disco.ServiceDiscoveryManager</className>
|
||||
<className>org.jivesoftware.smackx.xhtmlim.XHTMLManager</className>
|
||||
<className>org.jivesoftware.smackx.mediaelement.MediaElementManager</className>
|
||||
<className>org.jivesoftware.smackx.muc.MultiUserChatManager</className>
|
||||
<className>org.jivesoftware.smackx.muc.bookmarkautojoin.MucBookmarkAutojoinManager</className>
|
||||
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.mediaelement.provider;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||
import org.jivesoftware.smack.test.util.SmackTestUtil;
|
||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||
|
||||
import org.jivesoftware.smackx.mediaelement.element.MediaElement;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
|
||||
public class MediaElementProviderTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
|
||||
public void simpleMediaElementTest(SmackTestUtil.XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException {
|
||||
final String xml =
|
||||
"<media xmlns='urn:xmpp:media-element' height='80' width='290'>" +
|
||||
"<uri type='audio/x-wav'>" +
|
||||
"http://victim.example.com/challenges/speech.wav?F3A6292C" +
|
||||
"</uri>" +
|
||||
"</media>";
|
||||
|
||||
MediaElement mediaElement = SmackTestUtil.parse(xml, MediaElementProvider.class, parserKind);
|
||||
assertEquals(80, mediaElement.getHeight());
|
||||
assertEquals(290, mediaElement.getWidth());
|
||||
|
||||
List<MediaElement.Uri> uris = mediaElement.getUris();
|
||||
assertEquals(1, uris.size());
|
||||
|
||||
MediaElement.Uri uri = uris.get(0);
|
||||
assertEquals("audio/x-wav", uri.getType());
|
||||
assertEquals("http://victim.example.com/challenges/speech.wav?F3A6292C", uri.getUri().toString());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
|
||||
public void parseMediaElementTest(SmackTestUtil.XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException {
|
||||
final String xml =
|
||||
"<media xmlns='urn:xmpp:media-element'>" +
|
||||
"<uri type='audio/x-wav'>" +
|
||||
"http://victim.example.com/challenges/speech.wav?F3A6292C" +
|
||||
"</uri>" +
|
||||
"<uri type='audio/ogg; codecs=speex'>" +
|
||||
"cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org" +
|
||||
"</uri>" +
|
||||
"<uri type='audio/mpeg'>" +
|
||||
"http://victim.example.com/challenges/speech.mp3?F3A6292C" +
|
||||
"</uri>" +
|
||||
"</media>";
|
||||
|
||||
MediaElement mediaElement = SmackTestUtil.parse(xml, MediaElementProvider.class, parserKind);
|
||||
|
||||
List<MediaElement.Uri> uris = mediaElement.getUris();
|
||||
assertEquals(3, uris.size());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue