001/*
002 *
003 * Copyright © 2017 Grigory Fedorov, 2017-2024 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.httpfileupload.provider;
018
019import java.io.IOException;
020import java.net.URI;
021import java.net.URL;
022import java.util.HashMap;
023import java.util.Map;
024
025import org.jivesoftware.smack.packet.IqData;
026import org.jivesoftware.smack.packet.XmlEnvironment;
027import org.jivesoftware.smack.parsing.SmackParsingException.SmackUriSyntaxParsingException;
028import org.jivesoftware.smack.provider.IqProvider;
029import org.jivesoftware.smack.util.ParserUtils;
030import org.jivesoftware.smack.xml.XmlPullParser;
031import org.jivesoftware.smack.xml.XmlPullParserException;
032
033import org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager;
034import org.jivesoftware.smackx.httpfileupload.UploadService;
035import org.jivesoftware.smackx.httpfileupload.element.Slot;
036import org.jivesoftware.smackx.httpfileupload.element.Slot_V0_2;
037
038import org.jxmpp.JxmppContext;
039
040/**
041 * Provider for Slot.
042 *
043 * @author Grigory Fedorov
044 * @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
045 */
046public class SlotProvider extends IqProvider<Slot> {
047
048    @Override
049    public Slot parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment, JxmppContext jxmppContext) throws XmlPullParserException, IOException, SmackUriSyntaxParsingException {
050        final String namespace = parser.getNamespace();
051
052        final UploadService.Version version = HttpFileUploadManager.namespaceToVersion(namespace);
053        assert version != null;
054
055        URL putUrl = null;
056        URL getUrl = null;
057        PutElement_V0_4_Content putElementV04Content = null;
058
059        outerloop: while (true) {
060            XmlPullParser.Event event = parser.next();
061
062            switch (event) {
063                case START_ELEMENT:
064                    String name = parser.getName();
065                    switch (name) {
066                        case "put": {
067                            switch (version) {
068                            case v0_2:
069                                String putUrlString = parser.nextText();
070                                putUrl = toUrl(putUrlString);
071                                break;
072                            case v0_3:
073                                putElementV04Content = parsePutElement_V0_4(parser);
074                                break;
075                            default:
076                                throw new AssertionError();
077                            }
078                            break;
079                        }
080                        case "get":
081                            String getUrlString;
082                            switch (version) {
083                            case v0_2:
084                                getUrlString = parser.nextText();
085                                break;
086                            case v0_3:
087                                getUrlString = parser.getAttributeValue(null, "url");
088                                break;
089                            default:
090                                throw new AssertionError();
091                            }
092                            getUrl = toUrl(getUrlString);
093                            break;
094                    }
095                    break;
096                case END_ELEMENT:
097                    if (parser.getDepth() == initialDepth) {
098                        break outerloop;
099                    }
100                    break;
101                default:
102                    // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
103                    break;
104            }
105        }
106
107        switch (version) {
108        case v0_3:
109            return new Slot(putElementV04Content.putUrl, getUrl, putElementV04Content.headers);
110        case v0_2:
111            return new Slot_V0_2(putUrl, getUrl);
112        default:
113            throw new AssertionError();
114        }
115    }
116
117    public static PutElement_V0_4_Content parsePutElement_V0_4(XmlPullParser parser) throws XmlPullParserException, IOException {
118        final int initialDepth = parser.getDepth();
119
120        String putUrlString = parser.getAttributeValue(null, "url");
121        URL putUrl = URI.create(putUrlString).toURL();
122
123        Map<String, String> headers = null;
124        outerloop: while (true) {
125            XmlPullParser.Event next = parser.next();
126            switch (next) {
127            case START_ELEMENT:
128                String name = parser.getName();
129                switch (name) {
130                case "header":
131                    String headerName = ParserUtils.getRequiredAttribute(parser, "name");
132                    String headerValue = ParserUtils.getRequiredNextText(parser);
133                    if (headers == null) {
134                        headers = new HashMap<>();
135                    }
136                    headers.put(headerName, headerValue);
137                    break;
138                default:
139                    break;
140                }
141                break;
142            case END_ELEMENT:
143                if (parser.getDepth() == initialDepth) {
144                    break outerloop;
145                }
146                break;
147            default:
148                // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
149                break;
150            }
151        }
152
153        return new PutElement_V0_4_Content(putUrl, headers);
154    }
155
156    public static final class PutElement_V0_4_Content {
157        private final URL putUrl;
158        private final Map<String, String> headers;
159
160        private PutElement_V0_4_Content(URL putUrl, Map<String, String> headers) {
161            this.putUrl = putUrl;
162            this.headers = headers;
163        }
164
165        public URL getPutUrl() {
166            return putUrl;
167        }
168
169        public Map<String, String> getHeaders() {
170            return headers;
171        }
172    }
173}