001/**
002 *
003 * Copyright 2020 Paul Schaub
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.stanza_content_encryption.provider;
018
019import java.io.IOException;
020import java.text.ParseException;
021import java.util.Date;
022
023import org.jivesoftware.smack.packet.XmlElement;
024import org.jivesoftware.smack.packet.XmlEnvironment;
025import org.jivesoftware.smack.parsing.SmackParsingException;
026import org.jivesoftware.smack.provider.ExtensionElementProvider;
027import org.jivesoftware.smack.util.PacketParserUtils;
028import org.jivesoftware.smack.util.ParserUtils;
029import org.jivesoftware.smack.xml.XmlPullParser;
030import org.jivesoftware.smack.xml.XmlPullParserException;
031
032import org.jivesoftware.smackx.stanza_content_encryption.element.AffixElement;
033import org.jivesoftware.smackx.stanza_content_encryption.element.ContentElement;
034import org.jivesoftware.smackx.stanza_content_encryption.element.FromAffixElement;
035import org.jivesoftware.smackx.stanza_content_encryption.element.PayloadElement;
036import org.jivesoftware.smackx.stanza_content_encryption.element.RandomPaddingAffixElement;
037import org.jivesoftware.smackx.stanza_content_encryption.element.TimestampAffixElement;
038import org.jivesoftware.smackx.stanza_content_encryption.element.ToAffixElement;
039
040import org.jxmpp.jid.impl.JidCreate;
041import org.jxmpp.stringprep.XmppStringprepException;
042
043public class ContentElementProvider extends ExtensionElementProvider<ContentElement> {
044
045    @Override
046    public ContentElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
047            throws XmlPullParserException, IOException, ParseException, SmackParsingException {
048        ContentElement.Builder builder = ContentElement.builder();
049
050        while (true) {
051            XmlPullParser.Event tag = parser.next();
052            if (tag == XmlPullParser.Event.START_ELEMENT) {
053                String name = parser.getName();
054                switch (name) {
055                    case ToAffixElement.ELEMENT:
056                        parseToAffix(parser, builder);
057                        break;
058
059                    case FromAffixElement.ELEMENT:
060                        parseFromAffix(parser, builder);
061                        break;
062
063                    case TimestampAffixElement.ELEMENT:
064                        parseTimestampAffix(parser, builder);
065                        break;
066
067                    case RandomPaddingAffixElement.ELEMENT:
068                        parseRPadAffix(parser, builder);
069                        break;
070
071                    case PayloadElement.ELEMENT:
072                        parsePayload(parser, xmlEnvironment, builder);
073                        break;
074
075                    default:
076                        parseCustomAffix(parser, xmlEnvironment, builder);
077                        break;
078                }
079            } else if (tag == XmlPullParser.Event.END_ELEMENT) {
080                if (parser.getDepth() == initialDepth) {
081                    break;
082                }
083            }
084        }
085        return builder.build();
086    }
087
088    private static void parseCustomAffix(XmlPullParser parser, XmlEnvironment outerXmlEnvironment, ContentElement.Builder builder)
089            throws XmlPullParserException, IOException, SmackParsingException {
090        String name = parser.getName();
091        String namespace = parser.getNamespace();
092
093        AffixElement element = (AffixElement) PacketParserUtils.parseExtensionElement(name, namespace, parser, outerXmlEnvironment);
094        builder.addFurtherAffixElement(element);
095    }
096
097    private static void parsePayload(XmlPullParser parser, XmlEnvironment outerXmlEnvironment, ContentElement.Builder builder)
098            throws IOException, XmlPullParserException, SmackParsingException {
099        final int initialDepth = parser.getDepth();
100        while (true) {
101            XmlPullParser.Event tag = parser.next();
102
103            if (tag == XmlPullParser.Event.START_ELEMENT) {
104                String name = parser.getName();
105                String namespace = parser.getNamespace();
106                XmlElement element = PacketParserUtils.parseExtensionElement(name, namespace, parser, outerXmlEnvironment);
107                builder.addPayloadItem(element);
108            }
109
110            if (tag == XmlPullParser.Event.END_ELEMENT && parser.getDepth() == initialDepth) {
111                return;
112            }
113        }
114    }
115
116    private static void parseRPadAffix(XmlPullParser parser, ContentElement.Builder builder)
117            throws IOException, XmlPullParserException {
118        builder.setRandomPadding(parser.nextText());
119    }
120
121    private static void parseTimestampAffix(XmlPullParser parser, ContentElement.Builder builder)
122            throws ParseException {
123        Date timestamp = ParserUtils.getDateFromXep82String(
124                parser.getAttributeValue("", TimestampAffixElement.ATTR_STAMP));
125        builder.setTimestamp(timestamp);
126    }
127
128    private static void parseFromAffix(XmlPullParser parser, ContentElement.Builder builder)
129            throws XmppStringprepException {
130        String jidString = parser.getAttributeValue("", FromAffixElement.ATTR_JID);
131        builder.setFrom(JidCreate.from(jidString));
132    }
133
134    private static void parseToAffix(XmlPullParser parser, ContentElement.Builder builder)
135            throws XmppStringprepException {
136        String jidString = parser.getAttributeValue("", ToAffixElement.ATTR_JID);
137        builder.addTo(JidCreate.from(jidString));
138    }
139}