[Webfunds-commits] java/webfunds/client/sox SOXWallet.java

Jeroen C. van Gelderen gelderen@cypherpunks.ai
Thu, 6 Jul 2000 15:32:51 -0400 (AST)


gelderen    00/07/06 15:32:51

  Modified:    webfunds/client/sox SOXWallet.java
  Log:
  - Add makePurePayment that takes AccountIds instead of AccountInfos.
  - Add doDeposit that tries to be as pure as possible (no GUI, no client code).
  - Add mailItemToReceipt which does the obvious.
  - Remove couple of hacks from makeDeposit, they've moved to their
    own function (doDeposit).
  - Add diagnostics.
  - Pretty print diagnostics.
  - Formatting fixes.
  - Remove commented out code.

Revision  Changes    Path
1.126     +280 -101  java/webfunds/client/sox/SOXWallet.java

Index: SOXWallet.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/client/sox/SOXWallet.java,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -r1.125 -r1.126
--- SOXWallet.java	2000/06/20 21:06:50	1.125
+++ SOXWallet.java	2000/07/06 19:32:50	1.126
@@ -1,7 +1,7 @@
-/* $Id: SOXWallet.java,v 1.125 2000/06/20 21:06:50 iang Exp $
+/* $Id: SOXWallet.java,v 1.126 2000/07/06 19:32:50 gelderen Exp $
  *
- * Copyright (c) Systemics Ltd 1995-2000 on behalf of
- * the WebFunds Development Team.  All Rights Reserved.
+ * Copyright (c) Systemics Inc. 1995-2000 on behalf of
+ * The WebFunds Development Team.  All Rights Reserved.
  */
 package webfunds.client.sox;
 
@@ -23,11 +23,9 @@
 import webfunds.client.WalletContext;
 import webfunds.client.WalletInterface;
 import webfunds.client.sox.StoreAccountStore;
-
 import webfunds.ricardian.Contract;
 import webfunds.ricardian.ContractStore;
 import webfunds.ricardian.SOXServerException;
-
 import webfunds.sox.Account;
 import webfunds.sox.AccountId;
 import webfunds.sox.Armoury;
@@ -45,10 +43,8 @@
 import webfunds.sox.SOXSubAccountException;
 import webfunds.sox.SubAccount;
 import webfunds.sox.ValueAccount;
-
 import webfunds.store.Store;
 import webfunds.store.StoreException;
-
 import webfunds.utils.Debug;
 import webfunds.utils.Hex;
 import webfunds.utils.Panic;
