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