001/**
002 *
003 * Copyright 2005-2007 Jive Software.
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 */
017
018package org.jivesoftware.smackx.commands.provider;
019
020import java.io.IOException;
021
022import org.jivesoftware.smack.packet.IqData;
023import org.jivesoftware.smack.packet.StanzaError;
024import org.jivesoftware.smack.packet.XmlEnvironment;
025import org.jivesoftware.smack.parsing.SmackParsingException;
026import org.jivesoftware.smack.provider.ExtensionElementProvider;
027import org.jivesoftware.smack.provider.IqProvider;
028import org.jivesoftware.smack.util.PacketParserUtils;
029import org.jivesoftware.smack.xml.XmlPullParser;
030import org.jivesoftware.smack.xml.XmlPullParserException;
031
032import org.jivesoftware.smackx.commands.AdHocCommandNote;
033import org.jivesoftware.smackx.commands.SpecificErrorCondition;
034import org.jivesoftware.smackx.commands.packet.AdHocCommandData;
035import org.jivesoftware.smackx.commands.packet.AdHocCommandData.Action;
036import org.jivesoftware.smackx.commands.packet.AdHocCommandData.AllowedAction;
037import org.jivesoftware.smackx.commands.packet.AdHocCommandDataBuilder;
038import org.jivesoftware.smackx.xdata.packet.DataForm;
039import org.jivesoftware.smackx.xdata.provider.DataFormProvider;
040
041/**
042 * The AdHocCommandDataProvider parses AdHocCommandData packets.
043 *
044 * @author Gabriel Guardincerri
045 */
046public class AdHocCommandDataProvider extends IqProvider<AdHocCommandData> {
047
048    @Override
049    public AdHocCommandData parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
050        String commandNode = parser.getAttributeValue("node");
051        AdHocCommandDataBuilder builder = AdHocCommandData.builder(commandNode, iqData);
052        DataFormProvider dataFormProvider = new DataFormProvider();
053
054        String sessionId = parser.getAttributeValue("sessionid");
055        builder.setSessionId(sessionId);
056
057        // Status
058        String status = parser.getAttributeValue("", "status");
059        if (AdHocCommandData.Status.executing.toString().equalsIgnoreCase(status)) {
060            builder.setStatus(AdHocCommandData.Status.executing);
061        }
062        else if (AdHocCommandData.Status.completed.toString().equalsIgnoreCase(status)) {
063            builder.setStatus(AdHocCommandData.Status.completed);
064        }
065        else if (AdHocCommandData.Status.canceled.toString().equalsIgnoreCase(status)) {
066            builder.setStatus(AdHocCommandData.Status.canceled);
067        }
068
069        // Action
070        String action = parser.getAttributeValue("", "action");
071        if (action != null) {
072            Action realAction = Action.valueOf(action);
073            if (realAction == null) {
074                throw new SmackParsingException("Invalid value for action attribute: " + action);
075            }
076
077            builder.setAction(realAction);
078        }
079
080        // TODO: Improve parsing below. Currently, the next actions like <prev/> are not checked for the correct position.
081        outerloop:
082        while (true) {
083            String elementName;
084            XmlPullParser.Event event = parser.next();
085            String namespace = parser.getNamespace();
086            switch (event) {
087            case START_ELEMENT:
088                elementName = parser.getName();
089                switch (elementName) {
090                case "actions":
091                    String execute = parser.getAttributeValue("execute");
092                    if (execute != null) {
093                        builder.setExecuteAction(AllowedAction.valueOf(execute));
094                    }
095                    break;
096                case "next":
097                    builder.addAction(AllowedAction.next);
098                    break;
099                case "complete":
100                    builder.addAction(AllowedAction.complete);
101                    break;
102                case "prev":
103                    builder.addAction(AllowedAction.prev);
104                    break;
105                case "x":
106                    if (namespace.equals("jabber:x:data")) {
107                        DataForm form = dataFormProvider.parse(parser);
108                        builder.setForm(form);
109                    }
110                    break;
111                case "note":
112                    String typeString = parser.getAttributeValue("type");
113                    AdHocCommandNote.Type type;
114                    if (typeString != null) {
115                        type = AdHocCommandNote.Type.valueOf(typeString);
116                    } else {
117                        // Type is optional and 'info' if not present.
118                        type = AdHocCommandNote.Type.info;
119                    }
120                    String value = parser.nextText();
121                    builder.addNote(new AdHocCommandNote(type, value));
122                    break;
123                case "error":
124                    StanzaError error = PacketParserUtils.parseError(parser);
125                    builder.setError(error);
126                    break;
127                }
128                break;
129            case END_ELEMENT:
130                if (parser.getName().equals("command")) {
131                    break outerloop;
132                }
133                break;
134            default:
135                // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
136                break;
137            }
138        }
139
140        return builder.build();
141    }
142
143    public static class BadActionError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
144        @Override
145        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
146            return new AdHocCommandData.SpecificError(SpecificErrorCondition.badAction);
147        }
148    }
149
150    public static class MalformedActionError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
151        @Override
152        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
153            return new AdHocCommandData.SpecificError(SpecificErrorCondition.malformedAction);
154        }
155    }
156
157    public static class BadLocaleError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
158        @Override
159        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
160            return new AdHocCommandData.SpecificError(SpecificErrorCondition.badLocale);
161        }
162    }
163
164    public static class BadPayloadError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
165        @Override
166        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
167            return new AdHocCommandData.SpecificError(SpecificErrorCondition.badPayload);
168        }
169    }
170
171    public static class BadSessionIDError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
172        @Override
173        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
174            return new AdHocCommandData.SpecificError(SpecificErrorCondition.badSessionid);
175        }
176    }
177
178    public static class SessionExpiredError extends ExtensionElementProvider<AdHocCommandData.SpecificError> {
179        @Override
180        public AdHocCommandData.SpecificError parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)  {
181            return new AdHocCommandData.SpecificError(SpecificErrorCondition.sessionExpired);
182        }
183    }
184}