@@ -56,6 +52,7 @@
 
 /**
  *  The GUI Wallet.
+ *
  *  Needs to be rewritten into 2 wallets, a highlevel WebFunds GUI
  *  wallet and a low level SOX wallet that returns all info internally.
  *
@@ -73,6 +70,9 @@
     // these should probably be protected
     public void error(String e)
     {
+        if(e==null) 
+            return;
+
         logmsg("[ " + e + " ]");
         context.getUInterface(this).errorMessage(e);
     }
@@ -94,11 +94,10 @@
     protected   Store                   store;
     protected   ContractStore           contracts = null;
     protected   Vector                  confirmmails = new Vector();
-    //protected final WalletAction[]      actions;
 
-    protected static final String name            = "SOX";
-    protected String shortname                    = name;
-    protected static final String fix             = "  SW: ";
+    protected static final String name = "SOX";
+    protected String shortname         = name;
+    protected static final String fix  = "  SW: ";
 
     protected static final String
         try_again_later = "Try again later - cannot get through.",
@@ -114,17 +113,6 @@
     public SOXWallet(PrintWriter bug)           { super(); debug(bug, fix); }
     public SOXWallet(PrintWriter bug, String f) { super(); debug(bug, f); }
 
-//  Nah, done by SubAccount extension.
-//    protected void addMine()
-//    {
-//        try {
-//            EncryptedRequest.add("SOX.Deposit", "webfunds.sox.DepositRequest");
-//        } catch (Exception ex) {
-//            logmsg("adding SOX.Deposit: " + ex);
-//            System.exit(1);  // should throw die exception
-//        }
-//    }
-
 
     /**
      * Set the WalletContext.
@@ -242,7 +230,11 @@
         //
         try
         {
+            System.err.println("Trying to get 'Accounts' store");
             Store st = store.getStore("Accounts");
+            System.err.println(
+                "  We got: " + st +
+                ", with size: " + st.size() );
             StoreAccountStore accs;
             accs = new StoreAccountStore(st, finder);
             accs.debug(bug);
@@ -420,15 +412,12 @@
                               long amount, byte[] desc,
                               Date from, Date till)
     {
-        //AccountId target = new AccountId();
-        //if (targetinfo != null)
-        //    target.setId(targetinfo.getId());
+        Payment pay = makePurePayment(source, targetinfo,
+                                      contractid, amount,
+                                      desc, 
+                                      from.getTime(), till.getTime(),
+                                      null);
 
-        Payment pay;
-        pay = makePurePayment(source, targetinfo,
-                              contractid, amount,
-                              desc, from.getTime(), till.getTime(), null);
-
         if (pay == null)
             return null ;
 
@@ -452,6 +441,24 @@
     }
 
 
+    public Payment makePurePayment(AccountId source, AccountId target,
+                                   ItemId instrument, long amount,
+                                   byte[] description,
+                                   long validFrom, long validTill, 
+                                   String paymentId)
+    {
+        return makePurePayment(
+                    new AccountInfo(source.getId(), null, null),
+                    new AccountInfo(target.getId(), null, null),
+                    instrument,
+                    amount,
+                    description,
+                    validFrom,
+                    validTill,
+                    paymentId);
+    }
+
+
     /**
      *  Make a payment.
      *  This should be used by all full service clients, it does:
@@ -519,8 +526,12 @@
 
 
         if ( amount > 0 &&
-           ((pend + confirmed) < amount || confirmed < amount))
+             ((pend + confirmed) < amount || confirmed < amount) )
         {
+            System.err.print("amount: " + amount);
+            System.err.print(", pend: " + pend);
+            System.err.println(", confirmed: " + confirmed);
+            
             Contract contract = contracts.getContract(contractid);
             double am = amount;
             String name = contractid.toString();
@@ -529,12 +540,10 @@
                 am = contract.getAmount(amount);
                 name = contract.getName();
             }
-            String descString = Hex.printable(desc);
 
             String q = "There is not enough for a payment of\n" +
                        "\n" +
-            "                   " + am + " " + name + "\n" +
-            "                   \"" + descString + "\"\n" +
+                       "                   " + am + " " + name + "\n" +
                        "\n" +
                        "and it may bounce when deposited!\n\n\n" +
                        "Are you sure you want to make this payment?";
@@ -612,16 +621,6 @@
 
     public void makeDeposit(byte[] payment, AccountInfo callerAc, byte[] desc)
     {
-        makeDeposit(payment, callerAc, desc, true);
-    }
-
-
-    /**
-     *  Client Wallet Interface
-     */
-    public void makeDeposit(byte[] payment, AccountInfo callerAc, byte[] desc,
-                            boolean useAddressBook)
-    {
         byte[] buf = decodeSOXPayment(payment);
         if (buf == null)
         {
@@ -660,6 +659,8 @@
         {
             if (pt.isBearer())
             {
+                logmsg("pt.isBearer() says 'true'");
+
                 // Ok, so it's bearer, and we can deposit it anywhere.
                 ac = getAccount(callerAc);
 
@@ -839,9 +840,6 @@
         }
 
 
-        if( useAddressBook )
-        {
-
         byte[] srcId = pss.getId();     // already checked
         AccountInfo source;
         source = context.getAddressbook(this).getInfo(srcId);
@@ -865,12 +863,208 @@
 
         aviso("Deposit from " + name + " is Good:\n" + statString);
 
-        } // useAddressBook
         internalUpdate(sub, mails);
 
         return ;
     }
 
+    private String _func;
+    private void ENTER(String s) { this._func = s; }
+    private void TRACE(String s) 
+    { 
+        System.err.println( "Wallet." + this._func + ": " + s );
+    }
+
+
+    /**
+     * Deposit the given payment.
+     *
+     * If the Payment is a bearer payment it is deposited in targetAccount.
+     * If not, targetAccount must be null.
+     *
+     * If the Payment 
+     */
+    public Receipt doDeposit(
+        Payment payment, 
+        AccountId accountToUse, 
+        byte[] desc)
+    throws DepositException
+    {
+        ENTER("doDeposit");
+        TRACE("payment="  + payment  + 
+            ", accountToUse=" + accountToUse + 
+            ", desc="     + desc     );
+
+        Payment pay = payment;
+
+        AccountId ptt = pay.getTarget();
+        AccountId pss = pay.getSource();
+
+        AccountInfo callerAc=new AccountInfo(accountToUse.getId(), null, null);
+        AccountInfo ps      =new AccountInfo(pss.getId(), null, null);
+        AccountInfo pt      =new AccountInfo(ptt.getId(), null, null);
+
+        String pid = pay.getId();
+
+
+        //
+        //  Acquire the account which does the deposit.
+        //  This might not be a participant in the activity.
+        //  Which makes it terribly complex.
+        //  Maybe this should be banned, or another flexible
+        //  interface provided.
+        //
+        Account ac;
+        boolean knownAccount = true;  // following code should work, except...
+        try
+        {
+            if (pt.isBearer())
+            {
+                System.err.println("it's a bearer payment!");
+                // Ok, so it's bearer, and we can deposit it anywhere.
+                ac = getAccount(callerAc);
+
+                if (ac == null)
+                    throw new RuntimeException("no target for bearer");
+
+                // this is who we are going to deposit the bearer into
+                ptt = ac.getId();
+                pt = new AccountInfo(ptt.getId(), null, this);
+                knownAccount = true;
+            }
+            else
+            {
+                System.err.println("JCvG: it's not a bearer payment");
+                //
+                //  We need to acquire an account, so as to get a
+                //  subaccount, so as to do a deposit.  It doesn't
+                //  actually make much difference which sub account
+                //  does the deposit, as the issuer checks that the
+                //  payment is good, not the deposit (unless bearer).
+                //  But, it's nice for the receipt if it is all
+                //  aligned.
+                //
+ // was this back to front?  Should look at target first...
+                ac = getAccount(ps);
+                if (ac == null)                      // not our target
+                {
+                    ac = getAccount(pt);
+                    if(ac == null)
+                        throw new DepositException(
+                            DepositException.UNKNOWN_ACCOUNT);
+                }
+            }
+        }
+        catch (StoreException ex)
+        {
+            ex.printStackTrace();
+            error("cannot recover accounts? " + ex);
+            throw new RuntimeException("Dunno, looks very wrong");
+        }
+
+
+        String choice = ac.getName();
+        logmsg("ready to deposit payment using " + choice + "\n" + pay);
+        if (desc == null)
+            desc = new byte[0];
+
+        //
+        // When we grab the subaccount, record if it doesn't exists,
+        // so we can add it later to the store.
+        //
+        ItemId item = pay.getItem();
+        boolean makeNewSub = false;
+        ValueAccount sub = (ValueAccount) ac.getSub(item);
+        if (sub == null)
+        {
+            makeNewSub = true;              // only if our account...
+            sub = new ValueAccount(item);
+            try {
+                ac.newSub(sub);
+            } catch (SOXSubAccountException ex) {
+                ex.printStackTrace();
+                error("cannot create SubAccount: " + ex);
+                throw new RuntimeException("cannot create subAccount");
+            } catch (SOXAccountException ex) {
+                ex.printStackTrace();
+                error("Account error: " + ex);
+                throw new RuntimeException("Account error: " + ex);
+            }
+        }
+
+        MailItem[] mails;
+        try {
+            mails = sub.deposit(pay, new String(desc));
+        } catch (SOXLaterException ex) {
+            throw new RuntimeException("later!");
+        } catch (SOXSubAccountException e) {
+            e.printStackTrace();
+            throw new DepositException(e.getNumber());
+        } catch (SOXException ex) {
+            throw new DepositException(DepositException.INSUFFICIENT_FUNDS);
+        }
+
+        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 RuntimeException(
+                "Deposit partial (no mail returned) try an update...");
+
+        String s = checkReceipt(mails[0], pss, ptt, item, pay.getQty());
+        if (s != null)
+            throw new RuntimeException("cancel receipt is not good: " + s);
+
+        if (makeNewSub && !knownAccount)      // only if our account...
+        {
+            // I think this is right.
+            aviso("Deposit is complete.\n\nAs the account is unknown,\nignoring mail and subs");
+            throw new RuntimeException("Account unknown???");
+        }
+
+        String statString = "";
+        //
+        // Some admin
+        //       - make a new sub by re-adding the account if needed.
+        //       - get a name for a new source account.
+        //
+        if (makeNewSub)
+        {
+            //
+            // The getSub() did all the account work,
+            // now just need to store it.
+            //
+            try {
+                accountStore.addAccount(ac);
+            } catch (StoreException ex) {
+                ex.printStackTrace(System.err);
+                logmsg("account " + ac + " sub " + sub);
+                logmsg("cannot add subaccount? " + ex);
+                System.exit(1);
+            }
+            aviso("Hmmm.  That worked, and created a new subaccount...\n" +
+                  "which you can't see :(  What you need is a workaround:" +
+                  "\n\nTo see the contract, hit [Add Contract] on this:" +
+                  "\n\n" + item + "\n\n" +
+                  "(as there is no way to tell the GUI what to do here!)");
+            statString += "\n    (subAccount made in " + ac + ")";
+        }
+
+
+        internalUpdate(sub, mails);
+
+        Receipt rcpt = mailItemToReceipt( mails[0] );
+        if( rcpt == null )
+            throw new DepositException(DepositException.NO_RECEIPT);
+        else
+            return rcpt;
+    }
+
 
 
     /**
@@ -892,7 +1086,25 @@
         return checkReceipt(receipt, p_src, p_tgt, p_item, amount);
     }
 
+
     /**
+     * Convert a MailItem to Receipt.
+     *
+     * @return Receipt or null
+     */
+    private Receipt mailItemToReceipt(MailItem mailItem)
+    {
+        try
+        {
+            return new Receipt( mailItem.getMessage() );
+        }
+        catch(SOXPacketException e1)
+        {
+            return null;
+        }
+    }
+
+    /**
      *  Check the receipt conforms to what was expected.
      *  @return an error string if not conformant, else null
      */
@@ -996,6 +1208,7 @@
         cancel(sub, pid);
     }
 
+
     /**
      *  Cancel a Payment (pid) within a SubAccount.
      *  And call the update.  This can be used by other wallets.
@@ -1134,6 +1347,7 @@
         return ;
     }
 
+
     /**
      *  Cancel a Payment (pid) within a SubAccount.
      *
@@ -1183,6 +1397,7 @@
         throw new RuntimeException("not implemented");
     }
 
+
     /**
      *  Cancel a Payment (pid) within a SubAccount.
      *  This can be used by other wallets, but be
@@ -1232,8 +1447,8 @@
     }
 
 
-
 ///////////  Account / Contract manipulations ////////////////////////
+
     public AccountInfo addAccount()
     {
 
@@ -1438,20 +1653,7 @@
 
             sub.freeze();
 
-//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-//            try {
-//                account.encode(baos);
-//                byte[] b = baos.toByteArray();
-//                logmsg("converting " + b.length + " bytes");
-//                Account ac = new Account(b);
-//            } catch (Exception ex) {
-//                logmsg("sunk " + ex);
-//                ex.printStackTrace();
-//                System.exit(1);
-//            }
-
-            try
-            {
+            try {
                 accountStore.addAccount(account);  // restorage saves freeze
             } catch (StoreException ex) {
                 ex.printStackTrace();
@@ -1512,6 +1714,7 @@
         return true;
     }
 
+
     /**
      *  Client Wallet Interface
      */
@@ -1611,6 +1814,7 @@
         manyUpdates(sub, null);           // sub is surrogate for account
     }
 
