package net.whistlingfish.harmony.protocol; import static java.lang.String.format; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jivesoftware.smack.packet.IQ; public abstract class OAReplyParser { static Set<String> validResponses = new HashSet<>(); static { validResponses.add("100"); validResponses.add("200"); validResponses.add("506"); // Bluetooth not connected validResponses.add("566"); // Command not found for device, recoverable } public abstract IQ parseReplyContents(String statusCode, String errorString, String contents); /* * FIXME: This parser could be far cleaner than it is, given the possibility of the pseudo-json components * containing colons, and the structure of them */ static final Pattern kvRE = Pattern.compile("(.*?)=(.*)"); protected Map<String, Object> parseKeyValuePairs(String statusCode, String errorString, String contents) { Map<String, Object> params = new HashMap<>(); params.put("statusCode", statusCode); params.put("errorString", errorString); for (String pair : contents.split(":")) { Matcher matcher = kvRE.matcher(pair); if (!matcher.matches()) { continue; // throw new AuthFailedException(format("failed to parse element in auth response: %s", pair)); } Object valueObj; String value = matcher.group(2); if (value.startsWith("{")) { valueObj = parsePseudoJson(value); } else { valueObj = value; } params.put(matcher.group(1), valueObj); } return params; } protected Map<String, Object> parsePseudoJson(String value) { Map<String, Object> params = new HashMap<>(); value = value.substring(1, value.length() - 1); for (String pair : value.split(", ?")) { Matcher matcher = kvRE.matcher(pair); if (!matcher.matches()) { throw new AuthFailedException(format("failed to parse element in auth response: %s", value)); } params.put(matcher.group(1), parsePseudoJsonValue(matcher.group(2))); } return params; } private Object parsePseudoJsonValue(String value) { switch (value.charAt(0)) { case '{': return parsePseudoJsonValue(value); case '"': return value.substring(1, value.length() - 1); case '\'': return value.substring(1, value.length() - 1); default: try { return Long.parseLong(value); } catch (NumberFormatException e) { // do nothing } try { return Double.parseDouble(value); } catch (NumberFormatException e) { // do nothing } return value; } } public boolean validResponseCode(String code) { return validResponses.contains(code); } }