diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 14d7c0e90..f1c0b9015 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -172,14 +172,15 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { client = BOSHClient.create(cfgBuilder.build()); - client.addBOSHClientConnListener(new BOSHConnectionListener()); - client.addBOSHClientResponseListener(new BOSHPacketReader()); - - // Initialize the debugger + // Initialize the debugger before addBOSHClientResponseListener(new BOSHPacketReader()); + // BOSHPacketReader may hold and send response prior to display of the request i.e. before if (debugger != null) { initDebugger(); } + client.addBOSHClientConnListener(new BOSHConnectionListener()); + client.addBOSHClientResponseListener(new BOSHPacketReader()); + // Send the session creation request client.send(ComposableBody.builder() .setNamespaceDefinition("xmpp", XMPP_BOSH_NS) @@ -359,10 +360,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { CloseableUtil.maybeClose(reader, LOGGER); CloseableUtil.maybeClose(writer, LOGGER); + // set readerConsumer = null before reader to avoid NPE reference + readerConsumer = null; readerPipe = null; reader = null; writer = null; - readerConsumer = null; } /** @@ -440,6 +442,8 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { if (event.getBody() != null) { try { writer.write(event.getBody().toXML()); + // Fix all BOSH sent debug messages not shown + writer.flush(); } catch (Exception e) { // Ignore } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/FileMetadataElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/FileMetadataElement.java new file mode 100644 index 000000000..e9f2976bb --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/FileMetadataElement.java @@ -0,0 +1,312 @@ +/** + * + * 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.file_metadata.element; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.CollectionUtil; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.hashes.HashManager; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.jivesoftware.smackx.thumbnails.element.ThumbnailElement; + +/** + * File metadata element as defined in XEP-0446: File Metadata Element. + * This element is used in a generic way to provide information about files, e.g. during file sharing. + */ +public final class FileMetadataElement implements ExtensionElement { + + public static final String ELEMENT = "file"; + public static final String NAMESPACE = "urn:xmpp:file:metadata:0"; + public static final String ELEM_DATE = "date"; + public static final String ELEM_HEIGHT = "height"; + public static final String ELEM_WIDTH = "width"; + public static final String ELEM_DESC = "desc"; + public static final String ELEM_LENGTH = "length"; + public static final String ELEM_MEDIA_TYPE = "media-type"; + public static final String ELEM_NAME = "name"; + public static final String ELEM_SIZE = "size"; + + + private final Date date; + private final Integer height; + private final Integer width; + private final Map descriptions; + private final Map hashElements; + private final Long length; + private final String mediaType; + private final String name; + private final Long size; + private final List thumbnails; + + private FileMetadataElement(Date date, Integer height, Integer width, Map descriptions, + Map hashElements, Long length, + String mediaType, String name, Long size, + List thumbnails) { + this.date = date; + this.height = height; + this.width = width; + this.descriptions = CollectionUtil.cloneAndSeal(descriptions); + this.hashElements = CollectionUtil.cloneAndSeal(hashElements); + this.length = length; + this.mediaType = mediaType; + this.name = name; + this.size = size; + this.thumbnails = CollectionUtil.cloneAndSeal(thumbnails); + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder sb = new XmlStringBuilder(this) + .rightAngleBracket() + .optElement(ELEM_DATE, date) + .optElement(ELEM_HEIGHT, height) + .optElement(ELEM_WIDTH, width); + for (String key : descriptions.keySet()) { + sb.halfOpenElement(ELEM_DESC) + .optXmlLangAttribute(key) + .rightAngleBracket() + .append(descriptions.get(key)) + .closeElement(ELEM_DESC); + } + sb.append(hashElements.values()) + .optElement(ELEM_LENGTH, length != null ? Long.toString(length) : null) + .optElement(ELEM_MEDIA_TYPE, mediaType) + .optElement(ELEM_NAME, name) + .optElement(ELEM_SIZE, size != null ? Long.toString(size) : null) + .append(thumbnails); + return sb.closeElement(this); + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + public Date getDate() { + return date; + } + + public Integer getHeight() { + return height; + } + + public Integer getWidth() { + return width; + } + + public Map getDescriptions() { + return Collections.unmodifiableMap(descriptions); + } + + public String getDescription() { + return getDescription(getLanguage()); + } + + public String getDescription(String lang) { + return descriptions.get(lang != null ? lang : ""); + } + + public Map getHashElements() { + return Collections.unmodifiableMap(hashElements); + } + + public HashElement getHashElement(HashManager.ALGORITHM algorithm) { + return hashElements.get(algorithm); + } + + public Long getLength() { + return length; + } + + public String getMediaType() { + return mediaType; + } + + /** + * Return the name of the file. + * + * @return escaped name + */ + public String getName() { + if (name == null) { + return null; + } + try { + return URLEncoder.encode(name, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // UTF-8 MUST be supported + } + } + + public String getRawName() { + return name; + } + + public Long getSize() { + return size; + } + + public List getThumbnails() { + return Collections.unmodifiableList(thumbnails); + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getNamespace()) + .append(getDate()) + .append(getDescriptions()) + .append(getHeight()) + .append(getWidth()) + .append(getHashElements()) + .append(getLength()) + .append(getMediaType()) + .append(getRawName()) + .append(getSize()) + .append(getThumbnails()) + .build(); + } + + @Override + public boolean equals(Object other) { + return EqualsUtil.equals(this, other, (equalsBuilder, o) -> equalsBuilder + .append(getElementName(), o.getElementName()) + .append(getNamespace(), o.getNamespace()) + .append(getDate(), o.getDate()) + .append(getDescriptions(), o.getDescriptions()) + .append(getHeight(), o.getHeight()) + .append(getWidth(), o.getWidth()) + .append(getHashElements(), o.getHashElements()) + .append(getLength(), o.getLength()) + .append(getMediaType(), o.getMediaType()) + .append(getRawName(), o.getRawName()) + .append(getSize(), o.getSize()) + .append(getThumbnails(), o.getThumbnails())); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Date date; + private Integer height; + private Integer width; + private Map descriptions = new HashMap<>(); + private Map hashElements = new HashMap<>(); + private Long length; + private String mediaType; + private String name; + private Long size; + private List thumbnails = new ArrayList<>(); + + public Builder setModificationDate(Date date) { + this.date = date; + return this; + } + + public Builder setDimensions(int width, int height) { + return setHeight(height).setWidth(width); + } + + public Builder setHeight(int height) { + if (height <= 0) { + throw new IllegalArgumentException("Height must be a positive number"); + } + this.height = height; + return this; + } + + public Builder setWidth(int width) { + if (width <= 0) { + throw new IllegalArgumentException("Width must be a positive number"); + } + this.width = width; + return this; + } + + public Builder addDescription(String description) { + return addDescription(description, null); + } + + public Builder addDescription(String description, String language) { + this.descriptions.put(language != null ? language : "", StringUtils.requireNotNullNorEmpty(description, "Description MUST NOT be null nor empty")); + return this; + } + + public Builder addHash(HashElement hashElement) { + hashElements.put(hashElement.getAlgorithm(), hashElement); + return this; + } + + public Builder setLength(long length) { + if (length < 0) { + throw new IllegalArgumentException("Length cannot be negative."); + } + this.length = length; + return this; + } + + public Builder setMediaType(String mediaType) { + this.mediaType = StringUtils.requireNotNullNorEmpty(mediaType, "Media-Type MUST NOT be null nor empty"); + return this; + } + + public Builder setName(String name) { + this.name = StringUtils.requireNotNullNorEmpty(name, "Name MUST NOT be null nor empty"); + return this; + } + + public Builder setSize(long size) { + if (size < 0) { + throw new IllegalArgumentException("Size MUST NOT be negative."); + } + this.size = size; + return this; + } + + public Builder addThumbnail(ThumbnailElement thumbnail) { + thumbnails.add(thumbnail); + return this; + } + + public FileMetadataElement build() { + return new FileMetadataElement(date, height, width, descriptions, hashElements, length, + mediaType, name, size, thumbnails); + } + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/package-info.java new file mode 100644 index 000000000..dbea97273 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/package-info.java @@ -0,0 +1,20 @@ +/** + * + * 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. + */ +/** + * Smacks implementation of XEP-0446: File Metadata Element. + */ +package org.jivesoftware.smackx.file_metadata.element; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/package-info.java new file mode 100644 index 000000000..8d9825d6c --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/package-info.java @@ -0,0 +1,20 @@ +/** + * + * 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. + */ +/** + * Smacks implementation of XEP-0446: File Metadata Element. + */ +package org.jivesoftware.smackx.file_metadata; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java new file mode 100644 index 000000000..e4212b0ce --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java @@ -0,0 +1,102 @@ +/** + * + * 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.file_metadata.provider; + +import java.io.IOException; +import java.text.ParseException; + +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.file_metadata.element.FileMetadataElement; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.jivesoftware.smackx.hashes.provider.HashElementProvider; +import org.jivesoftware.smackx.thumbnails.element.ThumbnailElement; +import org.jivesoftware.smackx.thumbnails.provider.ThumbnailElementProvider; + +public class FileMetadataElementProvider extends ExtensionElementProvider { + + @Override + public FileMetadataElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) + throws XmlPullParserException, IOException, SmackParsingException, ParseException { + FileMetadataElement.Builder builder = FileMetadataElement.builder(); + + outerloop: while (true) { + XmlPullParser.Event event = parser.next(); + switch (event) { + case START_ELEMENT: + String name = parser.getName(); + switch (name) { + case FileMetadataElement.ELEMENT: + parser.next(); + break; + case FileMetadataElement.ELEM_DATE: + builder.setModificationDate(ParserUtils.getDateFromNextText(parser)); + break; + case FileMetadataElement.ELEM_DESC: + String lang = ParserUtils.getXmlLang(parser); + builder.addDescription(ParserUtils.getRequiredNextText(parser), lang); + break; + case "dimensions": // was replaced with width and height + String dimensions = ParserUtils.getRequiredNextText(parser); + String[] split = dimensions.split("x"); + if (split.length != 2) { + throw new IllegalArgumentException("Invalid dimensions."); + } + builder.setWidth(Integer.parseInt(split[0])); + builder.setHeight(Integer.parseInt(split[1])); + break; + case FileMetadataElement.ELEM_WIDTH: + builder.setWidth(Integer.parseInt(ParserUtils.getRequiredNextText(parser))); + break; + case FileMetadataElement.ELEM_HEIGHT: + builder.setHeight(Integer.parseInt(ParserUtils.getRequiredNextText(parser))); + break; + case FileMetadataElement.ELEM_LENGTH: + builder.setLength(Long.parseLong(ParserUtils.getRequiredNextText(parser))); + break; + case FileMetadataElement.ELEM_MEDIA_TYPE: + builder.setMediaType(ParserUtils.getRequiredNextText(parser)); + break; + case FileMetadataElement.ELEM_NAME: + builder.setName(ParserUtils.getRequiredNextText(parser)); + break; + case FileMetadataElement.ELEM_SIZE: + builder.setSize(Long.parseLong(ParserUtils.getRequiredNextText(parser))); + break; + case HashElement.ELEMENT: + builder.addHash(HashElementProvider.INSTANCE.parse(parser, parser.getDepth(), xmlEnvironment)); + break; + case ThumbnailElement.ELEMENT: + ThumbnailElementProvider provider = new ThumbnailElementProvider(); + builder.addThumbnail(provider.parse(parser, parser.getDepth(), xmlEnvironment)); + } + break; + case END_ELEMENT: + if (parser.getDepth() == initialDepth) break outerloop; + break; + default: + // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. + break; + } + } + return builder.build(); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/package-info.java new file mode 100644 index 000000000..e28f0d94b --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/package-info.java @@ -0,0 +1,20 @@ +/** + * + * 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. + */ +/** + * File metadata element provider. + */ +package org.jivesoftware.smackx.file_metadata.provider; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElement.java new file mode 100644 index 000000000..3bcd4b045 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElement.java @@ -0,0 +1,92 @@ +/** + * + * Copyright 2023 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.thumbnails.element; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class ThumbnailElement implements ExtensionElement { + + public static final String ELEMENT = "thumbnail"; + public static final String NAMESPACE = "urn:xmpp:thumbs:1"; + public static final String ELEM_URI = "uri"; + public static final String ELEM_MEDIA_TYPE = "media-type"; + public static final String ELEM_WIDTH = "width"; + public static final String ELEM_HEIGHT = "height"; + + private final String uri; + private final String mediaType; + private final Integer width; + private final Integer height; + + public ThumbnailElement(String uri) { + this(uri, null, null, null); + } + + public ThumbnailElement(String uri, String mediaType, Integer width, Integer height) { + this.uri = Objects.requireNonNull(uri); + this.mediaType = mediaType; + + if (width != null && width < 0) { + throw new IllegalArgumentException("Width cannot be negative."); + } + this.width = width; + + if (height != null && height < 0) { + throw new IllegalArgumentException("Height cannot be negative."); + } + this.height = height; + } + + public String getUri() { + return uri; + } + + public String getMediaType() { + return mediaType; + } + + public Integer getWidth() { + return width; + } + + public Integer getHeight() { + return height; + } + + @Override + public CharSequence toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder sb = new XmlStringBuilder(this, xmlEnvironment); + return sb.attribute(ELEM_URI, uri) + .optAttribute(ELEM_MEDIA_TYPE, mediaType) + .optAttribute(ELEM_WIDTH, width) + .optAttribute(ELEM_HEIGHT, height) + .closeEmptyElement(); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/package-info.java new file mode 100644 index 000000000..a13671247 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/element/package-info.java @@ -0,0 +1,20 @@ +/** + * + * Copyright 2023 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. + */ +/** + * Smacks implementation of XEP-0264: Jingle Content Thumbnails. + */ +package org.jivesoftware.smackx.thumbnails.element; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProvider.java new file mode 100644 index 000000000..6fc174002 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProvider.java @@ -0,0 +1,46 @@ +/** + * + * Copyright 2023 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.thumbnails.provider; + +import java.io.IOException; +import java.text.ParseException; + +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.thumbnails.element.ThumbnailElement; + +public class ThumbnailElementProvider extends ExtensionElementProvider { + @Override + public ThumbnailElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) + throws XmlPullParserException, IOException, SmackParsingException, ParseException { + String uri = parser.getAttributeValue(ThumbnailElement.ELEM_URI); + String mediaType = parser.getAttributeValue(ThumbnailElement.ELEM_MEDIA_TYPE); + Integer width = ParserUtils.getIntegerAttribute(parser, ThumbnailElement.ELEM_WIDTH); + Integer height = ParserUtils.getIntegerAttribute(parser, ThumbnailElement.ELEM_HEIGHT); + + return new ThumbnailElement( + uri, + mediaType, + width, + height + ); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/package-info.java new file mode 100644 index 000000000..20816c2ce --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/thumbnails/provider/package-info.java @@ -0,0 +1,20 @@ +/** + * + * Copyright 2023 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. + */ +/** + * Smacks implementation of XEP-0264: Jingle Content Thumbnails. + */ +package org.jivesoftware.smackx.thumbnails.provider; diff --git a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers index eb0c1a45f..822bc5837 100644 --- a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers +++ b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers @@ -2,6 +2,13 @@ + + + thumbnail + urn:xmpp:thumbs:1 + org.jivesoftware.smackx.thumbnails.provider.ThumbnailElementProvider + + sent @@ -345,6 +352,13 @@ org.jivesoftware.smackx.fallback_indication.provider.FallbackIndicationElementProvider + + + file + urn:xmpp:file:metadata:0 + org.jivesoftware.smackx.file_metadata.provider.FileMetadataElementProvider + + query diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/file_metadata/FileMetadataElementTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/file_metadata/FileMetadataElementTest.java new file mode 100644 index 000000000..229581308 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/file_metadata/FileMetadataElementTest.java @@ -0,0 +1,190 @@ +/** + * + * 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.file_metadata; + +import static org.jivesoftware.smack.test.util.XmlAssertUtil.assertXmlSimilar; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.text.ParseException; +import java.util.Date; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.SmackTestUtil; +import org.jivesoftware.smackx.file_metadata.element.FileMetadataElement; +import org.jivesoftware.smackx.file_metadata.provider.FileMetadataElementProvider; +import org.jivesoftware.smackx.hashes.HashManager; +import org.jivesoftware.smackx.hashes.element.HashElement; + +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 FileMetadataElementTest extends SmackTestSuite { + + private static final Date date; + static { + try { + date = XmppDateTime.parseDate("2015-07-26T21:46:00+01:00"); + } catch (ParseException e) { + throw new IllegalStateException(e); + } + } + + private static final FileMetadataElement metadataElement = FileMetadataElement.builder() + .setModificationDate(date) + .setWidth(1920) + .setHeight(1080) + .addDescription("Picture of 24th XSF Summit") + .addDescription("Foto vom 24. XSF Summit", "de") + .addHash(new HashElement(HashManager.ALGORITHM.SHA_256, "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=")) + .setLength(63000) + .setMediaType("text/plain") + .setName("text.txt") + .setSize(6144) + .build(); + + private static final String expectedXml = "" + + "2015-07-26T20:46:00.000+00:00" + + "1920" + + "1080" + + "Picture of 24th XSF Summit" + + "Foto vom 24. XSF Summit" + + "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=" + + "63000" + + "text/plain" + + "text.txt" + + "6144" + + ""; + + private static final String expectedLegacyXml = "" + + "2015-07-26T20:46:00.000+00:00" + + "1920x1080" + + "Picture of 24th XSF Summit" + + "Foto vom 24. XSF Summit" + + "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=" + + "63000" + + "text/plain" + + "text.txt" + + "6144" + + ""; + + @Test + public void testSerialization() { + assertXmlSimilar(expectedXml, metadataElement.toXML().toString()); + } + + @ParameterizedTest + @EnumSource(SmackTestUtil.XmlPullParserKind.class) + public void testParsing(SmackTestUtil.XmlPullParserKind parserKind) throws Exception { + FileMetadataElement parsed = SmackTestUtil.parse(expectedXml, FileMetadataElementProvider.class, parserKind); + + assertEquals(metadataElement, parsed); + } + + @ParameterizedTest + @EnumSource(SmackTestUtil.XmlPullParserKind.class) + public void testLegacyParsing(SmackTestUtil.XmlPullParserKind parserKind) throws Exception { + FileMetadataElement parsed = SmackTestUtil.parse(expectedLegacyXml, FileMetadataElementProvider.class, parserKind); + + assertEquals(metadataElement, parsed); + } + + @ParameterizedTest + @EnumSource(SmackTestUtil.XmlPullParserKind.class) + public void testParseUnknownExtension(SmackTestUtil.XmlPullParserKind parserKind) throws Exception { + final String xml = "" + + "2015-07-26T20:46:00.000+00:00" + + "1920" + + "1080" + + "foo" + + "Picture of 24th XSF Summit" + + "Foto vom 24. XSF Summit" + + "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=" + + "63000" + + "text/plain" + + "text.txt" + + "6144" + + ""; + + FileMetadataElement parsed = SmackTestUtil.parse(xml, FileMetadataElementProvider.class, parserKind); + + assertEquals(metadataElement, parsed); + } + + @Test + public void nameIsEscaped() { + FileMetadataElement e = FileMetadataElement.builder().setName("/etc/passwd").build(); + assertEquals("%2Fetc%2Fpasswd", e.getName()); + } + + @Test + public void rejectNegativeSize() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setSize(-1)); + } + + @Test + public void rejectNegativeLength() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setLength(-1)); + } + + @Test + public void rejectNegativeWidth() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setWidth(-1)); + } + + @Test + public void rejectNegativeHeight() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setHeight(-1)); + } + + @Test + public void rejectEmptyDescription() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().addDescription("")); + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().addDescription(null)); + } + + @Test + public void rejectEmptyNameElement() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setName("")); + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setName(null)); + } + + @Test + public void rejectEmptyMediaTypeElement() { + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setMediaType("")); + assertThrows(IllegalArgumentException.class, () -> FileMetadataElement.builder().setMediaType(null)); + } + + @Test + public void getDescTest() { + FileMetadataElement metadataElement = FileMetadataElement.builder() + .addDescription("Foo", "br") + .addDescription("Baz") + .addDescription("Bag", "en") + .build(); + + assertEquals("Foo", metadataElement.getDescription("br")); + assertEquals("Baz", metadataElement.getDescription(null)); + assertEquals("Baz", metadataElement.getDescription()); + assertEquals("Bag", metadataElement.getDescription("en")); + assertNull(metadataElement.getDescription("null")); + assertEquals(3, metadataElement.getDescriptions().size()); + } +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElementTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElementTest.java new file mode 100644 index 000000000..87d03bbb6 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/element/ThumbnailElementTest.java @@ -0,0 +1,56 @@ +/** + * + * Copyright 2023 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.thumbnails.element; + +import static org.jivesoftware.smack.test.util.XmlAssertUtil.assertXmlSimilar; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class ThumbnailElementTest { + + @Test + public void uriIsRequired() { + assertThrows(IllegalArgumentException.class, () -> new ThumbnailElement(null)); + assertThrows(IllegalArgumentException.class, () -> new ThumbnailElement(null, "image/png", 128, 128)); + } + + @Test + public void testMinimal() { + ThumbnailElement minimal = new ThumbnailElement("cid:sha1+ffd7c8d28e9c5e82afea41f97108c6b4@bob.xmpp.org"); + + assertXmlSimilar("", + minimal.toXML()); + } + + @Test + public void testFull() { + ThumbnailElement full = new ThumbnailElement( + "cid:sha1+ffd7c8d28e9c5e82afea41f97108c6b4@bob.xmpp.org", + "image/png", + 128, + 96); + + assertXmlSimilar("", + full.toXML()); + } +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProviderTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProviderTest.java new file mode 100644 index 000000000..dbaec7c9a --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/thumbnails/provider/ThumbnailElementProviderTest.java @@ -0,0 +1,64 @@ +/** + * + * Copyright 2023 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.thumbnails.provider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +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.thumbnails.element.ThumbnailElement; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +public class ThumbnailElementProviderTest { + + @ParameterizedTest + @EnumSource(SmackTestUtil.XmlPullParserKind.class) + public void testParseFull(SmackTestUtil.XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException { + String xml = ""; + + ThumbnailElement element = SmackTestUtil.parse(xml, ThumbnailElementProvider.class, parserKind); + + assertEquals("cid:sha1+ffd7c8d28e9c5e82afea41f97108c6b4@bob.xmpp.org", element.getUri()); + assertEquals("image/png", element.getMediaType()); + assertEquals(128, element.getWidth()); + assertEquals(96, element.getHeight()); + } + + @ParameterizedTest + @EnumSource(SmackTestUtil.XmlPullParserKind.class) + public void testParseMinimal(SmackTestUtil.XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException { + String xml = ""; + + ThumbnailElement element = SmackTestUtil.parse(xml, ThumbnailElementProvider.class, parserKind); + + assertEquals("cid:sha1+ffd7c8d28e9c5e82afea41f97108c6b4@bob.xmpp.org", element.getUri()); + assertNull(element.getMediaType()); + assertNull(element.getWidth()); + assertNull(element.getHeight()); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/DescElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/DescElement.java new file mode 100644 index 000000000..7cb6b4b6b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/DescElement.java @@ -0,0 +1,67 @@ +/** + * + * 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.urldata.element; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class DescElement implements NamedElement { + + public static final String ELEMENT = "desc"; + + private final String desc; + + public DescElement(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getDesc()) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getDesc()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getDesc(), other.getDesc())); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/MetaInformationElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/MetaInformationElement.java new file mode 100644 index 000000000..95628092b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/MetaInformationElement.java @@ -0,0 +1,22 @@ +/** + * + * 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.urldata.element; + +import org.jivesoftware.smack.packet.NamedElement; + +public interface MetaInformationElement extends NamedElement { +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/UrlDataElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/UrlDataElement.java new file mode 100644 index 000000000..b10478e44 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/UrlDataElement.java @@ -0,0 +1,160 @@ +/** + * + * 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.urldata.element; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +import org.jivesoftware.smackx.urldata.http.element.CookieElement; +import org.jivesoftware.smackx.urldata.http.element.HeaderElement; +import org.jivesoftware.smackx.urldata.http.element.HttpAuthElement; + +/** + * The url-data element. + */ +public class UrlDataElement implements ExtensionElement { + + public static final String ELEMENT = "url-data"; + public static final String NAMESPACE = "http://jabber.org/protocol/url-data"; + public static final String ATTR_TARGET = "target"; + public static final String ATTR_SID = "sid"; + public static final String XMLNS_HTTP = "xmlns:http"; + + public static final String SCHEME_HTTP = "http://jabber.org/protocol/url-data/scheme/http"; + + private final String target; + private final String sid; + private final List authParamElements = new ArrayList<>(); + private final List cookieElements = new ArrayList<>(); + private final List headerElements = new ArrayList<>(); + + public UrlDataElement(String target, + String sid) { + this(target, sid, null, null, null); + } + + public UrlDataElement(String target, + String sid, + List authParamElements, + List cookieElements, + List headerElements) { + this.target = target; + this.sid = sid; + if (authParamElements != null) { + this.authParamElements.addAll(authParamElements); + } + if (cookieElements != null) { + this.cookieElements.addAll(cookieElements); + } + if (headerElements != null) { + this.headerElements.addAll(headerElements); + } + } + + public String getTarget() { + return target; + } + + /** + * Return the optional stream identifier used for XEP-0095: Stream Initiation. + * + * @return stream identifier or null + */ + public String getSid() { + return sid; + } + + public List getAuthParameters() { + return authParamElements; + } + + public List getCookies() { + return cookieElements; + } + + public List getHeaders() { + return headerElements; + } + + private List getMetaInformationElements() { + List elements = new ArrayList<>(); + elements.addAll(getAuthParameters()); + elements.addAll(getCookies()); + elements.addAll(getHeaders()); + return elements; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + List metaInformation = getMetaInformationElements(); + + XmlStringBuilder sb = new XmlStringBuilder(this); + if (!metaInformation.isEmpty()) { + sb.attribute(XMLNS_HTTP, SCHEME_HTTP); + } + sb.attribute(ATTR_TARGET, getTarget()) + .optAttribute(ATTR_SID, getSid()); + if (metaInformation.isEmpty()) { + return sb.closeEmptyElement(); + } else { + return sb.rightAngleBracket() + .append(metaInformation) + .closeElement(this); + } + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getNamespace()) + .append(getTarget()) + .append(getAuthParameters()) + .append(getCookies()) + .append(getHeaders()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getNamespace(), other.getNamespace()) + .append(getTarget(), other.getTarget()) + .append(getAuthParameters(), other.getAuthParameters()) + .append(getCookies(), other.getCookies()) + .append(getHeaders(), other.getHeaders())); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/package-info.java new file mode 100644 index 000000000..0682aff01 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/element/package-info.java @@ -0,0 +1,23 @@ +/** + * + * 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. + */ + +/** + * Element classes for XEP-0103: URL Address Information. + * + * @see XEP-0103 - URL Address Information. + */ +package org.jivesoftware.smackx.urldata.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/AuthParamElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/AuthParamElement.java new file mode 100644 index 000000000..42ca5218a --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/AuthParamElement.java @@ -0,0 +1,77 @@ +/** + * + * 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.urldata.http.element; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class AuthParamElement extends NameValuePairElement { + + public static final String ELEMENT = "auth-param"; + public static final String PREFIX = "http"; + + public static final String NAME_REALM = "realm"; + public static final String NAME_USERNAME = "username"; + public static final String NAME_PASSWORD = "password"; + + public AuthParamElement(String name, String value) { + super(name, value); + } + + public static AuthParamElement realm(String realm) { + return new AuthParamElement(NAME_REALM, realm); + } + + public static AuthParamElement username(String username) { + return new AuthParamElement(NAME_USERNAME, username); + } + + public static AuthParamElement password(String password) { + return new AuthParamElement(NAME_PASSWORD, password); + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return addCommonXml(new XmlStringBuilder(this)) + .closeEmptyElement(); + } + + @Override + public String getElementName() { + return PREFIX + ':' + ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getName()) + .append(getValue()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getName(), other.getName()) + .append(getValue(), other.getValue())); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/CookieElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/CookieElement.java new file mode 100644 index 000000000..3bd95347b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/CookieElement.java @@ -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.urldata.http.element; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class CookieElement extends NameValuePairElement { + + public static final String ELEMENT = "cookie"; + public static final String PREFIX = "http"; + public static final String ATTR_DOMAIN = "domain"; + public static final String ATTR_MAX_AGE = "max-age"; + public static final String ATTR_PATH = "path"; + public static final String ATTR_COMMENT = "comment"; + public static final String ATTR_VERSION = "version"; + public static final String ATTR_SECURE = "secure"; + + private final String domain; + private final Integer maxAge; + private final String path; + private final String comment; + private final String version; + private final Boolean secure; + + public CookieElement(String name, String value) { + this(name, value, null, null, null, null, null, null); + } + + public CookieElement(String name, String value, String domain, Integer maxAge, String path, String comment, String version, Boolean secure) { + super(name, value); + this.domain = domain; + this.maxAge = maxAge; + this.path = path; + this.comment = comment; + this.version = version; + this.secure = secure; + } + + public String getPath() { + return path; + } + + public int getMaxAge() { + return maxAge == null ? 0 : maxAge; + } + + public String getDomain() { + return domain; + } + + public String getComment() { + return comment; + } + + public String getVersion() { + return version == null ? "1.0" : version; + } + + public boolean isSecure() { + return secure != null && secure; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder sb = addCommonXml(new XmlStringBuilder(this)) + .optAttribute(ATTR_DOMAIN, domain) + .optAttribute(ATTR_MAX_AGE, maxAge) + .optAttribute(ATTR_PATH, path) + .optAttribute(ATTR_COMMENT, comment) + .optAttribute(ATTR_VERSION, version); + if (secure != null) { + sb.attribute(ATTR_SECURE, secure); + } + return sb.closeEmptyElement(); + } + + @Override + public String getElementName() { + return PREFIX + ':' + ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getName()) + .append(getValue()) + .append(getDomain()) + .append(getMaxAge()) + .append(getPath()) + .append(getComment()) + .append(getVersion()) + .append(isSecure()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getName(), other.getName()) + .append(getValue(), other.getValue()) + .append(getDomain(), other.getDomain()) + .append(getMaxAge(), other.getMaxAge()) + .append(getPath(), other.getPath()) + .append(getComment(), other.getComment()) + .append(getVersion(), other.getVersion()) + .append(isSecure(), other.isSecure())); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HeaderElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HeaderElement.java new file mode 100644 index 000000000..0feb816e3 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HeaderElement.java @@ -0,0 +1,61 @@ +/** + * + * 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.urldata.http.element; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class HeaderElement extends NameValuePairElement { + + public static final String ELEMENT = "header"; + public static final String PREFIX = "http"; + + public HeaderElement(String name, String value) { + super(name, value); + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return addCommonXml(new XmlStringBuilder(this)) + .closeEmptyElement(); + } + + @Override + public String getElementName() { + return PREFIX + ':' + ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getName()) + .append(getValue()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getName(), other.getName()) + .append(getValue(), other.getValue())); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HttpAuthElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HttpAuthElement.java new file mode 100644 index 000000000..ff11163f2 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/HttpAuthElement.java @@ -0,0 +1,123 @@ +/** + * + * 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.urldata.http.element; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +import org.jivesoftware.smackx.urldata.element.MetaInformationElement; + +public final class HttpAuthElement implements MetaInformationElement { + + public static final String ELEMENT = "auth"; + public static final String PREFIX = "http"; + public static final String ATTR_SCHEME = "scheme"; + + public static final String SCHEME_BASIC = "basic"; + + private final String scheme; + private final List params = new ArrayList<>(); + + public HttpAuthElement(String scheme, List params) { + this.scheme = scheme; + if (params != null) { + this.params.addAll(params); + } + } + + public static HttpAuthElement basicAuth() { + return basicAuth(null, null); + } + + public static HttpAuthElement basicAuth(String username, String password) { + return basicAuth(null, username, password); + } + + public static HttpAuthElement basicAuth(String realm, String username, String password) { + List params = new ArrayList<>(); + if (realm != null) { + params.add(AuthParamElement.realm(realm)); + } + if (username != null) { + params.add(AuthParamElement.username(username)); + } + if (password != null) { + params.add(AuthParamElement.password(password)); + } + + return new HttpAuthElement(SCHEME_BASIC, params); + } + + public String getScheme() { + return scheme; + } + + public List getParams() { + return params; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder sb = new XmlStringBuilder(this) + .attribute(ATTR_SCHEME, getScheme()); + if (getParams().isEmpty()) { + return sb.closeEmptyElement(); + } else { + return sb.rightAngleBracket() + .append(getParams()) + .closeElement(this); + } + } + + @Override + public String getElementName() { + return PREFIX + ':' + ELEMENT; + } + + public AuthParamElement getParam(String name) { + for (AuthParamElement param : getParams()) { + if (param.getName().equals(name)) { + return param; + } + } + return null; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getScheme()) + .append(getParams()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder + .append(getElementName(), other.getElementName()) + .append(getScheme(), other.getScheme()) + .append(getParams(), other.getParams())); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/NameValuePairElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/NameValuePairElement.java new file mode 100644 index 000000000..911bdb339 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/NameValuePairElement.java @@ -0,0 +1,49 @@ +/** + * + * 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.urldata.http.element; + +import org.jivesoftware.smack.util.XmlStringBuilder; + +import org.jivesoftware.smackx.urldata.element.MetaInformationElement; + +public abstract class NameValuePairElement implements MetaInformationElement { + + public static final String ATTR_NAME = "name"; + public static final String ATTR_VALUE = "value"; + + private final String name; + private final String value; + + public NameValuePairElement(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public XmlStringBuilder addCommonXml(XmlStringBuilder sb) { + return sb.attribute(ATTR_NAME, getName()) + .attribute(ATTR_VALUE, getValue()); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/package-info.java new file mode 100644 index 000000000..7bc42714a --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/element/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Element classes for XEP-0104. + */ +package org.jivesoftware.smackx.urldata.http.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/package-info.java new file mode 100644 index 000000000..4a7f1b8db --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/http/package-info.java @@ -0,0 +1,23 @@ +/** + * + * 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. + */ + +/** + * Smack's API for XEP-0104: HTTP Scheme for URL Address Information. + * + * @see XEP-0104 - HTTP Scheme for URL Address Information + */ +package org.jivesoftware.smackx.urldata.http; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/package-info.java new file mode 100644 index 000000000..06fec0af9 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Smack's API for XEP-0103 - URL Address Information. + */ +package org.jivesoftware.smackx.urldata; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/UrlDataElementProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/UrlDataElementProvider.java new file mode 100644 index 000000000..f1a8a2b25 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/UrlDataElementProvider.java @@ -0,0 +1,101 @@ +/** + * + * 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.urldata.provider; + +import static org.jivesoftware.smackx.urldata.element.UrlDataElement.ATTR_SID; +import static org.jivesoftware.smackx.urldata.element.UrlDataElement.ATTR_TARGET; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +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.urldata.element.UrlDataElement; +import org.jivesoftware.smackx.urldata.http.element.AuthParamElement; +import org.jivesoftware.smackx.urldata.http.element.CookieElement; +import org.jivesoftware.smackx.urldata.http.element.HeaderElement; +import org.jivesoftware.smackx.urldata.http.element.HttpAuthElement; + +public class UrlDataElementProvider extends ExtensionElementProvider { + + @Override + public UrlDataElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException { + String target = parser.getAttributeValue(ATTR_TARGET); + String sid = parser.getAttributeValue(ATTR_SID); + List authElements = new ArrayList<>(); + List cookieElements = new ArrayList<>(); + List headerElements = new ArrayList<>(); + do { + XmlPullParser.TagEvent event = parser.nextTag(); + String name = parser.getName(); + + if (event == XmlPullParser.TagEvent.START_ELEMENT) { + switch (name) { + case UrlDataElement.ELEMENT: + continue; + + case HttpAuthElement.ELEMENT: + String scheme = parser.getAttributeValue(HttpAuthElement.ATTR_SCHEME); + List authParamElements = new ArrayList<>(); + int innerDepth = parser.getDepth(); + do { + XmlPullParser.TagEvent innerTag = parser.nextTag(); + String innerName = parser.getName(); + if (innerTag.equals(XmlPullParser.TagEvent.START_ELEMENT)) { + if (innerName.equals(AuthParamElement.ELEMENT)) { + String attrName = ParserUtils.getRequiredAttribute(parser, AuthParamElement.ATTR_NAME); + String attrVal = ParserUtils.getRequiredAttribute(parser, AuthParamElement.ATTR_VALUE); + authParamElements.add(new AuthParamElement(attrName, attrVal)); + } + } + } while (parser.getDepth() != innerDepth); + + authElements.add(new HttpAuthElement(scheme, authParamElements)); + break; + + case CookieElement.ELEMENT: + String cookieName = ParserUtils.getRequiredAttribute(parser, CookieElement.ATTR_NAME); + String cookieValue = ParserUtils.getRequiredAttribute(parser, CookieElement.ATTR_VALUE); + String cookieDomain = parser.getAttributeValue(CookieElement.ATTR_DOMAIN); + Integer cookieMaxAge = ParserUtils.getIntegerAttribute(parser, CookieElement.ATTR_MAX_AGE); + String cookiePath = parser.getAttributeValue(CookieElement.ATTR_PATH); + String cookieComment = parser.getAttributeValue(CookieElement.ATTR_COMMENT); + Boolean cookieSecure = ParserUtils.getBooleanAttribute(parser, CookieElement.ATTR_SECURE); + String cookieVersion = parser.getAttributeValue(CookieElement.ATTR_VERSION); + + cookieElements.add(new CookieElement(cookieName, cookieValue, cookieDomain, cookieMaxAge, cookiePath, cookieComment, cookieVersion, cookieSecure)); + break; + + case HeaderElement.ELEMENT: + String headerName = ParserUtils.getRequiredAttribute(parser, HeaderElement.ATTR_NAME); + String headerValue = ParserUtils.getRequiredAttribute(parser, HeaderElement.ATTR_VALUE); + + headerElements.add(new HeaderElement(headerName, headerValue)); + break; + } + } + } while (parser.getDepth() != initialDepth); + + return new UrlDataElement(target, sid, authElements, cookieElements, headerElements); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/package-info.java new file mode 100644 index 000000000..c31c44db0 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/urldata/provider/package-info.java @@ -0,0 +1,23 @@ +/** + * + * 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. + */ + +/** + * Provider classes for XEP-0103: URL Address Information. + * + * @see XEP-0103 - URL Address Information. + */ +package org.jivesoftware.smackx.urldata.provider; diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers index c2ac6921e..8dd5b32d3 100644 --- a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers +++ b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers @@ -365,6 +365,13 @@ org.jivesoftware.smackx.si.provider.StreamInitiationProvider + + + url-data + http://jabber.org/protocol/url-data + org.jivesoftware.smackx.urldata.provider.UrlDataElementProvider + + mood diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/urldata/UrlDataElementTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/urldata/UrlDataElementTest.java new file mode 100644 index 000000000..72bc4f32a --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/urldata/UrlDataElementTest.java @@ -0,0 +1,219 @@ +/** + * + * 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.urldata; + +import static org.jivesoftware.smack.test.util.XmlAssertUtil.assertXmlSimilar; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; + +import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smack.xml.XmlPullParserException; + +import org.jivesoftware.smackx.urldata.element.UrlDataElement; +import org.jivesoftware.smackx.urldata.http.element.CookieElement; +import org.jivesoftware.smackx.urldata.http.element.HeaderElement; +import org.jivesoftware.smackx.urldata.http.element.HttpAuthElement; +import org.jivesoftware.smackx.urldata.provider.UrlDataElementProvider; + +import org.junit.jupiter.api.Test; + +public class UrlDataElementTest extends SmackTestSuite { + + public static final UrlDataElementProvider URL_DATA_ELEMENT_PROVIDER = new UrlDataElementProvider(); + + @Test + public void simpleSerializationTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement("http://www.jabber.org/members/index.php", + null, + Collections.singletonList(HttpAuthElement.basicAuth()), + null, null); + + final String expectedXml = "" + + "" + + "" + + ""; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void additionalAuthParamTest() throws XmlPullParserException, IOException, SmackParsingException { + + UrlDataElement urlDataElement = new UrlDataElement("http://www.jabber.org/members/index.php", + null, + Collections.singletonList(HttpAuthElement.basicAuth( + "www.jabber.org", + "defaultuser", + "defaultpwd" + )), + null, + null); + + final String expectedXml = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " "; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void simpleUrlWithSidTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement("http://pass.jabber.org:8519/test.txt", "a0"); + + final String expectedXml = ""; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void simpleUrlNoChildrenTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement("http://festhall.outer-planes.net/d20M/announce/latest/", null); + + final String expectedXml = ""; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void simpleCookieTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement("http://www.jabber.org/members/index.php", + null, + null, + Collections.singletonList(new CookieElement("jsessionid", "1243asd234190sa32ds")), + null); + + final String expectedXml = "" + + "\n" + + " \n" + + ""; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void additionalParametersCookieTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement("http://www.jabber.org/members/index.php", + null, + null, + Collections.singletonList(new CookieElement( + "jsessionid", + "1243asd234190sa32ds", + "jabber.org", + 1234000, + "/members", + "Web Session Identifier", + "1.0", + false + )), + null); + + final String expectedXml = "\n" + + " \n" + + ""; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void simpleHeaderTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement( + "http://www.jabber.org/members/index.php", + null, + null, + null, + Collections.singletonList(new HeaderElement("Custom-Data", "some custom data"))); + + final String expectedXml = "\n" + + " \n" + + " "; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } + + @Test + public void multiChildTest() throws XmlPullParserException, IOException, SmackParsingException { + UrlDataElement urlDataElement = new UrlDataElement( + "https://blog.jabberhead.tk", + null, + Collections.singletonList(HttpAuthElement.basicAuth()), + Arrays.asList( + new CookieElement("jsessionid", "somecookievalue"), + new CookieElement("come2darkSide", "weHaveCookies")), + Arrays.asList( + new HeaderElement("Accept", "text/plain"), + new HeaderElement("Access-Control-Allow-Origin", "*"))); + + final String expectedXml = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " "; + assertXmlSimilar(expectedXml, urlDataElement.toXML().toString()); + + UrlDataElement parsed = URL_DATA_ELEMENT_PROVIDER.parse(TestUtils.getParser(expectedXml)); + assertEquals(urlDataElement, parsed); + } +} diff --git a/smack-java8-full/src/main/java/org/jivesoftware/smackx/package-info.java b/smack-java8-full/src/main/java/org/jivesoftware/smackx/package-info.java index 803afc7da..d9f01636e 100644 --- a/smack-java8-full/src/main/java/org/jivesoftware/smackx/package-info.java +++ b/smack-java8-full/src/main/java/org/jivesoftware/smackx/package-info.java @@ -206,6 +206,18 @@ * Transfer files between two users over XMPP. * * + * URL Address Information + * XEP-0103 + * {@link org.jivesoftware.smackx.urldata.element} + * Provide information about an Uniform Resource Locator (URL), and a protocol signaling retrieval states. + * + * + * HTTP Scheme for URL Data + * XEP-0104 + * + * A schema description for detailed information about HTTP URLs. + * + * * User Mood * XEP-0107 * @@ -358,6 +370,12 @@ * Allows sending a MUC invitation directly from the user to the contact with mediation by the room. * * + * Jingle Content Thumbnails + * XEP-0264 + * {@link org.jivesoftware.smackx.thumbnails.element} + * Defines a way for a client to supply a preview image for Jingle content. + * + * * Message Carbons * XEP-0280 * {@link org.jivesoftware.smackx.carbons} @@ -571,6 +589,12 @@ * Declare body elements of a message as ignorable fallback for naive legacy clients. * * + * File metadata element + * XEP-0446 + * {@link org.jivesoftware.smackx.file_metadata.element} + * Defines a generic file metadata element to be used in other specifications. + * + * * Google GCM JSON payload * *