+
     /**
      *  Make an AccountInfo for this sub account.
      *  Gets the account, then the id.
@@ -1622,6 +1826,7 @@
         return new AccountInfo(id.getId(), null, this);
     }
 
+
     /**
      *  Make an AccountId for this sub account.
      *  Gets the account, then the id.
@@ -1633,6 +1838,7 @@
         return ac.getId();
     }
 
+
     /**
      *  Handle this mail that came via another request
      *  or another subaccount.
@@ -1647,6 +1853,7 @@
         manyUpdates(sub, mails);
     }
 
+
     protected void internalUpdate(SubAccount sub, MailItem mail)
     {
         MailItem[] mm = new MailItem[1];
@@ -1654,6 +1861,7 @@
         manyUpdates(sub, mm);
     }
 
+
     /**
      * Get and sign for the mail from the issuer for this account.
      */
@@ -1694,6 +1902,7 @@
         throw new RuntimeException("too many: mail appears to be spinning");
     }
 
+
     /**
      *  Do an update - one single cycle of request with sigs.
      *  Bummer.  There is a problem here.  Mail is requested
@@ -1714,8 +1923,9 @@
         try
         {
             mails = sub.update(confirms);
-        } catch (SOXLaterException e) {
-
+        } 
+        catch (SOXLaterException e)
+        {
             // Yeah, this real wrong.  Need to handle errors silently.
             // hmm, caller might not want a popup.  How to handle?
 
@@ -1733,11 +1943,11 @@
         return mails ;
     }
 
+
     /**
      * Do an update - one single cycle of request with sigs.
      */
