/** * * Copyright 2017-2019 Florian Schmaus, 2018 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.ox.element; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.Charset; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; import javax.xml.namespace.QName; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.util.MultiMap; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.PacketUtil; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jxmpp.jid.Jid; import org.jxmpp.util.XmppDateTime; /** * This class describes an OpenPGP content element. It defines the elements and fields that OpenPGP content elements * do have in common. */ public abstract class OpenPgpContentElement implements ExtensionElement { public static final String ELEM_TO = "to"; public static final String ATTR_JID = "jid"; public static final String ELEM_TIME = "time"; public static final String ATTR_STAMP = "stamp"; public static final String ELEM_PAYLOAD = "payload"; private final Set to; private final Date timestamp; private final MultiMap payload; private String timestampString; protected OpenPgpContentElement(Set to, Date timestamp, List payload) { this.to = to; this.timestamp = Objects.requireNonNull(timestamp); this.payload = new MultiMap<>(); for (ExtensionElement e : payload) { this.payload.put(e.getQName(), e); } } /** * Return the set of recipients. * * @return recipients. */ public final Set getTo() { return to; } /** * Return the timestamp on which the encrypted element has been created. * This should be checked for sanity by the client. * * @return timestamp. */ public final Date getTimestamp() { return timestamp; } /** * Return the payload of the message. * * @return payload. */ public final List getExtensions() { synchronized (payload) { return payload.values(); } } /** * Return a list of all extensions with the given element name and namespace. *

* Changes to the returned set will update the stanza extensions, if the returned set is not the empty set. *

* * @param elementName the element name, must not be null. * @param namespace the namespace of the element(s), must not be null. * @return a set of all matching extensions. */ public List getExtensions(String elementName, String namespace) { QName key = new QName(namespace, elementName); return payload.getAll(key); } /** * Returns the first extension of this stanza that has the given namespace. *

* When possible, use {@link #getExtension(String, String)} instead. *

* * @param namespace the namespace of the extension that is desired. * @return the stanza extension with the given namespace. */ public ExtensionElement getExtension(String namespace) { return PacketUtil.extensionElementFrom(getExtensions(), null, namespace); } /** * Returns the first extension that matches the specified element name and * namespace, or null if it doesn't exist. If the provided elementName is null, * only the namespace is matched. Extensions are * are arbitrary XML elements in standard XMPP stanzas. * * @param elementName the XML element name of the extension. (May be null) * @param namespace the XML element namespace of the extension. * @param type of the ExtensionElement. * @return the extension, or null if it doesn't exist. */ @SuppressWarnings("unchecked") public PE getExtension(String elementName, String namespace) { if (namespace == null) { return null; } QName key = new QName(namespace, elementName); ExtensionElement packetExtension; synchronized (payload) { packetExtension = payload.getFirst(key); } if (packetExtension == null) { return null; } return (PE) packetExtension; } @Override public String getNamespace() { return OpenPgpElement.NAMESPACE; } protected void ensureTimestampStringSet() { if (timestampString != null) return; timestampString = XmppDateTime.formatXEP0082Date(timestamp); } protected void addCommonXml(XmlStringBuilder xml) { for (Jid toJid : to != null ? to : Collections.emptySet()) { xml.halfOpenElement(ELEM_TO).attribute(ATTR_JID, toJid).closeEmptyElement(); } ensureTimestampStringSet(); xml.halfOpenElement(ELEM_TIME).attribute(ATTR_STAMP, timestampString).closeEmptyElement(); xml.openElement(ELEM_PAYLOAD); for (ExtensionElement element : payload.values()) { xml.append(element.toXML(getNamespace())); } xml.closeElement(ELEM_PAYLOAD); } /** * Return a {@link ByteArrayInputStream} that reads the bytes of the XML representation of this element. * * @return InputStream over xml. */ public InputStream toInputStream() { byte[] encoded = toXML().toString().getBytes(Charset.forName("UTF-8")); return new ByteArrayInputStream(encoded); } }