/* * Copyright 2013-2014 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package devcoin.wallet.ui; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface.OnClickListener; import com.google.devcoin.core.*; import com.google.devcoin.uri.BitcoinURI; import com.google.devcoin.uri.BitcoinURIParseException; import devcoin.wallet.Constants; import devcoin.wallet.R; import devcoin.wallet.util.Bluetooth; import devcoin.wallet.util.Qr; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.math.BigInteger; import java.util.regex.Pattern; /** * @author Andreas Schildbach */ public abstract class InputParser { public abstract static class StringInputParser extends InputParser { private final String input; public StringInputParser(@Nonnull final String input) { this.input = input; } @Override public void parse() { if (input.startsWith("devcoin:")) { try { final BitcoinURI bitcoinUri = new BitcoinURI(null, input); final Address address = bitcoinUri.getAddress(); final String addressLabel = bitcoinUri.getLabel(); final BigInteger amount = bitcoinUri.getAmount(); final String bluetoothMac = (String) bitcoinUri.getParameterByName(Bluetooth.MAC_URI_PARAM); bitcoinRequest(address, addressLabel, amount, bluetoothMac); } catch (final BitcoinURIParseException x) { error(R.string.input_parser_invalid_bitcoin_uri, input); } } else if (PATTERN_BITCOIN_ADDRESS.matcher(input).matches()) { try { final Address address = new Address(Constants.NETWORK_PARAMETERS, input); bitcoinRequest(address, null, null, null); } catch (final AddressFormatException x) { error(R.string.input_parser_invalid_address); } } else if (PATTERN_PRIVATE_KEY.matcher(input).matches()) { try { final ECKey key = new DumpedPrivateKey(Constants.NETWORK_PARAMETERS, input).getKey(); final Address address = new Address(Constants.NETWORK_PARAMETERS, key.getPubKeyHash()); bitcoinRequest(address, null, null, null); } catch (final AddressFormatException x) { error(R.string.input_parser_invalid_address); } } else if (PATTERN_TRANSACTION.matcher(input).matches()) { try { final Transaction tx = new Transaction(Constants.NETWORK_PARAMETERS, Qr.decodeBinary(input)); directTransaction(tx); } catch (final IOException x) { error(R.string.input_parser_invalid_transaction, x.getMessage()); } catch (final ProtocolException x) { error(R.string.input_parser_invalid_transaction, x.getMessage()); } } else { cannotClassify(input); } } } public abstract static class BinaryInputParser extends InputParser { private final String inputType; private final byte[] input; public BinaryInputParser(@Nonnull final String inputType, @Nonnull final byte[] input) { this.inputType = inputType; this.input = input; } @Override public void parse() { if (Constants.MIMETYPE_TRANSACTION.equals(inputType)) { try { final Transaction tx = new Transaction(Constants.NETWORK_PARAMETERS, input); directTransaction(tx); } catch (final ProtocolException x) { error(R.string.input_parser_invalid_transaction, x.getMessage()); } } else { cannotClassify(inputType); } } } public abstract void parse(); protected abstract void bitcoinRequest(@Nonnull Address address, @Nullable String addressLabel, @Nullable BigInteger amount, @Nullable String bluetoothMac); protected abstract void directTransaction(@Nonnull Transaction transaction); protected abstract void error(int messageResId, Object... messageArgs); protected void cannotClassify(@Nonnull final String input) { error(R.string.input_parser_cannot_classify, input); } protected void dialog(final Context context, @Nullable final OnClickListener dismissListener, final int titleResId, final int messageResId, final Object... messageArgs) { final Builder dialog = new AlertDialog.Builder(context); if (titleResId != 0) dialog.setTitle(titleResId); dialog.setMessage(context.getString(messageResId, messageArgs)); dialog.setNeutralButton(R.string.button_dismiss, dismissListener); dialog.show(); } private static final Pattern PATTERN_BITCOIN_ADDRESS = Pattern.compile("[" + new String(Base58.ALPHABET) + "]{20,40}"); private static final Pattern PATTERN_PRIVATE_KEY = Pattern.compile("5[" + new String(Base58.ALPHABET) + "]{50,51}"); private static final Pattern PATTERN_TRANSACTION = Pattern.compile("[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$\\*\\+\\-\\.\\/\\:]{100,}"); }