use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.
the class WalletOperations method importWalletPrivateKeys.
public void importWalletPrivateKeys() {
// TODO: Will need corrections once encryption is re-enabled!!!
int option = JOptionPane.showConfirmDialog(this.parent, "Private key import is a potentially slow operation. It may take\n" + "several minutes during which the GUI will be non-responsive.\n" + "The data to import must be in the format used by the option:\n" + "\"Export private keys...\"\n\n" + "Are you sure you wish to import private keys?", "Private key import notice...", JOptionPane.YES_NO_OPTION);
if (option == JOptionPane.NO_OPTION) {
return;
}
try {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Import wallet private keys from file...");
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showOpenDialog(this.parent);
if (result != JFileChooser.APPROVE_OPTION) {
return;
}
File f = fileChooser.getSelectedFile();
Cursor oldCursor = this.parent.getCursor();
try {
this.parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.clientCaller.importWallet(f.getCanonicalPath());
this.parent.setCursor(oldCursor);
} catch (WalletCallException wce) {
this.parent.setCursor(oldCursor);
Log.error("Unexpected error: ", wce);
JOptionPane.showMessageDialog(this.parent, "An unexpected error occurred while importing wallet private keys!" + "\n" + wce.getMessage().replace(",", ",\n"), "Error in importing wallet private keys...", JOptionPane.ERROR_MESSAGE);
return;
}
JOptionPane.showMessageDialog(this.parent, "Wallet private keys have been imported successfully from location:\n" + f.getCanonicalPath() + "\n\n", "Wallet private key import...", JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
this.errorReporter.reportError(e, false);
}
}
use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.
the class SendCashPanel method sendCash.
private void sendCash() throws WalletCallException, IOException, InterruptedException {
if (balanceAddressCombo.getItemCount() <= 0) {
JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.no.funds.text"), langUtil.getString("send.cash.panel.option.pane.no.funds.title"), JOptionPane.ERROR_MESSAGE);
return;
}
if (this.balanceAddressCombo.getSelectedIndex() < 0) {
JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.select.source.text"), langUtil.getString("send.cash.panel.option.pane.select.source.title"), JOptionPane.ERROR_MESSAGE);
return;
}
final String sourceAddress = this.lastAddressBalanceData[this.balanceAddressCombo.getSelectedIndex()][1];
final String destinationAddress = this.destinationAddressField.getText();
final String memo = this.destinationMemoField.getText();
final String amount = this.destinationAmountField.getText();
final String fee = this.transactionFeeField.getText();
// Verify general correctness.
String errorMessage = null;
if ((sourceAddress == null) || (sourceAddress.trim().length() <= 20)) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.source.address.invalid");
} else if (sourceAddress.length() > 512) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.source.address.too.long");
}
// TODO: full address validation
if ((destinationAddress == null) || (destinationAddress.trim().length() <= 0)) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.invalid");
} else if (destinationAddress.trim().length() <= 20) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.too.short");
} else if (destinationAddress.length() > 512) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.too.long");
} else if (destinationAddress.trim().length() != destinationAddress.length()) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.has.spaces");
}
if ((amount == null) || (amount.trim().length() <= 0)) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.amount.invalid");
} else {
try {
double d = Double.valueOf(amount);
} catch (NumberFormatException nfe) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.amount.not.number");
}
}
if ((fee == null) || (fee.trim().length() <= 0)) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.fee.invalid");
} else {
try {
double d = Double.valueOf(fee);
} catch (NumberFormatException nfe) {
errorMessage = langUtil.getString("send.cash.panel.option.pane.error.fee.not.number");
}
}
if (errorMessage != null) {
JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), errorMessage, langUtil.getString("send.cash.panel.option.pane.error.incorrect.sending.parameters"), JOptionPane.ERROR_MESSAGE);
return;
}
// ZClassic compatibility
if (!installationObserver.isOnTestNet()) {
if (!(destinationAddress.startsWith("zc") || destinationAddress.startsWith("zn") || destinationAddress.startsWith("zs"))) {
Object[] options = { "OK" };
JOptionPane.showOptionDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.error.destination.address.incorrect.text", destinationAddress), langUtil.getString("send.cash.panel.option.pane.error.destination.address.incorrect.title"), JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
// Do not send anything!
return;
}
}
// If a memo is specified, make sure the destination is a Z address.
if ((!installationObserver.isOnTestNet()) && (!Util.stringIsEmpty(memo)) && (!Util.isZAddress(destinationAddress))) {
int reply = JOptionPane.showConfirmDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.error.destination.address.notz.text", destinationAddress), langUtil.getString("send.cash.panel.option.pane.error.destination.address.notz.title"), JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.NO_OPTION) {
return;
}
}
// Check for encrypted wallet
final boolean bEncryptedWallet = this.clientCaller.isWalletEncrypted();
if (bEncryptedWallet) {
PasswordDialog pd = new PasswordDialog((JFrame) (SendCashPanel.this.getRootPane().getParent()));
pd.setVisible(true);
if (!pd.isOKPressed()) {
return;
}
this.clientCaller.unlockWallet(pd.getPassword());
}
// Call the wallet send method
operationStatusID = this.clientCaller.sendCash(sourceAddress, destinationAddress, amount, memo, fee);
// Make sure the keypool has spare addresses
if ((this.backupTracker.getNumTransactionsSinceLastBackup() % 5) == 0) {
this.clientCaller.keypoolRefill(100);
}
// Disable controls after send
sendButton.setEnabled(false);
balanceAddressCombo.setEnabled(false);
destinationAddressField.setEnabled(false);
destinationAmountField.setEnabled(false);
destinationMemoField.setEnabled(false);
transactionFeeField.setEnabled(false);
// Start a data gathering thread specific to the operation being executed - this is done is a separate
// thread since the server responds more slowly during JoinSPlits and this blocks he GUI somewhat.
final DataGatheringThread<Boolean> opFollowingThread = new DataGatheringThread<Boolean>(new DataGatheringThread.DataGatherer<Boolean>() {
public Boolean gatherData() throws Exception {
long start = System.currentTimeMillis();
Boolean result = clientCaller.isSendingOperationComplete(operationStatusID);
long end = System.currentTimeMillis();
Log.info("Checking for operation " + operationStatusID + " status done in " + (end - start) + "ms.");
return result;
}
}, this.errorReporter, 2000, true);
// Start a timer to update the progress of the operation
operationStatusCounter = 0;
operationStatusTimer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
// TODO: Handle errors in case of restarted server while wallet is sending ...
Boolean opComplete = opFollowingThread.getLastData();
if ((opComplete != null) && opComplete.booleanValue()) {
// End the special thread used to follow the operation
opFollowingThread.setSuspended(true);
SendCashPanel.this.reportCompleteOperationToTheUser(amount, sourceAddress, destinationAddress);
// Lock the wallet again
if (bEncryptedWallet) {
SendCashPanel.this.clientCaller.lockWallet();
}
// Restore controls etc.
operationStatusCounter = 0;
operationStatusID = null;
operationStatusTimer.stop();
operationStatusTimer = null;
operationStatusProhgressBar.setValue(0);
sendButton.setEnabled(true);
balanceAddressCombo.setEnabled(true);
destinationAddressField.setEnabled(true);
destinationAmountField.setEnabled(true);
transactionFeeField.setEnabled(true);
destinationMemoField.setEnabled(true);
} else {
// Update the progress
operationStatusLabel.setText(langUtil.getString("send.cash.panel.operation.status.progress.label"));
operationStatusCounter += 2;
int progress = 0;
if (operationStatusCounter <= 100) {
progress = operationStatusCounter;
} else {
progress = 100 + (((operationStatusCounter - 100) * 6) / 10);
}
operationStatusProhgressBar.setValue(progress);
}
SendCashPanel.this.repaint();
} catch (Exception ex) {
Log.error("Unexpected error: ", ex);
SendCashPanel.this.errorReporter.reportError(ex);
}
}
});
operationStatusTimer.setInitialDelay(0);
operationStatusTimer.start();
}
use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.
the class MessagingPanel method collectAndStoreNewReceivedMessages.
private void collectAndStoreNewReceivedMessages(MessagingIdentity groupIdentity) throws IOException, WalletCallException, InterruptedException {
MessagingIdentity ownIdentity = this.messagingStorage.getOwnIdentity();
// Check to make sure the Z address of the messaging identity is valid
if ((ownIdentity != null) && (!this.identityZAddressValidityChecked)) {
String ownZAddress = ownIdentity.getSendreceiveaddress();
String[] walletZaddresses = this.clientCaller.getWalletZAddresses();
boolean bFound = false;
for (String address : walletZaddresses) {
if (ownZAddress.equals(address)) {
bFound = true;
}
}
if (!bFound) {
JOptionPane.showMessageDialog(MessagingPanel.this.getRootPane().getParent(), "The messaging identity send/receive address: \n" + ownZAddress + "\n" + "is not found in the wallet.dat. The reason may be that after a mesaging identity\n" + "was created the wallet.dat was changed or the ZEN node configuration was changed\n" + "(e.g. mainnet -> testnet). If such a change was made, the messaging identity can no\n" + "longer be used. To avoid this error mesage, you may rename the directory:\n" + OSUtil.getSettingsDirectory() + File.separator + "messaging" + "\n" + "until the configuration or wallet.dat is restored! Directory may only be renamed when\n" + "the wallet is stopped!", "Messaging identity address is not found in walet!", JOptionPane.ERROR_MESSAGE);
return;
}
this.identityZAddressValidityChecked = true;
}
// Get the transaction IDs from all received transactions in the local storage
// TODO: optimize/cache this
Set<String> storedTransactionIDs = new HashSet<String>();
for (MessagingIdentity identity : this.messagingStorage.getContactIdentities(true)) {
for (Message localMessage : this.messagingStorage.getAllMessagesForContact(identity)) {
if ((localMessage.getDirection() == DIRECTION_TYPE.RECEIVED) && (!Util.stringIsEmpty(localMessage.getTransactionID()))) {
storedTransactionIDs.add(localMessage.getTransactionID());
}
}
}
if (ownIdentity == null) {
Log.warning("Own messaging identity does not exist yet. No received messages collected!");
return;
}
String ZAddress = (groupIdentity != null) ? groupIdentity.getSendreceiveaddress() : ownIdentity.getSendreceiveaddress();
// Get all known transactions received from the wallet
// TODO: there seems to be no way to limit the number of transactions returned!
JsonObject[] walletTransactions = this.clientCaller.getTransactionMessagingDataForZaddress(ZAddress);
// Filter the transactions to obtain only those that have memos parsable as JSON
// and being real messages. In addition only those remain that are not registered before
List<Message> filteredMessages = new ArrayList<Message>();
for (JsonObject trans : walletTransactions) {
String memoHex = trans.getString("memo", "ERROR");
String transactionID = trans.getString("txid", "ERROR");
if (!memoHex.equals("ERROR")) {
String decodedMemo = Util.decodeHexMemo(memoHex);
JsonObject jsonMessage = null;
try {
if (decodedMemo != null) {
jsonMessage = Util.parseJsonObject(decodedMemo);
}
} catch (Exception ex) {
Log.warningOneTime("Decoded memo is not parsable: {0}, due to {1}: {2}", decodedMemo, ex.getClass().getName(), ex.getMessage());
}
if ((jsonMessage != null) && ((jsonMessage.get("zenmsg") != null) && (!storedTransactionIDs.contains(transactionID)))) {
JsonObject innerZenmsg = jsonMessage.get("zenmsg").asObject();
if (Message.isValidZENMessagingProtocolMessage(innerZenmsg)) {
// Finally test that the message has all attributes required
Message message = new Message(innerZenmsg);
// Set additional message attributes not available over the wire
message.setDirection(DIRECTION_TYPE.RECEIVED);
message.setTransactionID(transactionID);
String UNIXDate = this.clientCaller.getWalletTransactionTime(transactionID);
message.setTime(new Date(Long.valueOf(UNIXDate).longValue() * 1000L));
// TODO: additional sanity check that T/Z addresses are valid etc.
filteredMessages.add(message);
} else {
// Warn of unexpected message content
Log.warningOneTime("Ignoring received mesage with invalid or incomplete content: {0}", jsonMessage.toString());
}
}
}
// End if (!memoHex.equals("ERROR"))
}
// for (JsonObject trans : walletTransactions)
MessagingOptions msgOptions = this.messagingStorage.getMessagingOptions();
// Finally we have all messages that are new and unprocessed. For every message we find out
// who the sender is, verify it and store it
boolean bNewContactCreated = false;
// Loop for processing standard (not anonymous messages)
standard_message_loop: for (Message message : filteredMessages) {
if (message.isAnonymous()) {
continue standard_message_loop;
}
MessagingIdentity contactID = this.messagingStorage.getContactIdentityForSenderIDAddress(message.getFrom());
// Check for ignored contact messages
if ((groupIdentity == null) && (contactID == null)) {
MessagingIdentity ignoredContact = this.messagingStorage.getIgnoredContactForMessage(message);
if (ignoredContact != null) {
Log.warningOneTime("Message detected from an ignored contact. Message will be ignored. " + "Message: {0}, Ignored contact: {1}", message.toJSONObject(false).toString(), ignoredContact.toJSONObject(false).toString());
continue standard_message_loop;
}
}
// Skip message if from an unknown user and options are not set
if ((groupIdentity == null) && (contactID == null) && (!msgOptions.isAutomaticallyAddUsersIfNotExplicitlyImported())) {
Log.warningOneTime("Message is from an unknown user, but options do not allow adding new users: {0}", message.toJSONObject(false).toString());
continue standard_message_loop;
}
if ((groupIdentity == null) && (contactID == null)) {
// Update list of contacts with an unknown remote user ... to be updated later
Log.warning("Message is from unknown contact: {0} . " + "A new Unknown_xxx contact will be created!", message.toJSONObject(false).toString());
contactID = this.messagingStorage.createAndStoreUnknownContactIdentity(message.getFrom());
bNewContactCreated = true;
}
// Verify the message signature
if (this.clientCaller.verifyMessage(message.getFrom(), message.getSign(), Util.encodeHexString(message.getMessage()).toUpperCase())) {
// Handle the special case of a messaging identity sent as payload - update identity then
if ((groupIdentity == null) && this.isZENIdentityMessage(message.getMessage())) {
this.updateAndStoreExistingIdentityFromIDMessage(contactID, message.getMessage());
}
message.setVerification(VERIFICATION_TYPE.VERIFICATION_OK);
} else {
// Set verification status permanently - store even invalid messages
Log.error("Message signature is invalid {0} . Message will be stored as invalid!", message.toJSONObject(false).toString());
message.setVerification(VERIFICATION_TYPE.VERIFICATION_FAILED);
}
this.messagingStorage.writeNewReceivedMessageForContact((groupIdentity == null) ? contactID : groupIdentity, message);
}
// Loop for processing anonymous messages
anonymus_message_loop: for (Message message : filteredMessages) {
if (!message.isAnonymous()) {
continue anonymus_message_loop;
}
// It is possible that it will find a normal identity to which we previously sent the first
// anonymous message (send scenario) or maybe an anonymous identity created by incoming
// message etc.
MessagingIdentity anonContctID = this.messagingStorage.findAnonymousOrNormalContactIdentityByThreadID(message.getThreadID());
// Check for ignored contact messages
if ((groupIdentity == null) && (anonContctID == null)) {
MessagingIdentity ignoredContact = this.messagingStorage.getIgnoredContactForMessage(message);
if (ignoredContact != null) {
Log.warningOneTime("Message detected from an ignored contact. Message will be ignored. " + "Message: {0}, Ignored contact: {1}", message.toJSONObject(false).toString(), ignoredContact.toJSONObject(false).toString());
continue anonymus_message_loop;
}
}
// Skip message if from an unknown user and options are not set
if ((groupIdentity == null) && (anonContctID == null) && (!msgOptions.isAutomaticallyAddUsersIfNotExplicitlyImported())) {
Log.warningOneTime("Anonymous message is from an unknown user, but options do not allow adding new users: {0}", message.toJSONObject(false).toString());
continue anonymus_message_loop;
}
if ((groupIdentity == null) && (anonContctID == null)) {
// Return address may be empty but we pass it
anonContctID = this.messagingStorage.createAndStoreAnonumousContactIdentity(message.getThreadID(), message.getReturnAddress());
Log.info("Created new anonymous contact identity: ", anonContctID.toJSONObject(false).toString());
bNewContactCreated = true;
} else if ((groupIdentity == null) && Util.stringIsEmpty(anonContctID.getSendreceiveaddress())) {
if (!Util.stringIsEmpty(message.getReturnAddress())) {
anonContctID.setSendreceiveaddress(message.getReturnAddress());
this.messagingStorage.updateAnonumousContactIdentityForThreadID(anonContctID.getThreadID(), anonContctID);
Log.info("Updated anonymous contact identity: ", anonContctID.toJSONObject(false).toString());
}
}
this.messagingStorage.writeNewReceivedMessageForContact((groupIdentity == null) ? anonContctID : groupIdentity, message);
}
if (bNewContactCreated) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
MessagingPanel.this.contactList.reloadMessagingIdentities();
} catch (Exception e) {
Log.error("Unexpected error in reloading contacts after gathering messages: ", e);
MessagingPanel.this.errorReporter.reportError(e);
}
}
});
}
// TODO: Call this only if anything was changed - e.g. new messages saved
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
// Reload the messages for the currently selected user
final MessagingIdentity selectedContact = MessagingPanel.this.contactList.getSelectedContact();
if (selectedContact != null) {
MessagingPanel.this.displayMessagesForContact(selectedContact);
}
} catch (Exception e) {
Log.error("Unexpected error in updating message pane after gathering messages: ", e);
MessagingPanel.this.errorReporter.reportError(e);
}
}
});
}
Aggregations