2018-07-29 18:52:45 +02:00
|
|
|
/**
|
|
|
|
*
|
2019-03-25 12:29:40 +01:00
|
|
|
* Copyright 2017-2019 Florian Schmaus, 2018 Paul Schaub.
|
2018-07-29 18:52:45 +02:00
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2019-06-11 00:10:38 +02:00
|
|
|
import javax.xml.namespace.QName;
|
|
|
|
|
2018-07-29 18:52:45 +02:00
|
|
|
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";
|
|
|
|
|
2019-03-25 12:29:40 +01:00
|
|
|
private final Set<? extends Jid> to;
|
2018-07-29 18:52:45 +02:00
|
|
|
private final Date timestamp;
|
2019-06-11 00:10:38 +02:00
|
|
|
private final MultiMap<QName, ExtensionElement> payload;
|
2018-07-29 18:52:45 +02:00
|
|
|
|
|
|
|
private String timestampString;
|
|
|
|
|
2019-03-25 12:29:40 +01:00
|
|
|
protected OpenPgpContentElement(Set<? extends Jid> to, Date timestamp, List<ExtensionElement> payload) {
|
2018-07-29 18:52:45 +02:00
|
|
|
this.to = to;
|
|
|
|
this.timestamp = Objects.requireNonNull(timestamp);
|
|
|
|
this.payload = new MultiMap<>();
|
|
|
|
for (ExtensionElement e : payload) {
|
2019-06-11 00:10:38 +02:00
|
|
|
this.payload.put(e.getQName(), e);
|
2018-07-29 18:52:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the set of recipients.
|
|
|
|
*
|
|
|
|
* @return recipients.
|
|
|
|
*/
|
2019-03-25 12:29:40 +01:00
|
|
|
public final Set<? extends Jid> getTo() {
|
2018-07-29 18:52:45 +02:00
|
|
|
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<ExtensionElement> getExtensions() {
|
|
|
|
synchronized (payload) {
|
|
|
|
return payload.values();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a list of all extensions with the given element name <em>and</em> namespace.
|
|
|
|
* <p>
|
|
|
|
* Changes to the returned set will update the stanza extensions, if the returned set is not the empty set.
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @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<ExtensionElement> getExtensions(String elementName, String namespace) {
|
2019-06-11 00:10:38 +02:00
|
|
|
QName key = new QName(namespace, elementName);
|
2018-07-29 18:52:45 +02:00
|
|
|
return payload.getAll(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the first extension of this stanza that has the given namespace.
|
|
|
|
* <p>
|
2019-05-17 21:56:46 +02:00
|
|
|
* When possible, use {@link #getExtension(String, String)} instead.
|
2018-07-29 18:52:45 +02:00
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @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
|
2019-07-19 18:10:36 +02:00
|
|
|
* namespace, or <code>null</code> if it doesn't exist. If the provided elementName is null,
|
2018-07-29 18:52:45 +02:00
|
|
|
* 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 <PE> type of the ExtensionElement.
|
2019-07-19 18:10:36 +02:00
|
|
|
* @return the extension, or <code>null</code> if it doesn't exist.
|
2018-07-29 18:52:45 +02:00
|
|
|
*/
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public <PE extends ExtensionElement> PE getExtension(String elementName, String namespace) {
|
|
|
|
if (namespace == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2019-06-11 00:10:38 +02:00
|
|
|
QName key = new QName(namespace, elementName);
|
2018-07-29 18:52:45 +02:00
|
|
|
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) {
|
2019-07-24 09:18:39 +02:00
|
|
|
for (Jid toJid : to != null ? to : Collections.<Jid>emptySet()) {
|
2018-07-29 18:52:45 +02:00
|
|
|
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() {
|
2019-02-04 13:27:41 +01:00
|
|
|
byte[] encoded = toXML().toString().getBytes(Charset.forName("UTF-8"));
|
2018-07-29 18:52:45 +02:00
|
|
|
return new ByteArrayInputStream(encoded);
|
|
|
|
}
|
|
|
|
}
|