001/**
002 *
003 * Copyright 2013-2014 Georg Lukas, 2020 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.forward.packet;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.List;
022
023import javax.xml.namespace.QName;
024
025import org.jivesoftware.smack.packet.ExtensionElement;
026import org.jivesoftware.smack.packet.Message;
027import org.jivesoftware.smack.packet.Stanza;
028import org.jivesoftware.smack.util.Objects;
029import org.jivesoftware.smack.util.XmlStringBuilder;
030
031import org.jivesoftware.smackx.delay.packet.DelayInformation;
032
033/**
034 * Stanza extension for XEP-0297: Stanza Forwarding.
035 *
036 * @author Georg Lukas
037 * @see <a href="http://xmpp.org/extensions/xep-0297.html">XEP-0297: Stanza Forwarding</a>
038 */
039public class Forwarded<S extends Stanza> implements ExtensionElement {
040    public static final String NAMESPACE = "urn:xmpp:forward:0";
041    public static final String ELEMENT = "forwarded";
042    public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
043
044    private final DelayInformation delay;
045    private final S forwardedStanza;
046
047    /**
048     * Creates a new Forwarded stanza extension.
049     *
050     * @param delay an optional {@link DelayInformation} timestamp of the packet.
051     * @param forwardedStanza the stanza that is forwarded (required).
052     * @deprecated use {@link #Forwarded(Stanza, DelayInformation)} instead.
053     */
054    @Deprecated
055    public Forwarded(DelayInformation delay, S forwardedStanza) {
056        this(forwardedStanza, delay);
057    }
058
059    /**
060     * Creates a new Forwarded stanza extension.
061     *
062     * @param fwdPacket the stanza that is forwarded (required).
063     */
064    public Forwarded(S fwdPacket) {
065        this(fwdPacket, null);
066    }
067
068    /**
069     * Creates a new Forwarded stanza extension.
070     *
071     * @param forwardedStanza the stanza that is forwarded (required).
072     * @param delay an optional {@link DelayInformation} timestamp of the packet.
073     */
074    public Forwarded(S forwardedStanza, DelayInformation delay) {
075        this.forwardedStanza = Objects.requireNonNull(forwardedStanza);
076        this.delay = delay;
077    }
078
079    @Override
080    public String getElementName() {
081        return ELEMENT;
082    }
083
084    @Override
085    public String getNamespace() {
086        return NAMESPACE;
087    }
088
089    @Override
090    public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
091        XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
092        xml.rightAngleBracket();
093        xml.optElement(getDelayInformation());
094        xml.append(forwardedStanza);
095        xml.closeElement(this);
096        return xml;
097    }
098
099    /**
100     * Get the forwarded Stanza found in this extension.
101     *
102     * @return the {@link Stanza} (typically a message) that was forwarded.
103     */
104    public S getForwardedStanza() {
105        return forwardedStanza;
106    }
107
108    /**
109     * get the timestamp of the forwarded packet.
110     *
111     * @return the {@link DelayInformation} representing the time when the original stanza was sent. May be null.
112     */
113    public DelayInformation getDelayInformation() {
114        return delay;
115    }
116
117    /**
118     * Check if this is forwarding a stanza of the provided class.
119     *
120     * @param stanzaClass the class to check for.
121     * @return <code>true</code> if this is forwarding a stanza of the provided class.
122     * @since 4.4
123     */
124    public boolean isForwarded(Class<? extends Stanza> stanzaClass) {
125        return stanzaClass.isAssignableFrom(forwardedStanza.getClass());
126    }
127
128    /**
129     * Get the forwarded extension.
130     * @param packet TODO javadoc me please
131     * @return the Forwarded extension or null
132     */
133    public static Forwarded<?> from(Stanza packet) {
134        return packet.getExtension(Forwarded.class);
135    }
136
137    /**
138     * Extract messages in a collection of forwarded elements. Note that it is required that the {@link Forwarded} in
139     * the given collection only contain {@link Message} stanzas.
140     *
141     * @param forwardedCollection the collection to extract from.
142     * @return a list a the extracted messages.
143     * @since 4.3.0
144     */
145    public static List<Message> extractMessagesFrom(Collection<Forwarded<Message>> forwardedCollection) {
146        List<Message> res = new ArrayList<>(forwardedCollection.size());
147        for (Forwarded<Message> forwarded : forwardedCollection) {
148            Message message =  forwarded.getForwardedStanza();
149            res.add(message);
150        }
151        return res;
152    }
153}