/* * Copyright (C) 2013 Sasha Vasko <sasha at aftercode dot net> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wifiafterconnect.html; import org.jsoup.nodes.Element; import android.util.Log; import com.wifiafterconnect.BuildConfig; import com.wifiafterconnect.Constants; import com.wifiafterconnect.WifiAuthParams; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class HtmlForm { // Empty strings if not available (see Jsoup docs : http://jsoup.org/apidocs/org/jsoup/nodes/Node.html#attr%28java.lang.String%29) protected String id; protected String action; protected String method; protected String onsubmit; protected URL actionURL; protected Map<String, HtmlInput> inputs = new HashMap<String,HtmlInput>(); // This will store inputs in the same order they are found in original HTML protected ArrayList<HtmlInput> inputsList = new ArrayList<HtmlInput>(); public void addInput (HtmlInput i) { if (i != null && i.isValid()) { inputs.put (i.getName(), i); inputsList.add (i); } } HtmlForm (Element e) { id = e.attr("id"); setAction(e.attr("action")); method = e.attr("method"); onsubmit = e.attr("onsubmit"); for (Element ie : e.getElementsByTag("input")) { if (BuildConfig.DEBUG) Log.d(Constants.TAG, "Parsing html: form input found : " + ie.toString()); boolean hidden = false; for (Element parent = ie.parent(); parent != e ; parent = parent.parent()) // this weirdness is used in Colubris (now owned by HP) portals: if (parent.hasClass("hidedata")|| parent.hasClass("hidden")) { hidden = true; break; } addInput(new HtmlInput (ie, hidden)); } } public String getOnsubmit() { return onsubmit; } public String getMethod () { return method.toUpperCase(Locale.ENGLISH); } public String getAction () { return action; } public String getId () { return id; } public Collection<HtmlInput> getInputs() { return inputs.values(); } public boolean hasInput (String name) { return inputs.containsKey(name); } public boolean hasInputWithClass (String classAttr) { for (HtmlInput i :inputs.values()) { if (i.isClass (classAttr)) return true; } return false; } public boolean hasVisibleInput (String name) { HtmlInput i = inputs.get(name); return (i != null && !i.isHidden()); } public HtmlInput getInput (String name) { return inputs.get(name); } public HtmlInput getVisibleInput (String name) { HtmlInput i = getInput (name); return (i == null || i.isHidden()) ? null : i; } public HtmlInput getVisibleInputByType (String type) { for (HtmlInput i :inputs.values()) { if (!i.isHidden() && i.matchType (type)) return i; } return null; } public boolean setInputValue (String name, String value) { HtmlInput i = inputs.get(name); if (i != null) i.setValue (value); return inputs.containsKey(name); } public String formatPostData () { StringBuilder postData = new StringBuilder(); for (HtmlInput i :inputsList) { i.formatPostData(postData); } if (postData.length() > 0) { if (postData.charAt(0) == '&') postData.deleteCharAt(0); } return postData.toString(); } public URL formatActionURL (URL originalURL) { URL result = originalURL; if (action != null) { String protocol; String authority = null; String file = action; String ref = null; if (actionURL != null) { protocol = actionURL.getProtocol(); authority = actionURL.getAuthority(); // we want to keep the query in as some portals use query params in post requests file = actionURL.getFile(); ref = actionURL.getRef(); }else { String origPath = originalURL.getPath(); //ignore query of original url if (file.isEmpty()) file = origPath; else if (!file.startsWith("/")) { file = origPath.substring(0, origPath.lastIndexOf('/')+1) + file; } protocol = originalURL.getProtocol(); } if (authority == null) authority = originalURL.getAuthority(); String urlString = protocol + "://" + authority; if (file != null) urlString += file; if (ref != null) urlString += "#" + ref; if (BuildConfig.DEBUG) Log.d(Constants.TAG, "actionURL string = [" + urlString + "]"); try { result = new URL (urlString); } catch (MalformedURLException e) { } }else { // TODO need to check for onclick="form.action=" in type="submit" inputs } return result; } public WifiAuthParams fillParams (WifiAuthParams params) { for (HtmlInput i :inputsList) { if (!i.isHidden() && !params.hasParam(i.getName())) { HtmlInput param = new HtmlInput (i); params.add(param); } } return params; } public boolean isParamMissing (WifiAuthParams params, final String paramName) { return (hasVisibleInput(paramName) && (params == null || !params.hasParam (paramName))); } public void fillInputs (WifiAuthParams params) { if (params != null) { for (HtmlInput f :params.getFields()) { String value = f.getValue(); HtmlInput i = inputs.get(f.getName()); if (i!=null) i.setValue(value); } } } public boolean isSubmittable() { boolean missingValues = false; boolean hasSubmit = false; for (HtmlInput i :inputs.values()) { if (!i.isHidden() && i.getValue().isEmpty() && (WifiAuthParams.isSupportedParamType(i) || i.matchType(HtmlInput.TYPE_CHECKBOX))) missingValues = true; if (i.matchType(HtmlInput.TYPE_SUBMIT)) hasSubmit = true; } return !missingValues && hasSubmit; } public void setAction(String switchUrl) { action = (switchUrl == null)? "" : switchUrl; try { actionURL = new URL(action); } catch (MalformedURLException ex) {actionURL = null;} } }