[Webfunds-commits] java/webfunds/client/utils UpgradesManager.java
Ian Grigg
iang@cypherpunks.ai
Thu, 9 Nov 2000 09:28:21 -0400 (AST)
iang 00/11/09 09:28:21
Modified: webfunds/client AccountBrowser.java AccountBrowserImpl.java
webfunds/client/plugins PluginManager.java
webfunds/client/sox SOXWallet.java WalletException.java
webfunds/client/utils UpgradesManager.java
Added: webfunds/client/sox/gui PaymentFrame.java
Log:
1. checnged the plugins model so that SOXWallet could add as well as Trader
2. moved and added Payment Frame as a plugin into SOXWallet
3. added Token and Rollover payments to above. Untested, don't use.
Revision Changes Path
1.8 +3 -3 java/webfunds/client/AccountBrowser.java
Index: AccountBrowser.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/AccountBrowser.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- AccountBrowser.java 2000/06/05 03:48:15 1.7
+++ AccountBrowser.java 2000/11/09 13:28:19 1.8
@@ -1,5 +1,5 @@
/*
- * $Id: AccountBrowser.java,v 1.7 2000/06/05 03:48:15 gelderen Exp $
+ * $Id: AccountBrowser.java,v 1.8 2000/11/09 13:28:19 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -17,6 +17,6 @@
void setWallets(WalletInterface[] wallets);
void setPlugins(PluginInfo[] plugins);
- void setPlugins(PluginInfo[] plugins, WalletInterface wi);
-
+ void startPlugins(PluginInfo[] plugins, WalletInterface wi);
+ void addPlugins(PluginInfo[] plugins, WalletInterface wi);
}
1.81 +36 -35 java/webfunds/client/AccountBrowserImpl.java
Index: AccountBrowserImpl.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/AccountBrowserImpl.java,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -r1.80 -r1.81
--- AccountBrowserImpl.java 2000/10/09 17:30:01 1.80
+++ AccountBrowserImpl.java 2000/11/09 13:28:19 1.81
@@ -1,5 +1,5 @@
/*
- * $Id: AccountBrowserImpl.java,v 1.80 2000/10/09 17:30:01 iang Exp $
+ * $Id: AccountBrowserImpl.java,v 1.81 2000/11/09 13:28:19 iang Exp $
*
* Copyright (c) Systemics Inc 1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -17,6 +17,7 @@
import java.util.*;
import webfunds.utils.Debug;
+import webfunds.utils.Panic;
import webfunds.client.sun.ExampleFileFilter;
import webfunds.sox.*;
import webfunds.client.sox.*;
@@ -1115,7 +1116,6 @@
popup.add(contractInfoAction);
popup.add(contractHelp);
- //popup.add(new JPopupMenu.Separator()); // now in plugged call
return popup ;
}
@@ -1130,7 +1130,6 @@
popup.add(accountInfoAction);
popup.add(accountHelp);
- //popup.add(new JPopupMenu.Separator());
return popup ;
}
@@ -1142,7 +1141,6 @@
popup.add(walletInfo);
popup.add(walletHelp);
- //popup.add(new JPopupMenu.Separator());
return popup ;
}
@@ -1197,29 +1195,47 @@
}
/**
- * Set a plugin for this wallet only.
+ * Start the plugins for this wallet only.
* Should be called after all common plugins above are set,
* as the already set ones are copied.
+ * May be called multiple times, ignored after first time.
+ *
+ * A concession to extended wallets that can't figure out who
+ * called what first...
*/
- public void setPlugins(PluginInfo[] plugins, WalletInterface wi)
+ public void startPlugins(PluginInfo[] plugins, WalletInterface wi)
{
- JPopupMenu menu;
+ if (contractPopups.get(wi) != null)
+ return ; // already called
//
// Need the standard plugin block first.
// If not there, must be the first time, so create a
// new default popup for this wallet.
//
- if (contractPopups.get(wi) == null)
- {
+ JPopupMenu menu;
+
menu = newContractPopup();
contractPopups.put(wi, menu);
menu = newAccountPopup();
accountPopups.put(wi, menu);
menu = newWalletPopup();
walletPopups.put(wi, menu);
- }
+ addPlugins(plugins, wi);
+
+ }
+
+ /**
+ * Add plugins to this wallet.
+ * Should be called after startPlugins() above, else will crash.
+ * May be called multiple times, each call inserts a line in the menu.
+ */
+ public void addPlugins(PluginInfo[] plugins, WalletInterface wi)
+ {
+ if (contractPopups.get(wi) == null)
+ throw new Panic("must call startPlugins first");
+
int len = plugins.length;
logmsg("adding " + len + " plugins");
@@ -1228,13 +1244,15 @@
for (int i = 0; i < len; i++)
{
- if (plugins[i].getContractAction() != null)
+ PluginInfo plugin = plugins[i];
+
+ if (plugin.getContractAction() != null)
{
JMenuItem item = new AccountBrowserMenuItem(
- plugins[i].getContractAction(),
- Plugin.CONTRACTMODE, plugins[i]);
+ plugin.getContractAction(),
+ Plugin.CONTRACTMODE, plugin);
item.addActionListener(this);
- item.setActionCommand(plugins[i].getClassname());
+ item.setActionCommand(plugin.getClassname());
if (conMenu == null) // signal for first time, add line
{
@@ -1243,13 +1261,13 @@
}
conMenu.add(item);
}
- if (plugins[i].getAccountAction() != null)
+ if (plugin.getAccountAction() != null)
{
JMenuItem item = new AccountBrowserMenuItem(
- plugins[i].getAccountAction(),
- Plugin.ACCOUNTMODE, plugins[i]);
+ plugin.getAccountAction(),
+ Plugin.ACCOUNTMODE, plugin);
item.addActionListener(this);
- item.setActionCommand(plugins[i].getClassname());
+ item.setActionCommand(plugin.getClassname());
if (accMenu == null) // signal for first time, add line
{
@@ -1258,19 +1276,6 @@
}
accMenu.add(item);
}
-// if (plugins[i].getGeneralAction() != null)
-// {
-// JMenuItem item = new AccountBrowserMenuItem(
-// plugins[i].getGeneralAction(),
-// Plugin.GENERALMODE, plugins[i]);
-// item.addActionListener(this);
-// item.setActionCommand(plugins[i].getClassname());
-//
-//// I don't understand this. Is GeneralAction the same as WalletPopup????
-// menu = (JPopupMenu)walletPopups.get(wi);
-// menu.add(item);
-// //pluginmenu.add(item);
-// }
}
}
@@ -1332,13 +1337,9 @@
JPopupMenu popup;
if (obj instanceof Contract || obj instanceof ItemId)
{
-//logmsg("getting popup");
popup = (JPopupMenu)contractPopups.get(wi);
-//if (popup != null) logmsg("wi popup " + popup.getClass());
if (popup == null) // wallet has no special plugins
popup = contractMainPopup;
-//logmsg("use popup " + popup);
-//if (popup != null) logmsg("use popup " + popup.getClass());
popup.show(treetable, evt.getX(), evt.getY());
}
else if (obj instanceof AccountInfo)
1.18 +39 -23 java/webfunds/client/plugins/PluginManager.java
Index: PluginManager.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/plugins/PluginManager.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- PluginManager.java 2000/09/26 03:19:07 1.17
+++ PluginManager.java 2000/11/09 13:28:19 1.18
@@ -1,5 +1,5 @@
/*
- * $Id: PluginManager.java,v 1.17 2000/09/26 03:19:07 iang Exp $
+ * $Id: PluginManager.java,v 1.18 2000/11/09 13:28:19 iang Exp $
*
* Copyright (c) 1995-2000 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -56,27 +56,40 @@
{
PluginInfo[] array;
- int pugs;
+ int len;
+ AccountBrowser ab = core.getAccountBrowser(this);
//
// The "official" WebFunds plugins.
//
- pugs = plugins.size();
- array = new PluginInfo[pugs];
- for (int i = 0; i < pugs; i++)
- array[i] = (PluginInfo)plugins.elementAt(i);
- core.getAccountBrowser(this).setPlugins(array, wi);
+ len = plugins.size();
+ array = new PluginInfo[len];
+ // for (int i = 0; i < len; i++)
+ // array[i] = (PluginInfo)plugins.elementAt(i);
+ plugins.copyInto(array);
+ ab.startPlugins(array, wi); // ignored if already done
//
// The additional plugins added by the wallet itself.
//
Vector wp = getPluginVector(wi);
- pugs = wp.size();
- array = new PluginInfo[pugs];
- for (int i = 0; i < pugs; i++)
- array[i] = (PluginInfo)wp.elementAt(i);
- core.getAccountBrowser(this).setPlugins(array, wi);
+ len = wp.size();
+ logmsg("plugged(" + wi.getClass() + ") with " + len + " plugins");
+ array = new PluginInfo[len];
+ // for (int i = 0; i < len; i++)
+ // array[i] = (PluginInfo)wp.elementAt(i);
+ wp.copyInto(array);
+ ab.addPlugins(array, wi);
+
+ }
+ /*
+ * Reset the wallet list so that extending wallets can start again.
+ */
+ public void unplug(Object obj)
+ {
+ logmsg("unplug(" + obj.getClass() + ")");
+ walletPlugins.remove(obj);
}
public void plugged()
@@ -92,6 +105,20 @@
core.getAccountBrowser(this).setPlugins(array);
}
+ public Vector getPluginVector(Object obj)
+ {
+ Vector v = (Vector) walletPlugins.get(obj);
+ if (v == null)
+ {
+ logmsg("new " + obj.getClass() + "");
+ v = new Vector();
+ walletPlugins.put(obj, v);
+ }
+ return v ;
+ }
+
+
+
protected void updateAccountBrowser()
{
logmsg("updateAccountBrowser()");
@@ -183,17 +210,6 @@
Vector plugins = getPluginVector(wi);
prepare(plugin, plugins);
//updateAccountBrowser();
- }
-
- public Vector getPluginVector(Object obj)
- {
- Vector v = (Vector) walletPlugins.get(obj);
- if (v == null)
- {
- v = new Vector();
- walletPlugins.put(obj, v);
- }
- return v ;
}
static final String spec = "plugin.ini";
1.138 +414 -43 java/webfunds/client/sox/SOXWallet.java
Index: SOXWallet.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/sox/SOXWallet.java,v
retrieving revision 1.137
retrieving revision 1.138
diff -u -r1.137 -r1.138
--- SOXWallet.java 2000/10/14 02:20:20 1.137
+++ SOXWallet.java 2000/11/09 13:28:20 1.138
@@ -1,4 +1,4 @@
-/* $Id: SOXWallet.java,v 1.137 2000/10/14 02:20:20 iang Exp $
+/* $Id: SOXWallet.java,v 1.138 2000/11/09 13:28:20 iang Exp $
*
* Copyright (c) Systemics Inc. 1995-2000 on behalf of
* The WebFunds Development Team. All Rights Reserved.
@@ -36,7 +36,14 @@
import webfunds.sox.ItemId;
import webfunds.sox.MailId;
import webfunds.sox.MailItem;
+
+import webfunds.sox.AbstractPayment;
+import webfunds.sox.PaymentFactory;
import webfunds.sox.Payment;
+import webfunds.sox.TokenPayment;
+import webfunds.sox.Token;
+import webfunds.sox.RandomToken;
+
import webfunds.sox.Receipt;
import webfunds.sox.SOXAccountException;
import webfunds.sox.SOXArgsException;
@@ -53,6 +60,9 @@
import webfunds.client.Addressbook;
import webfunds.client.Transaction;
import webfunds.client.UInterface;
+import webfunds.client.plugins.PluginManager;
+import webfunds.client.plugins.Plugin;
+import webfunds.client.plugins.PluginException;
import webfunds.client.plugins.WalletContext;
import webfunds.client.WalletInterface;
import webfunds.client.sox.StoreAccountStore;
@@ -156,8 +166,58 @@
logmsg(e);
throw new InternalError(e);
}
+
+ addPlugins(soxFrames);
+ }
+
+ /**
+ * As a Wallet, I can add additional plugins.
+ */
+ public final static String[] soxFrames = {
+ "webfunds.client.sox.gui.PaymentFrame",
+ };
+
+ protected void addPlugins(String[] frames)
+ {
+ logmsg("PM");
+ PluginManager tap;
+ try {
+ tap = context.getPluginManager((WalletInterface)this);
+ } catch (Throwable ex) {
+ return ; // must be low level wallet :(
+ }
+
+ tap.unplug(this);
+ for (int i = 0; i < frames.length; i++)
+ {
+ String frame = frames[i];
+ logmsg("pugging " + frame + ":");
+ Plugin plugin;
+ try
+ {
+ Class clas = Class.forName(frame);
+ logmsg("W Class is " + clas);
+ plugin = (Plugin)clas.newInstance();
+ }
+ catch (Throwable e)
+ {
+ e.printStackTrace(err());
+ error("W Plugin " + frame + " failed to invoke: " + e);
+ continue ;
+ }
+
+ tap.addPlugin(plugin, this);
+
+ // try {
+ // } catch (PluginException ex) {
+ // error("Plugin " + frame + " no good: " + ex);
+ // continue ;
+ // }
+ }
+ tap.plugged(this);
}
+
/**
* Shortname is used for the stores. Can be set by child.
*/
@@ -470,10 +530,16 @@
return items;
}
+
+
+/////////// Payments //////////////////////////////////////////
+
/**
* Make an ASCII-armoured payment, a la PGP armouring.
* Also updates the addressbook.
* Should targetinfo be an AccountInfo? We don't really know of it.
+ *
+ * Client Wallet Interface
*/
public byte[] makePayment(ItemId contractid, AccountInfo source,
AccountInfo targetinfo,
@@ -489,26 +555,18 @@
if (pay == null)
return null ;
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try {
- pay.encode(bos);
- } catch (IOException ex) {
- ex.printStackTrace();
- error("Payment no good: " + ex);
- return null ;
- }
-
- String retval = Armoury.encode("SOX MESSAGE", bos.toByteArray());
-
Addressbook ab = context.getAddressbook(this);
ab.updateInfo(source);
if (targetinfo != null)
ab.updateInfo(targetinfo);
- return retval.getBytes();
+ return asciiArmourWithError(pay);
}
+
+
+
/**
* Conversion between high level and low level.
*/
@@ -539,8 +597,8 @@
}
private boolean gotEnough(AccountId src,
- ItemId contractid,
- long amount)
+ ItemId contractid,
+ long amount)
{
long pend = getValue(src, contractid, true);
long confirmed = getValue(src, contractid, false);
@@ -670,25 +728,11 @@
return null ;
}
- // this disappears when we get new better StateReceipts....
- AccountInfo targetinfo = new AccountInfo(tgt.getId(), null, null);
- AccountInfo sourceinfo = new AccountInfo(src.getId(), null, null);
-
- //
- // Have to create and store the PendingReceipt securely
- // before returning the payment to the caller. Once
- // returned, we have lost control of it, so must have the
- // PendingReceipt receipt there for matching or cancelling.
- //
- PendingReceipt pending = new PendingReceipt(pay.getId(),
- contractid,
- sourceinfo, targetinfo,
- amount, desc, new Date());
try {
- receiptStore.addPendingReceipt(pending, src);
- } catch (StoreException ex) {
+ savePaymentAsPending(src, pay);
+ } catch (PaymentException ex) {
ex.printStackTrace();
- error("Error saving receipt");
+ error("Payment not saved: " + ex);
return null ;
}
@@ -787,10 +831,22 @@
"Payment no good: " + ex);
}
- // this disappears when we get new better StateReceipts....
- AccountInfo targetinfo = new AccountInfo(tgt.getId(), null, null);
- AccountInfo sourceinfo = new AccountInfo(src.getId(), null, null);
+ savePaymentAsPending(src, pay);
+ return pay ;
+ }
+
+
+ /**
+ * Save a payment made as Pending.
+ *
+ * @param pay the Payment written out but not as yet saved
+ * @except PaymentException if the save could not be effected
+ */
+ protected void savePaymentAsPending(AccountId src, AbstractPayment pay)
+ throws PaymentException
+ {
+
//
// Have to create and store the PendingReceipt securely
// before returning the payment to the caller. Once
@@ -798,9 +854,13 @@
// PendingReceipt receipt there for matching or cancelling.
//
PendingReceipt pending = new PendingReceipt(pay.getId(),
- contractid,
- sourceinfo, targetinfo,
- amount, desc, new Date());
+ pay.getItem(),
+ // disappears when we get new better StateReceipts....
+ new AccountInfo(src.getId(), null, null),
+ new AccountInfo(pay.getTarget().getId(), null, null),
+ pay.getQty(),
+ pay.getDesc(),
+ new Date());
try {
receiptStore.addPendingReceipt(pending, src);
} catch (StoreException ex) {
@@ -808,13 +868,314 @@
throw new PaymentException(PaymentException.UNKNOWN,
"Error saving Pending: " + ex);
}
+ }
+
+ /**
+ * Make a Rollover payment.
+ * This should be used by low level clients. It checks:
+ * * access to subaccounts,
+ * * saves the pending payment for later reconciliation.
+ * and delivers the payment back.
+ *
+ * It does not check balances (by definition).
+ * It is thread safe. Why?
+ *
+ * @param tgt the target account, should not be bearer, where funds go
+ * @param src the source account (to be frozen) where funds are
+ * @param contractid is the name of the contract, but this is only used
+ * to identify the issuer, all contracts at that issuer effected
+ * @param desc a description of what this payment is for (optional)
+ * @param boolean whether or not the payment is a rollover payment
+ * @param from the time from which the payment is valid
+ * @param till the time at which the payment will expire
+ */
+ public synchronized Payment makeRollover(AccountId src, AccountId tgt,
+ ItemId contractid,
+ byte[] desc,
+ long till)
+ throws PaymentException
+ {
+ if (isClosed())
+ throw new PaymentException(WalletException.CLOSED, closeReason());
+
+ Account acc;
+ try {
+ acc = getAccount(src);
+ } catch (StoreException ex) {
+ ex.printStackTrace();
+ throw new PaymentException(PaymentException.UNKNOWN_AC,
+ "Error getting account: " + ex);
+ }
+
+ /*
+ * There is always "enough" for a rollover...
+ */
+
+ ValueAccount sub;
+ Payment pay;
+ try {
+ sub = (ValueAccount) acc.getSub(contractid);
+ if (sub == null)
+ {
+ throw new PaymentException(PaymentException.UNKNOWN_SUB,
+ "unknown: " + contractid);
+ }
+ pay = sub.createPayment(tgt,
+ 0, /* value doesn't matter */
+ desc,
+ true, /* the flag that makes it Rollover */
+ System.currentTimeMillis(),
+ till,
+ null
+ );
+ } catch (SOXException ex) {
+ ex.printStackTrace();
+ throw new PaymentException(PaymentException.UNKNOWN,
+ "Payment no good: " + ex);
+ }
+
+ savePaymentAsPending(src, pay);
+
return pay ;
}
+
/**
- * Smart decoder.
+ * Make a Token payment.
+ * This should be used by all automatic clients, it does:
+ * * access to subaccounts,
+ * * checks balances, and
+ * * saves the pending payment for later reconciliation.
+ * and delivers the payment back. It is thread safe.
+ *
+ * @param tgt the target account, may be bearer
+ * @param src the source account where funds are written from
+ * @param contractid is the name of the contract
+ * @param amount the (contract) qty of items of which the payment is for
+ * @param desc a description of what this payment is for (optional)
+ * @param boolean whether or not the payment is a rollover payment
+ * @param from the time from which the payment is valid
+ * @param till the time at which the payment will expire
+ * @param type the type of token method from PaymentFactory
*/
+ public synchronized TokenPayment makeTokenPayment(
+ AccountId src, AccountId tgt,
+ ItemId contractid, long amount,
+ byte[] desc,
+ long from, long till,
+ int type)
+ throws PaymentException
+ {
+ if (isClosed())
+ throw new PaymentException(WalletException.CLOSED, closeReason());
+
+ if (amount < 0)
+ throw new IllegalArgumentException("amount " + amount + " < 0 !");
+
+ Account ac;
+ try {
+ ac = getAccount(src);
+ } catch (StoreException ex) {
+ ex.printStackTrace();
+ throw new PaymentException(PaymentException.UNKNOWN_AC,
+ "Error getting account: " + ex);
+ }
+
+ /*
+ * Check if there is enough.
+ * (There is always "enough" if the src is equal to the target
+ * or if the amount is zero... This is a judgement call of course.)
+ */
+ if ((amount > 0) &&
+ !gotEnough(src, contractid, amount))
+ {
+ throw new PaymentException(PaymentException.NOT_ENUF_FUNDS,
+ "amount " + amount + " not available");
+ }
+
+ ValueAccount sub;
+ sub = (ValueAccount) ac.getSub(contractid);
+ if (sub == null)
+ {
+ throw new PaymentException(PaymentException.UNKNOWN_SUB,
+ "unknown: " + contractid);
+ }
+
+ if (desc == null)
+ desc = new byte[0];
+
+ /*
+ * We need two payments: one is the proto token payment,
+ * the other is the cash to pay for it. Both need to be
+ * written, then saved. Then, we can attempt a deposit
+ * of the primary payment in order to pay for the proto.
+ *
+ * We need to write a payment to someone who can cash these
+ * payments ... it could be bearer, but here, let's make it
+ * "someone" and see what happens.
+ AccountId bearerFloat = new AccountId();
+ byte[] f = webfunds.sox.Crypto.digest("Random".getBytes());
+ bearerFloat.setId(f);
+ */
+
+ Payment pay;
+ try {
+ pay = sub.createPayment(new AccountId(), amount,
+ desc, false,
+ from, till,
+ null);
+ } catch (SOXException ex) {
+ ex.printStackTrace();
+ throw new PaymentException(ex.getNumber(), "SOXEx: " + ex);
+ }
+
+ Token[] tokens;
+ if (type == PaymentFactory.RANDOM_TOKEN)
+ tokens = RandomToken.getProtoTokens(amount);
+ else
+ {
+ throw new PaymentException(PaymentException.UNKNOWN_TYPE,
+ "Token Type " + type + " not supported");
+ }
+
+ TokenPayment proto;
+ String pid = pay.getId();
+ try {
+ proto = sub.createTokenPayment(tokens, desc, pid + "+");
+ } catch (SOXException ex) {
+ ex.printStackTrace();
+ throw new PaymentException(ex.getNumber(), "SOXEx: " + ex);
+ }
+
+ savePaymentAsPending(src, pay);
+// actually, what is the point of saving a proto payment?
+// savePaymentAsPending(src, proto);
+
+
+ //
+ // Beyond this point, failure leaves a dangling payment,
+ // cancel manually for now.
+ //
+ MailItem[] mails;
+ try {
+ mails = sub.deposit(pay, new String(desc), null);
+ } catch (SOXLaterException ex) {
+ throw new PaymentException(ex.getNumber(), "Later: " + ex);
+ } catch (SOXSubAccountException ex) {
+ throw new PaymentException(ex.getNumber(), "SOXSAEx: " + ex);
+ } catch (SOXException ex) {
+ throw new PaymentException(ex.getNumber(), "SOXEx: " + ex);
+ }
+
+ logmsg("received mails: " + mails.length);
+
+ //
+ // By convention, if mails are returned, 1st one is
+ // the one for this deposit.
+ // Others are for the (sub?) account.
+ // (Actually, as implemented, there is only one mail.)
+ //
+ if (mails == null)
+ {
+ throw new PaymentException(PaymentException.UNKNOWN,
+ "Withdraw partial (no mail returned) try an update ?");
+ }
+
+ /*
+ * As we have no clue who the payment went to, extract it
+ * out of the receipt so we can ... check it against the
+ * receipt.
+ */
+ byte[] b = mails[0].getMessage();
+ Receipt receipt;
+ try {
+ receipt = new Receipt(b);
+ } catch (SOXPacketException ex) {
+ throw new PaymentException(ex.getNumber(),
+ "SOXPEx on receipt: " + ex);
+ }
+ AccountId ptt = receipt.getTarget();
+
+ String s = checkReceipt(mails[0], src, ptt, contractid, pay.getQty());
+ if (s != null)
+ {
+ throw new PaymentException(PaymentException.UNKNOWN,
+ "cancel receipt is not good: " + s);
+ }
+
+ internalUpdate(sub, mails);
+
+ AbstractPayment pp = receipt.getExchangePayment();
+ if (pp == null && src.equals(receipt.getTarget()))
+ {
+ throw new PaymentException(PaymentException.UNKNOWN_TYPE,
+ "no Payment returned in Withdrawal"+
+ "\n\n(Issuer does not support this type of Payment)");
+ }
+ if ( !(pp instanceof TokenPayment) )
+ {
+ throw new PaymentException(PaymentException.UNKNOWN,
+ "AB is not TP? : " + pp.getClass() +
+ "\n\n" + pp.toString());
+ }
+ TokenPayment tp = (TokenPayment)pp;
+
+ if (!tp.isSigned())
+ {
+ throw new PaymentException(PaymentException.UNKNOWN,
+ "TP not signed? : " + tp.getClass() +
+ "\n\n" + pp.toString());
+ }
+ return tp;
+ }
+
+
+ public final static String SOX_MESSAGE = "SOX MESSAGE";
+
+ /**
+ * Make an ASCII-armoured message from a payment, a la PGP armouring.
+ * Low level wallet.
+ */
+ public byte[] asciiArmour(AbstractPayment pay)
+ throws PaymentException
+ {
+ if (pay == null)
+ throw new PaymentException("null");
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ pay.encode(bos);
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ throw new PaymentException("Payment no good: " + ex);
+ }
+
+ String s = Armoury.encode(SOX_MESSAGE, bos.toByteArray());
+
+ return s.getBytes();
+ }
+
+ /**
+ * Make an ASCII-armoured message from a payment, a la PGP armouring.
+ * High level wallet.
+ */
+ public byte[] asciiArmourWithError(AbstractPayment pay)
+ {
+ byte[] b;
+ try {
+ b = asciiArmour(pay);
+ } catch (PaymentException ex) {
+ error("Payment no good: " + ex);
+ return null ;
+ }
+
+ return b;
+ }
+
+ /**
+ * Smart decoder of SOX armoured messages.
+ */
public byte[] decodeSOXPayment(byte[] payment)
{
byte[] thing;
@@ -831,7 +1192,7 @@
logmsg("failed on Armoury.decode, trying decodeByteArray");
try {
- thing = Armoury.decodeByteArray("SOX MESSAGE", pay);
+ thing = Armoury.decodeByteArray(SOX_MESSAGE, pay);
return thing;
} catch (Exception ex) { }
@@ -841,6 +1202,9 @@
}
+
+/////////// Deposit //////////////////////////////////////////
+
public void makeDeposit(byte[] payment, AccountInfo callerAc, byte[] desc)
{
if (isClosed())
@@ -1404,6 +1768,8 @@
+/////////// Cancel ////////////////////////
+
/**
* Cancel many Transactions. Provides a chance to batch
* up the transactions. All details should be the same
@@ -1748,6 +2114,7 @@
}
+
/////////// Account / Contract manipulations ////////////////////////
/**
@@ -2260,9 +2627,12 @@
// Would often be two cycles, might be 3 if
// something arrived during the process.
// Too many cycles would probably indicate a bug
- // somewhere.
+ // somewhere. Although, if someone does a whole
+ // bunch of transactions, this can cause a steady
+ // series of cycles. Better to back off in that
+ // case. (Like if WebFunds does a hundred cancels...)
//
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 10; i++)
{
mails = tryUpdate(sub, confirms);
if (mails == null || (mails.length == 0))
@@ -2281,7 +2651,8 @@
return ;
}
- throw new Panic("too many: mail appears to be spinning");
+ logmsg("too many: mail appears to be spinning");
+ return ;
}
1.7 +3 -2 java/webfunds/client/sox/WalletException.java
Index: WalletException.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/sox/WalletException.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- WalletException.java 2000/09/30 18:50:14 1.6
+++ WalletException.java 2000/11/09 13:28:20 1.7
@@ -1,5 +1,5 @@
/*
- * $Id: WalletException.java,v 1.6 2000/09/30 18:50:14 iang Exp $
+ * $Id: WalletException.java,v 1.7 2000/11/09 13:28:20 iang Exp $
*
* Copyright (c) 2000 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -37,8 +37,9 @@
NOT_ENUF_FUNDS = 108, // asking for too much!
PID_IN_USE = 109, // requested pid already used
CLOSED = 110, // wallet has been shut down
+ UNKNOWN_TYPE = 111, // what type of payment?
- LAST_WALLET_ERRNO = 110;
+ LAST_WALLET_ERRNO = 111;
/**
* Use these rather than worry about which number...
1.1 java/webfunds/client/sox/gui/PaymentFrame.java
Index: PaymentFrame.java
===================================================================
/*
* $Id: PaymentFrame.java,v 1.1 2000/11/09 13:28:20 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.client.sox.gui;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.util.Date;
import webfunds.utils.Hex;
import webfunds.sox.*;
import webfunds.ricardian.Contract;
import webfunds.client.WalletInterface;
import webfunds.client.AccountInfo;
import webfunds.client.plugins.Plugin;
import webfunds.client.plugins.ModeNotSupportedException;
import webfunds.client.sox.PaymentException;
import webfunds.client.sox.SOXWallet;
/**
* This is a specialist SOX payment gui dialog, that knows all
* about the non-generic payments such as rollover and token.
*/
public class PaymentFrame
extends Plugin implements ActionListener
{
protected String name = "PaymentFrame";
protected String contractaction = "Pay";
public String getPluginName() { return name; }
public String getContractAction() { return contractaction; }
JFrame frame;
TextField amount;
TextField target1;
JTextField validFrom;
JTextField validTill;
TextArea paybox;
SOXWallet wallet;
AccountInfo source;
AccountId src;
JTextArea description;
JComboBox target2;
JComboBox typeChoice;
ItemId contractid;
Contract contract;
String contractName;
String title;
protected final static String TEXT_PAY = "Make Payment",
DIRECT_TFR = "Direct Deposit";
protected final static String SOX = "SOX", FRZ = "Rollover",
BRN = "Big Random Numbers", DAW = "Wagner";
protected final static String[] types = { SOX, FRZ, BRN, DAW };
public PaymentFrame() { }
public void init(WalletInterface wi, AccountInfo source, ItemId contractId)
throws ModeNotSupportedException
{
//System.err.println("PluginManager: " + pm);
if ( !(wi instanceof SOXWallet) )
throw new ModeNotSupportedException("wallet is not SOX: " + wi);
wallet = (SOXWallet)wi;
this.source = source;
this.contractid = contractId;
if (source == null)
throw new IllegalArgumentException("source == null");
src = new AccountId();
src.setId(source.getId());
// might be null
contract = cs.getContract(contractid);
contractName = (contract==null) ? contractid.fp() : contract.getName();
title = "Payment in " + contractName +
" from account: " + source.toString();
try
{
AccountInfo[] accounts = pm.getAddressbook(this).getAccounts();
DefaultComboBoxModel acList;
acList = new DefaultComboBoxModel(accounts);
AccountInfo bearer = new AccountInfo();
acList.insertElementAt(bearer, 0);
acList.setSelectedItem(bearer);
DefaultComboBoxModel typeList;
typeList = new DefaultComboBoxModel(types);
typeList.setSelectedItem(SOX);
amount = new TextField(15);
target1 = new TextField(15);
target2 = new JComboBox(acList);
validFrom = new JTextField(15);
validTill = new JTextField(15);
typeChoice = new JComboBox(typeList);
paybox = new TextArea(20, 55);
description = new JTextArea(5, 15);
frame = new JFrame(title);
JPanel pane = (JPanel)frame.getContentPane();
JLabel amountlbl = new JLabel("Amount:");
JLabel target1lbl = new JLabel("Target:");
JLabel target2lbl = new JLabel("Target:");
JLabel validFromlbl = new JLabel("Valid from:");
JLabel validTilllbl = new JLabel("Valid till:");
JLabel typelbl = new JLabel("Type:");
JLabel desclbl = new JLabel("Description:");
JButton ok = new JButton(TEXT_PAY);
JButton directdeposit = new JButton(DIRECT_TFR);
JButton close = new JButton("Close");
JPanel butpanel = new JPanel();
JPanel textpanel = new JPanel();
JMenuBar menu = new JMenuBar();
JMenu filemenu = new JMenu("File");
JMenuItem exititem = new JMenuItem("Close");
JMenuItem configureitem = new JMenuItem("Configure");
// why won't the menu show?
frame.setJMenuBar(menu);
menu.add(filemenu);
filemenu.add(configureitem);
filemenu.add(new JSeparator());
filemenu.add(exititem);
ok.setToolTipText("Write a Cut & Pastable Payment into Box");
directdeposit.setToolTipText("Write Payment and Deposit to Target");
close.setToolTipText("Close Dialog");
exititem.addActionListener(this);
configureitem.addActionListener(this);
ok.addActionListener(this);
close.addActionListener(this);
directdeposit.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//description.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
//paybox.setEnabled(false);
filemenu.setMnemonic('f');
exititem.setMnemonic('x');
configureitem.setMnemonic('n');
ok.setMnemonic('m');
close.setMnemonic('c');
amountlbl.setLabelFor(amount);
target1lbl.setLabelFor(target1);
target2lbl.setLabelFor(target2);
validFromlbl.setLabelFor(validFrom);
validTilllbl.setLabelFor(validTill);
typelbl.setLabelFor(typeChoice);
desclbl.setLabelFor(description);
textpanel.setLayout(new GridBagLayout());
int x = 0;
int y = 0;
GridBagConstraints c = new GridBagConstraints();
//
// Column 0: Labels
//
c.gridx = x++;
c.gridy = y++;
c.gridwidth = GridBagConstraints.RELATIVE;
c.gridheight = 1;
c.weightx = 0;
c.weighty = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.NONE;
c.insets = new Insets(10, 3, 3, 3);
textpanel.add(amountlbl, c);
c.gridy = y++;
c.insets = new Insets(3, 3, 3, 3);
textpanel.add(target1lbl, c);
c.gridy = y++;
textpanel.add(target2lbl, c);
c.gridy = y++;
textpanel.add(validFromlbl, c);
c.gridy = y++;
textpanel.add(validTilllbl, c);
c.gridy = y++;
textpanel.add(typelbl, c);
c.gridy = y++;
c.weighty = 1;
textpanel.add(desclbl, c);
y = 0;
//
// Column 1: Boxes
//
c.gridx = x++;
c.gridy = y++;
c.weighty = 0;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(10, 3, 3, 3);
textpanel.add(amount, c);
c.gridy = y++;
c.insets = new Insets(3, 3, 3, 3);
textpanel.add(target1, c);
c.gridy = y++;
textpanel.add(target2, c);
c.gridy = y++;
textpanel.add(validFrom, c);
c.gridy = y++;
textpanel.add(validTill, c);
c.gridy = y++;
textpanel.add(typeChoice, c);
c.gridy = y++;
c.weighty = 1;
textpanel.add(description,c);
/*
* Build the Pane: add the options panel (textpanel).
*/
pane.setLayout(new GridBagLayout());
GridBagConstraints ct = new GridBagConstraints();
ct.gridx = 1;
ct.gridy = 0;
ct.gridwidth = GridBagConstraints.REMAINDER;
ct.gridheight = GridBagConstraints.RELATIVE;
ct.fill = GridBagConstraints.HORIZONTAL;
ct.insets = new Insets(3, 3, 3, 3);
ct.anchor = GridBagConstraints.NORTHWEST;
ct.weightx = 0.7;
ct.weighty = 1;
pane.add(textpanel,ct);
/*
* Add the buttons panel at bottom.
*/
butpanel.add(ok);
butpanel.add(directdeposit);
butpanel.add(close);
GridBagConstraints cb = new GridBagConstraints();
cb.gridx = 0;
cb.gridy = 1;
cb.gridwidth = GridBagConstraints.REMAINDER;
cb.gridheight = GridBagConstraints.REMAINDER;
cb.fill = GridBagConstraints.BOTH;
cb.insets = new Insets(3, 3, 3, 3);
cb.weightx = 0;
cb.weighty = 0;
pane.add(butpanel, cb);
/*
* Add the payments panel at left.
*/
GridBagConstraints cp = new GridBagConstraints();
cp.gridx = 0;
cp.gridy = 0;
cp.gridwidth = GridBagConstraints.RELATIVE;
cp.gridheight = GridBagConstraints.RELATIVE;
cp.anchor = GridBagConstraints.NORTHWEST;
cp.weightx = 0.3;
cp.weighty = 0;
cp.fill = GridBagConstraints.BOTH;
cp.insets = new Insets(3, 3, 3, 3);
pane.add(paybox, cp);
frame.pack();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
if (frame != null)
{
frame.show();
}
}
public void actionPerformed(ActionEvent evt)
{
String command = evt.getActionCommand();
//
// dispose of the easy cases first
//
if (command.equals("Close"))
{
frame.dispose();
this.stop();
return ;
}
else if (command.equals("Configure"))
{
System.out.println("Should bring up config screen");
return ;
}
//
// Now we have to do a payment. Sort out standard details first.
//
// amount in units of contract
double dub;
try {
dub = new Double(amount.getText()).doubleValue();
} catch (NumberFormatException ex) {
String e = "Please specify an amount of " + contractName;
pm.getUInterface(this).errorMessage(e);
return ;
}
long longamount = contract.getUnitsOfContract(dub);
//
// Get the target. Text box of KHID overrides address book list.
// Default is bearer.
//
AccountInfo target = (AccountInfo)target2.getSelectedItem();
String tgtName = target1.getText();
if (!"".equals(tgtName)) // text box is (also?) set, use it
{
byte[] bytes = Hex.hex2data(tgtName);
target = new AccountInfo(bytes, null, null);
}
else if (target.isBearer()) // what does target return ?
tgtName = "BEARER";
else
tgtName = target.getName() + " (" + Hex.data2hex(target.getId()) + ")";
// expiry date and earliest date
Date validFrom = new Date(0);
long future = 5 * 24 * 60 * 60 * 1000;
Date validTill = new Date(System.currentTimeMillis() + future);
AccountId tgt = new AccountId();
if (target != null) // target probably bearer
tgt.setId(target.getId());
//
// Extract the payment from the wallet. What sort?
//
String typ = (String)typeChoice.getSelectedItem();
byte[] pay = null;
byte[] desc = description.getText().getBytes();
AbstractPayment payment = null;
long from = validFrom.getTime();
long till = validTill.getTime();
String typeString = typ;
if (SOX.equals(typ))
{
// the payment itself
pay = wallet.makePayment(contractid, source, target,
longamount, desc,
validFrom, validTill);
if (pay == null) // wallet encountered error, already reported
return ;
}
if (FRZ.equals(typ))
{
// a rollover payment causes account to freeze and transfer funds
try {
payment = wallet.makeRollover(src, tgt,
contractid,
desc,
till);
} catch (PaymentException ex) {
String e = "Failed: " + ex;
wallet.error(e);
return ;
}
String q = "This experimental ROLLOVER payment is highly dangerous"+
" and could lose your value." +
"\n\nAre you absolutely sure?";
if ( !wallet.ask(q) )
return;
pay = wallet.asciiArmourWithError(payment);
if (pay == null)
return;
typeString = "Rollover";
}
else if (BRN.equals(typ))
{
// the payment itself
try {
payment = wallet.makeTokenPayment(src, tgt,
contractid, longamount,
desc,
from, till,
webfunds.sox.PaymentFactory.RANDOM_TOKEN);
} catch (PaymentException ex) {
String e = "didn't work: " + ex;
wallet.error(e);
return ;
}
if (payment == null)
return ;
String q = "This experimental TOKEN payment is highly dangerous "+
"and could lose your value." +
"\n\nAre you absolutely sure?";
if ( !wallet.ask(q) )
return;
pay = wallet.asciiArmourWithError(payment);
if (pay == null)
return;
}
else if (DAW.equals(typ))
{
String e = "Sorry, this payment type not yet available.";
wallet.error(e);
return ;
}
//
// Two sorts of delivery - direct transfer or make payment for email.
//
if (TEXT_PAY.equals(command))
{
double am = contract.getUnitsOfAccount(longamount);
String tla = contract.getField("currency", "currency_tla");
String nam = "";
if (tla == null)
{
nam = " " + contractName;
tla = "";
}
else
tla = tla + " ";
String msg = "\nThis is a " + typeString +
" payment for " + tla + am + nam +
"\nfrom " + source.getName() +
" (" + Hex.data2hex(source.getId()) + ")" +
"\nto " + tgtName +
"\nCut and Paste the following lines into an email:" +
"\n";
// " from wallet " + wallet.getShortName() +
paybox.append(msg);;
paybox.append(new String(pay));
Toolkit toolkit = Toolkit.getDefaultToolkit();
Clipboard clipboard = toolkit.getSystemClipboard();
StringSelection string = new StringSelection(paybox.getText());
clipboard.setContents(string, string);
}
else if (DIRECT_TFR.equals(command))
{
if (target == null || target.isBearer())
{
String e = "You have to specify a target";
pm.getUInterface(this).errorMessage(e);
return ;
}
wallet.makeDeposit(pay, target, "Deposit".getBytes());
// frame.dispose();
// this.stop();
// pm.getUInterface(this).infoMessage("Transfer done!");
}
}
}
1.2 +1 -3 java/webfunds/client/utils/UpgradesManager.java
Index: UpgradesManager.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/utils/UpgradesManager.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- UpgradesManager.java 2000/10/07 01:12:45 1.1
+++ UpgradesManager.java 2000/11/09 13:28:21 1.2
@@ -1,5 +1,5 @@
/*
- * $Id: UpgradesManager.java,v 1.1 2000/10/07 01:12:45 iang Exp $
+ * $Id: UpgradesManager.java,v 1.2 2000/11/09 13:28:21 iang Exp $
*
* Copyright (c) 2000 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -37,11 +37,9 @@
protected String name = "UpgradesManager";
protected String generalaction = "UpgradesManager";
- protected String contractaction = "View Upgrades";
public String getPluginName() { return name; }
public String getGeneralAction() { return generalaction; }
- public String getContractAction() { return contractaction; }
public static final String INSTALL_BUTTON = "Install Upgrade";
public static final String GO_BUTTON = "Go!";