-    protected MailId[] tryHandle(SubAccount sub,
-                               MailItem[] mails)
+    protected MailId[] tryHandle(SubAccount sub, MailItem[] mails)
     {
         Vector newConfirms = new Vector();
 
@@ -1785,12 +1995,12 @@
         return ok ;
     }
 
+
     /**
      *  For some reason, Receipts are stored on an account basis.
      */
     public boolean handleReceiptData(byte[] recdata, AccountId acct)
     {
-        
         Receipt rec = null;
         try {
             rec = new Receipt(recdata);
@@ -1801,9 +2011,10 @@
             return false ;
         }
         logmsg("Receipt : " + rec);
-	return handleReceipt(rec, acct);
+        return handleReceipt(rec, acct);
     }
 
+
     public boolean handleReceipt(Receipt rec, AccountId acct)
     {
         try {
@@ -1845,7 +2056,6 @@
     {
         Receipt[] receipts;
         PendingReceipt[] pendings;
-        //AccountId account = getId(info);
         AccountId acct = new AccountId();
         acct.setId(info.getId());
 
@@ -1928,39 +2138,8 @@
     }
 
 
-//    /**
-//     *  Unused.
-//     */
-//    public Transaction getPaymentStatus(byte[] paymentdata)
-//    {
-//        try
-//        {
-//            byte[] thing = Armoury.decode(new String(paymentdata));
-//            Payment pay = new Payment(thing);
-//            byte[] src = pay.getSource().getId();
-//            AccountInfo info = new AccountInfo(src, null, null);
-//            context.getAddressbook(this).updateInfo(info);
-//            Transaction[] trans = getTransactions(info, pay.getItem());
-//            String id = pay.getId();
-//            for (int i = 0; i < trans.length; i++)
-//            {
-//                if (trans[i].getTransId().equals(id))
-//                    return trans[i];
-//            }
-//        }
-//        catch (Exception ex)
-//        {
-//            error("get status failed: " + ex);
-//        }
-//        return null;
-//    }
-
-
-
     public String toString()
     {
         return shortname;
     }
-
-
 }