Merge branch '0.5.x' into 0.6.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Mon, 16 Apr 2012 01:15:48 +0000 (21:15 -0400)
committerLuke Dashjr <luke-jr+git@utopios.org>
Mon, 16 Apr 2012 01:15:48 +0000 (21:15 -0400)
Conflicts:
src/qt/bitcoin.cpp
src/qt/bitcoingui.cpp
src/qt/guiutil.cpp
src/qt/guiutil.h
src/qt/sendcoinsdialog.cpp
src/qt/sendcoinsdialog.h
src/util.cpp

1  2 
doc/assets-attribution.txt
src/bignum.h
src/bitcoinrpc.cpp
src/keystore.h
src/qt/bitcoin.cpp
src/qt/bitcoingui.cpp
src/qt/sendcoinsdialog.cpp
src/qt/walletmodel.h
src/uint256.h
src/util.cpp

@@@ -1,3 -1,7 +1,7 @@@
+ Code: src/strlcpy.h
+ Author: Todd C. Miller <Todd.Miller@courtesan.com>
+ License: ISC
  Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png,
        src/qt/res/src/*.svg
  Designer: Wladimir van der Laan
@@@ -7,7 -11,7 +11,7 @@@ Icon: src/qt/res/icons/address-book.png
        src/qt/res/icons/history.png, src/qt/res/icons/key.png,
        src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png,
        src/qt/res/icons/receive.png, src/qt/res/icons/send.png,
 -      src/qt/res/icons/synced.png
 +      src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png
  Icon Pack: NUVOLA ICON THEME for KDE 3.x
  Designer: David Vignoni (david@icon-king.com)
            ICON KING - www.icon-king.com
diff --combined src/bignum.h
@@@ -1,5 -1,5 +1,5 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
 -// Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_BIGNUM_H
@@@ -11,7 -11,6 +11,7 @@@
  
  #include "util.h"
  
 +/** Errors thrown by the bignum class */
  class bignum_error : public std::runtime_error
  {
  public:
@@@ -19,7 -18,7 +19,7 @@@
  };
  
  
 -
 +/** RAII encapsulated BN_CTX (OpenSSL bignum context) */
  class CAutoBN_CTX
  {
  protected:
@@@ -47,7 -46,7 +47,7 @@@ public
  };
  
  
 -
 +/** C++ wrapper for BIGNUM (OpenSSl bignum) */
  class CBigNum : public BIGNUM
  {
  public:
      {
          unsigned long n = BN_get_word(this);
          if (!BN_is_negative(this))
 -            return (n > INT_MAX ? INT_MAX : n);
 +            return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
          else
 -            return (n > INT_MAX ? INT_MIN : -(int)n);
 +            return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
      }
  
      void setint64(int64 n)
          while (isxdigit(*psz))
          {
              *this <<= 4;
-             int n = phexdigit[*psz++];
+             int n = phexdigit[(unsigned char)*psz++];
              *this += n;
          }
          if (fNegative)
          return ToString(16);
      }
  
 -    unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
 +    unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          return ::GetSerializeSize(getvch(), nType, nVersion);
      }
  
      template<typename Stream>
 -    void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
 +    void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          ::Serialize(s, getvch(), nType, nVersion);
      }
  
      template<typename Stream>
 -    void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
 +    void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
      {
          std::vector<unsigned char> vch;
          ::Unserialize(s, vch, nType, nVersion);
diff --combined src/bitcoinrpc.cpp
@@@ -9,11 -9,9 +9,11 @@@
  #include "init.h"
  #undef printf
  #include <boost/asio.hpp>
 +#include <boost/filesystem.hpp>
  #include <boost/iostreams/concepts.hpp>
  #include <boost/iostreams/stream.hpp>
  #include <boost/algorithm/string.hpp>
 +#include <boost/lexical_cast.hpp>
  #ifdef USE_SSL
  #include <boost/asio/ssl.hpp> 
  #include <boost/filesystem.hpp>
@@@ -43,8 -41,6 +43,8 @@@ static std::string strRPCUserColonPass
  static int64 nWalletUnlockTime;
  static CCriticalSection cs_nWalletUnlockTime;
  
 +extern Value dumpprivkey(const Array& params, bool fHelp);
 +extern Value importprivkey(const Array& params, bool fHelp);
  
  Object JSONRPCError(int code, const string& message)
  {
      return error;
  }
  
 -
 -void PrintConsole(const std::string &format, ...)
 +double GetDifficulty(const CBlockIndex* blockindex = NULL)
  {
 -    char buffer[50000];
 -    int limit = sizeof(buffer);
 -    va_list arg_ptr;
 -    va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
 -    va_end(arg_ptr);
 -    if (ret < 0 || ret >= limit)
 +    // Floating point number that is a multiple of the minimum difficulty,
 +    // minimum difficulty = 1.0.
 +    if (blockindex == NULL)
 +    {
 +        if (pindexBest == NULL)
 +            return 1.0;
 +        else
 +            blockindex = pindexBest;
 +    }
 +
 +    int nShift = (blockindex->nBits >> 24) & 0xff;
 +
 +    double dDiff =
 +        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
 +
 +    while (nShift < 29)
      {
 -        ret = limit - 1;
 -        buffer[limit-1] = 0;
 +        dDiff *= 256.0;
 +        nShift++;
      }
 -    printf("%s", buffer);
 -    fprintf(stdout, "%s", buffer);
 +    while (nShift > 29)
 +    {
 +        dDiff /= 256.0;
 +        nShift--;
 +    }
 +
 +    return dDiff;
  }
  
  
@@@ -102,26 -85,9 +102,26 @@@ Value ValueFromAmount(int64 amount
      return (double)amount / (double)COIN;
  }
  
 +std::string
 +HexBits(unsigned int nBits)
 +{
 +    union {
 +        int32_t nBits;
 +        char cBits[4];
 +    } uBits;
 +    uBits.nBits = htonl((int32_t)nBits);
 +    return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
 +}
 +
  void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
  {
 -    entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
 +    int confirms = wtx.GetDepthInMainChain();
 +    entry.push_back(Pair("confirmations", confirms));
 +    if (confirms)
 +    {
 +        entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
 +        entry.push_back(Pair("blockindex", wtx.nIndex));
 +    }
      entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
      entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
      BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
@@@ -136,30 -102,6 +136,30 @@@ string AccountFromValue(const Value& va
      return strAccount;
  }
  
 +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
 +{
 +    Object result;
 +    result.push_back(Pair("hash", block.GetHash().GetHex()));
 +    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK)));
 +    result.push_back(Pair("height", blockindex->nHeight));
 +    result.push_back(Pair("version", block.nVersion));
 +    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
 +    result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
 +    result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
 +    result.push_back(Pair("bits", HexBits(block.nBits)));
 +    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
 +    Array txhashes;
 +    BOOST_FOREACH (const CTransaction&tx, block.vtx)
 +        txhashes.push_back(tx.GetHash().GetHex());
 +    result.push_back(Pair("tx", txhashes));
 +
 +    if (blockindex->pprev)
 +        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
 +    if (blockindex->pnext)
 +        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
 +    return result;
 +}
 +
  
  
  ///
@@@ -265,6 -207,32 +265,6 @@@ Value getconnectioncount(const Array& p
  }
  
  
 -double GetDifficulty()
 -{
 -    // Floating point number that is a multiple of the minimum difficulty,
 -    // minimum difficulty = 1.0.
 -
 -    if (pindexBest == NULL)
 -        return 1.0;
 -    int nShift = (pindexBest->nBits >> 24) & 0xff;
 -
 -    double dDiff =
 -        (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
 -
 -    while (nShift < 29)
 -    {
 -        dDiff *= 256.0;
 -        nShift++;
 -    }
 -    while (nShift > 29)
 -    {
 -        dDiff /= 256.0;
 -        nShift--;
 -    }
 -
 -    return dDiff;
 -}
 -
  Value getdifficulty(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
@@@ -283,7 -251,7 +283,7 @@@ Value getgenerate(const Array& params, 
              "getgenerate\n"
              "Returns true or false.");
  
 -    return (bool)fGenerateBitcoins;
 +    return GetBoolArg("-gen");
  }
  
  
@@@ -302,11 -270,13 +302,11 @@@ Value setgenerate(const Array& params, 
      if (params.size() > 1)
      {
          int nGenProcLimit = params[1].get_int();
 -        fLimitProcessors = (nGenProcLimit != -1);
 -        WriteSetting("fLimitProcessors", fLimitProcessors);
 -        if (nGenProcLimit != -1)
 -            WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
 +        mapArgs["-genproclimit"] = itostr(nGenProcLimit);
          if (nGenProcLimit == 0)
              fGenerate = false;
      }
 +    mapArgs["-gen"] = (fGenerate ? "1" : "0");
  
      GenerateBitcoins(fGenerate, pwalletMain);
      return Value::null;
@@@ -334,14 -304,15 +334,14 @@@ Value getinfo(const Array& params, boo
              "Returns an object containing various state info.");
  
      Object obj;
 -    obj.push_back(Pair("version",       (int)VERSION));
 +    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
 +    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
 +    obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
      obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
      obj.push_back(Pair("blocks",        (int)nBestHeight));
      obj.push_back(Pair("connections",   (int)vNodes.size()));
      obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
 -    obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
 -    obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
      obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
 -    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
      obj.push_back(Pair("testnet",       fTestNet));
      obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
      obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
  }
  
  
 +Value getmininginfo(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 0)
 +        throw runtime_error(
 +            "getmininginfo\n"
 +            "Returns an object containing mining-related information.");
 +
 +    Object obj;
 +    obj.push_back(Pair("blocks",        (int)nBestHeight));
 +    obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
 +    obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
 +    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
 +    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
 +    obj.push_back(Pair("generate",      GetBoolArg("-gen")));
 +    obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
 +    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
 +    obj.push_back(Pair("pooledtx",      (uint64_t)nPooledTx));
 +    obj.push_back(Pair("testnet",       fTestNet));
 +    return obj;
 +}
 +
 +
  Value getnewaddress(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() > 1)
@@@ -583,6 -532,8 +583,6 @@@ Value sendtoaddress(const Array& params
      return wtx.GetHash().GetHex();
  }
  
 -static const string strMessageMagic = "Bitcoin Signed Message:\n";
 -
  Value signmessage(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 2)
@@@ -644,7 -595,7 +644,7 @@@ Value verifymessage(const Array& params
      if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
          return false;
  
 -    return (key.GetAddress() == addr);
 +    return (CBitcoinAddress(key.GetPubKey()) == addr);
  }
  
  
@@@ -711,7 -662,7 +711,7 @@@ Value getreceivedbyaccount(const Array
      if (params.size() > 1)
          nMinDepth = params[1].get_int();
  
 -    // Get the set of pub keys that have the label
 +    // Get the set of pub keys assigned to account
      string strAccount = AccountFromValue(params[0]);
      set<CBitcoinAddress> setAddress;
      GetAccountAddresses(strAccount, setAddress);
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
 -            if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
 +            if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
                  if (wtx.GetDepthInMainChain() >= nMinDepth)
                      nAmount += txout.nValue;
          }
@@@ -982,79 -933,6 +982,79 @@@ Value sendmany(const Array& params, boo
      return wtx.GetHash().GetHex();
  }
  
 +Value addmultisigaddress(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() < 2 || params.size() > 3)
 +    {
 +        string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
 +            "Add a nrequired-to-sign multisignature address to the wallet\"\n"
 +            "each key is a bitcoin address or hex-encoded public key\n"
 +            "If [account] is specified, assign address to [account].";
 +        throw runtime_error(msg);
 +    }
 +    if (!fTestNet)
 +        throw runtime_error("addmultisigaddress available only when running -testnet\n");
 +
 +    int nRequired = params[0].get_int();
 +    const Array& keys = params[1].get_array();
 +    string strAccount;
 +    if (params.size() > 2)
 +        strAccount = AccountFromValue(params[2]);
 +
 +    // Gather public keys
 +    if (nRequired < 1 || keys.size() < nRequired)
 +        throw runtime_error(
 +            strprintf("wrong number of keys"
 +                      "(got %d, need at least %d)", keys.size(), nRequired));
 +    std::vector<CKey> pubkeys;
 +    pubkeys.resize(keys.size());
 +    for (int i = 0; i < keys.size(); i++)
 +    {
 +        const std::string& ks = keys[i].get_str();
 +
 +        // Case 1: bitcoin address and we have full public key:
 +        CBitcoinAddress address(ks);
 +        if (address.IsValid())
 +        {
 +            if (address.IsScript())
 +                throw runtime_error(
 +                    strprintf("%s is a pay-to-script address",ks.c_str()));
 +            std::vector<unsigned char> vchPubKey;
 +            if (!pwalletMain->GetPubKey(address, vchPubKey))
 +                throw runtime_error(
 +                    strprintf("no full public key for address %s",ks.c_str()));
 +            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
 +                throw runtime_error(" Invalid public key: "+ks);
 +        }
 +
 +        // Case 2: hex public key
 +        else if (IsHex(ks))
 +        {
 +            vector<unsigned char> vchPubKey = ParseHex(ks);
 +            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
 +                throw runtime_error(" Invalid public key: "+ks);
 +        }
 +        else
 +        {
 +            throw runtime_error(" Invalid public key: "+ks);
 +        }
 +    }
 +
 +    // Construct using pay-to-script-hash:
 +    CScript inner;
 +    inner.SetMultisig(nRequired, pubkeys);
 +
 +    uint160 scriptHash = Hash160(inner);
 +    CScript scriptPubKey;
 +    scriptPubKey.SetPayToScriptHash(inner);
 +    pwalletMain->AddCScript(inner);
 +    CBitcoinAddress address;
 +    address.SetScriptHash160(scriptHash);
 +
 +    pwalletMain->SetAddressBookName(address, strAccount);
 +    return address.ToString();
 +}
 +
  
  struct tallyitem
  {
      tallyitem()
      {
          nAmount = 0;
 -        nConf = INT_MAX;
 +        nConf = std::numeric_limits<int>::max();
      }
  };
  
@@@ -1084,7 -962,6 +1084,7 @@@ Value ListReceived(const Array& params
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          const CWalletTx& wtx = (*it).second;
 +
          if (wtx.IsCoinBase() || !wtx.IsFinal())
              continue;
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
 -            if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
 +            if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
                  continue;
  
              tallyitem& item = mapTally[address];
              continue;
  
          int64 nAmount = 0;
 -        int nConf = INT_MAX;
 +        int nConf = std::numeric_limits<int>::max();
          if (it != mapTally.end())
          {
              nAmount = (*it).second.nAmount;
              obj.push_back(Pair("address",       address.ToString()));
              obj.push_back(Pair("account",       strAccount));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
 -            obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
 +            obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
              Object obj;
              obj.push_back(Pair("account",       (*it).first));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
 -            obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
 +            obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
@@@ -1194,7 -1071,6 +1194,7 @@@ void ListTransactions(const CWalletTx& 
      string strSentAccount;
      list<pair<CBitcoinAddress, int64> > listReceived;
      list<pair<CBitcoinAddress, int64> > listSent;
 +
      wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
  
      bool fAllAccounts = (strAccount == string("*"));
@@@ -1293,14 -1169,21 +1293,21 @@@ Value listtransactions(const Array& par
      if (params.size() > 2)
          nFrom = params[2].get_int();
  
+     if (nCount < 0)
+         throw JSONRPCError(-8, "Negative count");
+     if (nFrom < 0)
+         throw JSONRPCError(-8, "Negative from");
      Array ret;
      CWalletDB walletdb(pwalletMain->strWalletFile);
  
-     // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
+     // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
      typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
      typedef multimap<int64, TxPair > TxItems;
      TxItems txByTime;
  
+     // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
+     // would make this much faster for applications that do this a lot.
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          CWalletTx* wtx = &((*it).second);
          txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
      }
  
-     // Now: iterate backwards until we have nCount items to return:
-     TxItems::reverse_iterator it = txByTime.rbegin();
-     if (txByTime.size() > nFrom) std::advance(it, nFrom);
-     for (; it != txByTime.rend(); ++it)
+     // iterate backwards until we have nCount items to return:
+     for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
      {
          CWalletTx *const pwtx = (*it).second.first;
          if (pwtx != 0)
          if (pacentry != 0)
              AcentryToJSON(*pacentry, strAccount, ret);
  
-         if (ret.size() >= nCount) break;
+         if (ret.size() >= (nCount+nFrom)) break;
      }
-     // ret is now newest to oldest
+     // ret is newest to oldest
      
-     // Make sure we return only last nCount items (sends-to-self might give us an extra):
-     if (ret.size() > nCount)
-     {
-         Array::iterator last = ret.begin();
-         std::advance(last, nCount);
-         ret.erase(last, ret.end());
-     }
-     std::reverse(ret.begin(), ret.end()); // oldest to newest
+     if (nFrom > ret.size()) nFrom = ret.size();
+     if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
+     Array::iterator first = ret.begin();
+     std::advance(first, nFrom);
+     Array::iterator last = ret.begin();
+     std::advance(last, nFrom+nCount);
+     if (last != ret.end()) ret.erase(last, ret.end());
+     if (first != ret.begin()) ret.erase(ret.begin(), first);
+     std::reverse(ret.begin(), ret.end()); // Return oldest to newest
  
      return ret;
  }
@@@ -1725,42 -1609,14 +1733,42 @@@ Value validateaddress(const Array& para
          // version of the address:
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
 -        ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
 +        if (pwalletMain->HaveKey(address))
 +        {
 +            ret.push_back(Pair("ismine", true));
 +            std::vector<unsigned char> vchPubKey;
 +            pwalletMain->GetPubKey(address, vchPubKey);
 +            ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
 +            CKey key;
 +            key.SetPubKey(vchPubKey);
 +            ret.push_back(Pair("iscompressed", key.IsCompressed()));
 +        }
 +        else if (pwalletMain->HaveCScript(address.GetHash160()))
 +        {
 +            ret.push_back(Pair("isscript", true));
 +            CScript subscript;
 +            pwalletMain->GetCScript(address.GetHash160(), subscript);
 +            ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
 +            std::vector<CBitcoinAddress> addresses;
 +            txnouttype whichType;
 +            int nRequired;
 +            ExtractAddresses(subscript, whichType, addresses, nRequired);
 +            ret.push_back(Pair("script", GetTxnOutputType(whichType)));
 +            Array a;
 +            BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
 +                a.push_back(addr.ToString());
 +            ret.push_back(Pair("addresses", a));
 +            if (whichType == TX_MULTISIG)
 +                ret.push_back(Pair("sigsrequired", nRequired));
 +        }
 +        else
 +            ret.push_back(Pair("ismine", false));
          if (pwalletMain->mapAddressBook.count(address))
              ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
      }
      return ret;
  }
  
 -
  Value getwork(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() > 1)
@@@ -1876,10 -1732,7 +1884,10 @@@ Value getmemorypool(const Array& params
              "  \"previousblockhash\" : hash of current highest block\n"
              "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
              "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
 +            "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
              "  \"time\" : timestamp appropriate for next block\n"
 +            "  \"mintime\" : minimum timestamp appropriate for next block\n"
 +            "  \"curtime\" : current timestamp\n"
              "  \"bits\" : compressed target of next block\n"
              "If [data] is specified, tries to solve the block and returns true if it was successful.");
  
          result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
          result.push_back(Pair("transactions", transactions));
          result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
 +        result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
          result.push_back(Pair("time", (int64_t)pblock->nTime));
 -
 -        union {
 -            int32_t nBits;
 -            char cBits[4];
 -        } uBits;
 -        uBits.nBits = htonl((int32_t)pblock->nBits);
 -        result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
 +        result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
 +        result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
 +        result.push_back(Pair("bits", HexBits(pblock->nBits)));
  
          return result;
      }
      }
  }
  
 +Value getblockhash(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 1)
 +        throw runtime_error(
 +            "getblockhash <index>\n"
 +            "Returns hash of block in best-block-chain at <index>.");
 +
 +    int nHeight = params[0].get_int();
 +    if (nHeight < 0 || nHeight > nBestHeight)
 +        throw runtime_error("Block number out of range.");
 +
 +    CBlock block;
 +    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
 +    while (pblockindex->nHeight > nHeight)
 +        pblockindex = pblockindex->pprev;
 +    return pblockindex->phashBlock->GetHex();
 +}
 +
 +Value getblock(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 1)
 +        throw runtime_error(
 +            "getblock <hash>\n"
 +            "Returns details of a block with given block-hash.");
 +
 +    std::string strHash = params[0].get_str();
 +    uint256 hash(strHash);
 +
 +    if (mapBlockIndex.count(hash) == 0)
 +        throw JSONRPCError(-5, "Block not found");
 +
 +    CBlock block;
 +    CBlockIndex* pblockindex = mapBlockIndex[hash];
 +    block.ReadFromDisk(pblockindex, true);
 +
 +    return blockToJSON(block, pblockindex);
 +}
 +
  
  
  
@@@ -2016,7 -1834,6 +2024,7 @@@ pair<string, rpcfn_type> pCallTable[] 
      make_pair("setgenerate",            &setgenerate),
      make_pair("gethashespersec",        &gethashespersec),
      make_pair("getinfo",                &getinfo),
 +    make_pair("getmininginfo",          &getmininginfo),
      make_pair("getnewaddress",          &getnewaddress),
      make_pair("getaccountaddress",      &getaccountaddress),
      make_pair("setaccount",             &setaccount),
      make_pair("move",                   &movecmd),
      make_pair("sendfrom",               &sendfrom),
      make_pair("sendmany",               &sendmany),
 +    make_pair("addmultisigaddress",     &addmultisigaddress),
 +    make_pair("getblock",               &getblock),
 +    make_pair("getblockhash",           &getblockhash),
      make_pair("gettransaction",         &gettransaction),
      make_pair("listtransactions",       &listtransactions),
 -    make_pair("signmessage",           &signmessage),
 -    make_pair("verifymessage",         &verifymessage),
 +    make_pair("signmessage",            &signmessage),
 +    make_pair("verifymessage",          &verifymessage),
      make_pair("getwork",                &getwork),
      make_pair("listaccounts",           &listaccounts),
      make_pair("settxfee",               &settxfee),
      make_pair("getmemorypool",          &getmemorypool),
 -    make_pair("listsinceblock",        &listsinceblock),
 +    make_pair("listsinceblock",         &listsinceblock),
 +    make_pair("dumpprivkey",            &dumpprivkey),
 +    make_pair("importprivkey",          &importprivkey)
  };
  map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
  
@@@ -2067,7 -1879,6 +2075,7 @@@ string pAllowInSafeMode[] 
      "setgenerate",
      "gethashespersec",
      "getinfo",
 +    "getmininginfo",
      "getnewaddress",
      "getaccountaddress",
      "getaccount",
@@@ -2347,26 -2158,30 +2355,30 @@@ void ThreadRPCServer(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
      try
      {
 -        vnThreadsRunning[4]++;
 +        vnThreadsRunning[THREAD_RPCSERVER]++;
          ThreadRPCServer2(parg);
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(&e, "ThreadRPCServer()");
      } catch (...) {
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(NULL, "ThreadRPCServer()");
      }
      printf("ThreadRPCServer exiting\n");
  }
  
+ #ifdef QT_GUI
+ extern bool HACK_SHUTDOWN;
+ #endif
  void ThreadRPCServer2(void* parg)
  {
      printf("ThreadRPCServer started\n");
  
      strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
 -    if (strRPCUserColonPass == ":")
 +    if (mapArgs["-rpcpassword"] == "")
      {
          unsigned char rand_pwd[32];
          RAND_bytes(rand_pwd, 32);
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
          ThreadSafeMessageBox(strprintf(
 -            _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
 +            _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
                "It is recommended you use the following random password:\n"
                "rpcuser=bitcoinrpc\n"
                "rpcpassword=%s\n"
  
      asio::io_service io_service;
      ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
+ #ifndef QT_GUI
      ip::tcp::acceptor acceptor(io_service, endpoint);
  
      acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ #else
+     ip::tcp::acceptor acceptor(io_service);
+     try
+     {
+         acceptor.open(endpoint.protocol());
+         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+         acceptor.bind(endpoint);
+         acceptor.listen(socket_base::max_connections);
+     }
+     catch(system::system_error &e)
+     {
+         HACK_SHUTDOWN = true;
+         ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
+                              _("Error"), wxOK | wxMODAL);
+         return;
+     }
+ #endif
  
  #ifdef USE_SSL
      ssl::context context(io_service, ssl::context::sslv23);
  #endif
  
          ip::tcp::endpoint peer;
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
  #ifdef USE_SSL
          acceptor.accept(sslStream.lowest_layer(), peer);
  #else
@@@ -2677,7 -2510,6 +2707,7 @@@ int CommandLineRPC(int argc, char *argv
          if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
          if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
 +        if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
          if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
          if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
              params[1] = v.get_obj();
          }
          if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
 +        if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
 +        if (strMethod == "addmultisigaddress"      && n > 1)
 +        {
 +            string s = params[1].get_str();
 +            Value v;
 +            if (!read_string(s, v) || v.type() != array_type)
 +                throw runtime_error("type mismatch "+s);
 +            params[1] = v.get_array();
 +        }
  
          // Execute
          Object reply = CallRPC(strMethod, params);
diff --combined src/keystore.h
@@@ -1,53 -1,46 +1,55 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
 -// Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_KEYSTORE_H
  #define BITCOIN_KEYSTORE_H
  
  #include "crypter.h"
 +#include "script.h"
  
 -// A virtual base class for key stores
 +/** A virtual base class for key stores */
  class CKeyStore
  {
  protected:
      mutable CCriticalSection cs_KeyStore;
  
  public:
+     virtual ~CKeyStore() {}
      // Add a key to the store.
      virtual bool AddKey(const CKey& key) =0;
  
      // Check whether a key corresponding to a given address is present in the store.
      virtual bool HaveKey(const CBitcoinAddress &address) const =0;
 -
 -    // Retrieve a key corresponding to a given address from the store.
 -    // Return true if succesful.
      virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0;
 -
 -    // Retrieve only the public key corresponding to a given address.
 -    // This may succeed even if GetKey fails (e.g., encrypted wallets)
 +    virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
      virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
  
 -    // Generate a new key, and add it to the store
 -    virtual std::vector<unsigned char> GenerateNewKey();
 +    // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
 +    virtual bool AddCScript(const CScript& redeemScript) =0;
 +    virtual bool HaveCScript(const uint160 &hash) const =0;
 +    virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0;
 +
 +    virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const
 +    {
 +        CKey key;
 +        if (!GetKey(address, key))
 +            return false;
 +        vchSecret = key.GetSecret(fCompressed);
 +        return true;
 +    }
  };
  
 -typedef std::map<CBitcoinAddress, CSecret> KeyMap;
 +typedef std::map<CBitcoinAddress, std::pair<CSecret, bool> > KeyMap;
 +typedef std::map<uint160, CScript > ScriptMap;
  
 -// Basic key store, that keeps keys in an address->secret map
 +/** Basic key store, that keeps keys in an address->secret map */
  class CBasicKeyStore : public CKeyStore
  {
  protected:
      KeyMap mapKeys;
 +    ScriptMap mapScripts;
  
  public:
      bool AddKey(const CKey& key);
              result = (mapKeys.count(address) > 0);
          return result;
      }
 -    bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const
 +    void GetKeys(std::set<CBitcoinAddress> &setAddress) const
 +    {
 +        setAddress.clear();
 +        CRITICAL_BLOCK(cs_KeyStore)
 +        {
 +            KeyMap::const_iterator mi = mapKeys.begin();
 +            while (mi != mapKeys.end())
 +            {
 +                setAddress.insert((*mi).first);
 +                mi++;
 +            }
 +        }
 +    }
 +    bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const
      {
          CRITICAL_BLOCK(cs_KeyStore)
          {
              KeyMap::const_iterator mi = mapKeys.find(address);
              if (mi != mapKeys.end())
              {
 -                keyOut.SetSecret((*mi).second);
 +                keyOut.Reset();
 +                keyOut.SetSecret((*mi).second.first, (*mi).second.second);
                  return true;
              }
          }
          return false;
      }
 +    virtual bool AddCScript(const CScript& redeemScript);
 +    virtual bool HaveCScript(const uint160 &hash) const;
 +    virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const;
  };
  
  typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap;
  
 -// Keystore which keeps the private keys encrypted
 -// It derives from the basic key store, which is used if no encryption is active.
 +/** Keystore which keeps the private keys encrypted.
 + * It derives from the basic key store, which is used if no encryption is active.
 + */
  class CCryptoKeyStore : public CBasicKeyStore
  {
  private:
@@@ -146,6 -121,7 +148,6 @@@ public
      }
  
      virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
 -    std::vector<unsigned char> GenerateNewKey();
      bool AddKey(const CKey& key);
      bool HaveKey(const CBitcoinAddress &address) const
      {
      }
      bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const;
      bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
 +    void GetKeys(std::set<CBitcoinAddress> &setAddress) const
 +    {
 +        if (!IsCrypted())
 +        {
 +            CBasicKeyStore::GetKeys(setAddress);
 +            return;
 +        }
 +        setAddress.clear();
 +        CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
 +        while (mi != mapCryptedKeys.end())
 +        {
 +            setAddress.insert((*mi).first);
 +            mi++;
 +        }
 +    }
  };
  
  #endif
diff --combined src/qt/bitcoin.cpp
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * W.J. van der Laan 2011
 + * W.J. van der Laan 2011-2012
   */
  #include "bitcoingui.h"
  #include "clientmodel.h"
@@@ -8,7 -8,7 +8,8 @@@
  
  #include "headers.h"
  #include "init.h"
 +#include "qtipcserver.h"
+ #include "util.h"
  
  #include <QApplication>
  #include <QMessageBox>
  #include <QSplashScreen>
  #include <QLibraryInfo>
  
 +#include <boost/interprocess/ipc/message_queue.hpp>
 +
  // Need a global reference for the notifications to find the GUI
  BitcoinGUI *guiref;
  QSplashScreen *splashref;
  
  int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
  {
 -    // Message from main thread
 -    if(guiref)
 -    {
 -        guiref->error(QString::fromStdString(caption),
 -                      QString::fromStdString(message));
 -    }
 -    else
 -    {
 -        QMessageBox::critical(0, QString::fromStdString(caption),
 -            QString::fromStdString(message),
 -            QMessageBox::Ok, QMessageBox::Ok);
 -    }
 +    // Message from AppInit2(), always in main thread before main window is constructed
 +    QMessageBox::critical(0, QString::fromStdString(caption),
 +        QString::fromStdString(message),
 +        QMessageBox::Ok, QMessageBox::Ok);
      return 4;
  }
  
@@@ -40,7 -46,7 +41,7 @@@ int ThreadSafeMessageBox(const std::str
  
      if (modal)
          while (!guiref)
-             sleep(1);
+             Sleep(1000);
  
      // Message from network thread
      if(guiref)
@@@ -81,22 -87,6 +82,22 @@@ bool ThreadSafeAskFee(int64 nFeeRequire
      return payFee;
  }
  
 +void ThreadSafeHandleURI(const std::string& strURI)
 +{
 +    if(!guiref)
 +        return;
 +
 +    // Call slot on GUI thread.
 +    // If called from another thread, use a blocking QueuedConnection.
 +    Qt::ConnectionType connectionType = Qt::DirectConnection;
 +    if(QThread::currentThread() != QCoreApplication::instance()->thread())
 +    {
 +        connectionType = Qt::BlockingQueuedConnection;
 +    }
 +    QMetaObject::invokeMethod(guiref, "handleURI", connectionType,
 +                               Q_ARG(QString, QString::fromStdString(strURI)));
 +}
 +
  void CalledSetStatusBar(const std::string& strText, int nField)
  {
      // Only used for built-in mining, which is disabled, simple ignore
@@@ -130,68 -120,28 +131,77 @@@ std::string _(const char* psz
      return QCoreApplication::translate("bitcoin-core", psz).toStdString();
  }
  
+ /* Handle runaway exceptions. Shows a message box with the problem and quits the program.
+  */
+ static void handleRunawayException(std::exception *e)
+ {
+     PrintExceptionContinue(e, "Runaway exception");
+     QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occured. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning));
+     exit(1);
+ }
 +#ifndef BITCOIN_QT_TEST
  int main(int argc, char *argv[])
  {
 +#if !defined(MAC_OSX) && !defined(WIN32)
 +// TODO: implement qtipcserver.cpp for Mac and Windows
 +
 +    // Do this early as we don't want to bother initializing if we are just calling IPC
 +    for (int i = 1; i < argc; i++)
 +    {
 +        if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
 +        {
 +            const char *strURI = argv[i];
 +            try {
 +                boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
 +                if(mq.try_send(strURI, strlen(strURI), 0))
 +                    exit(0);
 +                else
 +                    break;
 +            }
 +            catch (boost::interprocess::interprocess_exception &ex) {
 +                break;
 +            }
 +        }
 +    }
 +#endif
 +
 +    // Internal string conversion is all UTF-8
      QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
      QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
  
      Q_INIT_RESOURCE(bitcoin);
      QApplication app(argc, argv);
  
 -    // Load language files for system locale:
 +    // Command-line options take precedence:
 +    ParseParameters(argc, argv);
 +
 +    // ... then bitcoin.conf:
 +    if (!ReadConfigFile(mapArgs, mapMultiArgs))
 +    {
 +        fprintf(stderr, "Error: Specified directory does not exist\n");
 +        return 1;
 +    }
 +
 +    // Application identification (must be set before OptionsModel is initialized,
 +    // as it is used to locate QSettings)
 +    app.setOrganizationName("Bitcoin");
 +    app.setOrganizationDomain("bitcoin.org");
 +    if(GetBoolArg("-testnet")) // Separate UI settings for testnet
 +        app.setApplicationName("Bitcoin-Qt-testnet");
 +    else
 +        app.setApplicationName("Bitcoin-Qt");
 +
 +    // ... then GUI settings:
 +    OptionsModel optionsModel;
 +
 +    // Get desired locale ("en_US") from command line or system locale
 +    QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
 +    // Load language files for configured locale:
      // - First load the translator for the base language, without territory
      // - Then load the more specific locale translator
 -    QString lang_territory = QLocale::system().name(); // "en_US"
      QString lang = lang_territory;
 +
      lang.truncate(lang_territory.lastIndexOf('_')); // "en"
      QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
  
      if (!translator.isEmpty())
          app.installTranslator(&translator);
  
 -    app.setApplicationName(QApplication::translate("main", "Bitcoin-Qt"));
 -
      QSplashScreen splash(QPixmap(":/images/splash"), 0);
 -    if (!GetBoolArg("-min"))
 +    if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
      {
          splash.show();
          splash.setAutoFillBackground(true);
              {
                  // Put this in a block, so that BitcoinGUI is cleaned up properly before
                  // calling Shutdown() in case of exceptions.
 +
 +                optionsModel.Upgrade(); // Must be done after AppInit2
 +
                  BitcoinGUI window;
                  if (splashref)
                      splash.finish(&window);
 -                OptionsModel optionsModel(pwalletMain);
 +
                  ClientModel clientModel(&optionsModel);
                  WalletModel walletModel(pwalletMain, &optionsModel);
  
                      window.show();
                  }
  
 +                // Place this here as guiref has to be defined if we dont want to lose URIs
 +                ipcInit();
 +
 +#if !defined(MAC_OSX) && !defined(WIN32)
 +// TODO: implement qtipcserver.cpp for Mac and Windows
 +
 +                // Check for URI in argv
 +                for (int i = 1; i < argc; i++)
 +                {
 +                    if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
 +                    {
 +                        const char *strURI = argv[i];
 +                        try {
 +                            boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
 +                            mq.try_send(strURI, strlen(strURI), 0);
 +                        }
 +                        catch (boost::interprocess::interprocess_exception &ex) {
 +                        }
 +                    }
 +                }
 +#endif
                  app.exec();
  
                  guiref = 0;
              return 1;
          }
      } catch (std::exception& e) {
-         PrintException(&e, "Runaway exception");
+         handleRunawayException(&e);
      } catch (...) {
-         PrintException(NULL, "Runaway exception");
+         handleRunawayException(NULL);
      }
      return 0;
  }
 +#endif // BITCOIN_QT_TEST
diff --combined src/qt/bitcoingui.cpp
@@@ -1,14 -1,16 +1,17 @@@
  /*
   * Qt4 bitcoin GUI.
   *
 - * W.J. van der Laan 2011
 - * The Bitcoin Developers 2011
 + * W.J. van der Laan 20011-2012
 + * The Bitcoin Developers 20011-2012
   */
+ #include "checkpoints.h"
  #include "bitcoingui.h"
  #include "transactiontablemodel.h"
  #include "addressbookpage.h"
  #include "sendcoinsdialog.h"
 +#include "messagepage.h"
  #include "optionsdialog.h"
  #include "aboutdialog.h"
  #include "clientmodel.h"
@@@ -46,8 -48,6 +49,8 @@@
  #include <QStackedWidget>
  #include <QDateTime>
  #include <QMovie>
 +#include <QFileDialog>
 +#include <QDesktopServices>
  #include <QTimer>
  
  #include <QDragEnterEvent>
@@@ -103,17 -103,12 +106,17 @@@ BitcoinGUI::BitcoinGUI(QWidget *parent)
  
      sendCoinsPage = new SendCoinsDialog(this);
  
 +    messagePage = new MessagePage(this);
 +
      centralWidget = new QStackedWidget(this);
      centralWidget->addWidget(overviewPage);
      centralWidget->addWidget(transactionsPage);
      centralWidget->addWidget(addressBookPage);
      centralWidget->addWidget(receiveCoinsPage);
      centralWidget->addWidget(sendCoinsPage);
 +#ifdef FIRST_CLASS_MESSAGING
 +    centralWidget->addWidget(messagePage);
 +#endif
      setCentralWidget(centralWidget);
  
      // Create status bar
  
      // Status bar notification icons
      QFrame *frameBlocks = new QFrame();
 -    //frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
      frameBlocks->setContentsMargins(0,0,0,0);
      frameBlocks->setMinimumWidth(56);
      frameBlocks->setMaximumWidth(56);
  
  BitcoinGUI::~BitcoinGUI()
  {
 +    if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
 +        trayIcon->hide();
  #ifdef Q_WS_MAC
      delete appMenuBar;
  #endif
@@@ -203,25 -197,16 +206,25 @@@ void BitcoinGUI::createActions(
      sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
      tabGroup->addAction(sendCoinsAction);
  
 -    connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    messageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message"), this);
 +    messageAction->setToolTip(tr("Prove you control an address"));
 +#ifdef FIRST_CLASS_MESSAGING
 +    messageAction->setCheckable(true);
 +#endif
 +    tabGroup->addAction(messageAction);
 +
 +    connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
 -    connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
 -    connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
 -    connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
 -    connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
 +    connect(messageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
 +    connect(messageAction, SIGNAL(triggered()), this, SLOT(gotoMessagePage()));
  
      quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
      quitAction->setToolTip(tr("Quit application"));
      openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
      openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
      exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
 -    exportAction->setToolTip(tr("Export the current view to a file"));
 +    exportAction->setToolTip(tr("Export the data in the current tab to a file"));
      encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
      encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
      encryptWalletAction->setCheckable(true);
 +    backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet"), this);
 +    backupWalletAction->setToolTip(tr("Backup wallet to another location"));
      changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
      changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
  
      connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
      connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
      connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
 -    connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
 +    connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
      connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
  }
  
@@@ -270,12 -252,6 +273,12 @@@ void BitcoinGUI::createMenuBar(
  
      // Configure the menus
      QMenu *file = appMenuBar->addMenu(tr("&File"));
 +    file->addAction(backupWalletAction);
 +    file->addAction(exportAction);
 +#ifndef FIRST_CLASS_MESSAGING
 +    file->addAction(messageAction);
 +#endif
 +    file->addSeparator();
      file->addAction(quitAction);
  
      QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
@@@ -298,9 -274,6 +301,9 @@@ void BitcoinGUI::createToolBars(
      toolbar->addAction(receiveCoinsAction);
      toolbar->addAction(historyAction);
      toolbar->addAction(addressBookAction);
 +#ifdef FIRST_CLASS_MESSAGING
 +    toolbar->addAction(messageAction);
 +#endif
  
      QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
      toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
@@@ -355,7 -328,6 +358,7 @@@ void BitcoinGUI::setWalletModel(WalletM
          addressBookPage->setModel(walletModel->getAddressTableModel());
          receiveCoinsPage->setModel(walletModel->getAddressTableModel());
          sendCoinsPage->setModel(walletModel);
 +        messagePage->setModel(walletModel);
  
          setEncryptionStatus(walletModel->getEncryptionStatus());
          connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
@@@ -391,10 -363,6 +394,10 @@@ void BitcoinGUI::createTrayIcon(
      // Configuration of the tray icon (or dock icon) icon menu
      trayIconMenu->addAction(openBitcoinAction);
      trayIconMenu->addSeparator();
 +    trayIconMenu->addAction(messageAction);
 +#ifndef FIRST_CLASS_MESSAGING
 +    trayIconMenu->addSeparator();
 +#endif
      trayIconMenu->addAction(receiveCoinsAction);
      trayIconMenu->addAction(sendCoinsAction);
      trayIconMenu->addSeparator();
@@@ -515,7 -483,7 +518,7 @@@ void BitcoinGUI::setNumBlocks(int count
      }
  
      // Set icon state: spinning if catching up, tick otherwise
-     if(secs < 90*60)
+     if(secs < 90*60 && count >= Checkpoints::GetTotalBlocksEstimate())
      {
          tooltip = tr("Up to date") + QString(".\n") + tooltip;
          labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
@@@ -551,12 -519,16 +554,16 @@@ void BitcoinGUI::refreshStatusBar(
      setNumBlocks(clientModel->getNumBlocks());
  }
  
+ bool HACK_SHUTDOWN = false;
  void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
  {
      // Report errors from network/worker thread
      if (modal)
      {
          QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
+         if (HACK_SHUTDOWN)
+             QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
      } else {
          notificator->notify(Notificator::Critical, title, message);
      }
@@@ -692,26 -664,6 +699,26 @@@ void BitcoinGUI::gotoSendCoinsPage(
      disconnect(exportAction, SIGNAL(triggered()), 0, 0);
  }
  
 +void BitcoinGUI::gotoMessagePage()
 +{
 +#ifdef FIRST_CLASS_MESSAGING
 +    messageAction->setChecked(true);
 +    centralWidget->setCurrentWidget(messagePage);
 +
 +    exportAction->setEnabled(false);
 +    disconnect(exportAction, SIGNAL(triggered()), 0, 0);
 +#else
 +    messagePage->show();
 +    messagePage->setFocus();
 +#endif
 +}
 +
 +void BitcoinGUI::gotoMessagePage(QString addr)
 +{
 +    gotoMessagePage();
 +    messagePage->setAddress(addr);
 +}
 +
  void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
  {
      // Accept only URIs
@@@ -727,24 -679,13 +734,24 @@@ void BitcoinGUI::dropEvent(QDropEvent *
          QList<QUrl> uris = event->mimeData()->urls();
          foreach(const QUrl &uri, uris)
          {
 -            sendCoinsPage->handleURI(&uri);
 +            sendCoinsPage->handleURI(uri.toString());
          }
      }
  
      event->acceptProposedAction();
  }
  
 +void BitcoinGUI::handleURI(QString strURI)
 +{
 +    gotoSendCoinsPage();
 +    sendCoinsPage->handleURI(strURI);
 +
 +    if(!isActiveWindow())
 +        activateWindow();
 +
 +    showNormalIfMinimized();
 +}
 +
  void BitcoinGUI::setEncryptionStatus(int status)
  {
      switch(status)
@@@ -786,17 -727,6 +793,17 @@@ void BitcoinGUI::encryptWallet(bool sta
      setEncryptionStatus(walletModel->getEncryptionStatus());
  }
  
 +void BitcoinGUI::backupWallet()
 +{
 +    QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
 +    QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
 +    if(!filename.isEmpty()) {
 +        if(!walletModel->backupWallet(filename)) {
 +            QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
 +        }
 +    }
 +}
 +
  void BitcoinGUI::changePassphrase()
  {
      AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
@@@ -816,11 -746,3 +823,11 @@@ void BitcoinGUI::unlockWallet(
          dlg.exec();
      }
  }
 +
 +void BitcoinGUI::showNormalIfMinimized()
 +{
 +    if(!isVisible()) // Show, if hidden
 +        show();
 +    if(isMinimized()) // Unminimize, if minimized
 +        showNormal();
 +}
@@@ -30,8 -30,6 +30,8 @@@ SendCoinsDialog::SendCoinsDialog(QWidge
  
      connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
      connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
 +
 +    fNewRecipientAllowed = true;
  }
  
  void SendCoinsDialog::setModel(WalletModel *model)
@@@ -94,8 -92,6 +94,8 @@@ void SendCoinsDialog::on_sendButton_cli
          formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
      }
  
 +    fNewRecipientAllowed = false;
 +
      QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
                            tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
            QMessageBox::Yes|QMessageBox::Cancel,
  
      if(retval != QMessageBox::Yes)
      {
 +        fNewRecipientAllowed = true;
          return;
      }
  
      if(!ctx.isValid())
      {
          // Unlock wallet was cancelled
 +        fNewRecipientAllowed = true;
          return;
      }
  
              tr("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
              QMessageBox::Ok, QMessageBox::Ok);
          break;
+     case WalletModel::Aborted: // User aborted, nothing to do
+         break;
      case WalletModel::OK:
          accept();
          break;
      }
 +    fNewRecipientAllowed = true;
  }
  
  void SendCoinsDialog::clear()
@@@ -243,9 -238,6 +245,9 @@@ QWidget *SendCoinsDialog::setupTabChain
  
  void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
  {
 +    if (!fNewRecipientAllowed)
 +        return;
 +
      SendCoinsEntry *entry = 0;
      // Replace the first entry if it is still unused
      if(ui->entries->count() == 1)
  }
  
  
 -void SendCoinsDialog::handleURI(const QUrl *uri)
 -{
 -    SendCoinsRecipient rv;
 -    if(!GUIUtil::parseBitcoinURI(uri, &rv))
 -    {
 -        return;
 -    }
 -    pasteEntry(rv);
 -}
 -
  void SendCoinsDialog::handleURI(const QString &uri)
  {
      SendCoinsRecipient rv;
diff --combined src/qt/walletmodel.h
@@@ -34,8 -34,7 +34,7 @@@ public
          DuplicateAddress,
          TransactionCreationFailed, // Error returned when wallet is still locked
          TransactionCommitFailed,
-         Aborted,
-         MiscError
+         Aborted
      };
  
      enum EncryptionStatus
@@@ -77,8 -76,6 +76,8 @@@
      // Passphrase only needed when unlocking
      bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
      bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
 +    // Wallet backup
 +    bool backupWallet(const QString &filename);
  
      // RAI object for unlocking wallet, returned by requestUnlock()
      class UnlockContext
diff --combined src/uint256.h
@@@ -1,5 -1,5 +1,5 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
 -// Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_UINT256_H
  #include <string>
  #include <vector>
  
 -#if defined(_MSC_VER) || defined(__BORLANDC__)
 -typedef __int64  int64;
 -typedef unsigned __int64  uint64;
 -#else
  typedef long long  int64;
  typedef unsigned long long  uint64;
 -#endif
 -#if defined(_MSC_VER) && _MSC_VER < 1300
 -#define for  if (false) ; else for
 -#endif
  
  
  inline int Testuint256AdHoc(std::vector<std::string> vArg);
  
  
  
 -// We have to keep a separate base class without constructors
 -// so the compiler will let us use it in a union
 +/** Base class without constructors for uint256 and uint160.
 + * This makes the compiler let u use it in a union.
 + */
  template<unsigned int BITS>
  class base_uint
  {
@@@ -308,7 -315,7 +308,7 @@@ public
          // hex string to uint
          static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
          const char* pbegin = psz;
-         while (phexdigit[*psz] || *psz == '0')
+         while (phexdigit[(unsigned char)*psz] || *psz == '0')
              psz++;
          psz--;
          unsigned char* p1 = (unsigned char*)pn;
          return sizeof(pn);
      }
  
 +    uint64 Get64(int n=0) const
 +    {
 +        return pn[2*n] | (uint64)pn[2*n+1] << 32;
 +    }
  
 -    unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
 +    unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          return sizeof(pn);
      }
  
      template<typename Stream>
 -    void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
 +    void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          s.write((char*)pn, sizeof(pn));
      }
  
      template<typename Stream>
 -    void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
 +    void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
      {
          s.read((char*)pn, sizeof(pn));
      }
@@@ -394,7 -397,6 +394,7 @@@ typedef base_uint<256> base_uint256
  // uint160
  //
  
 +/** 160-bit unsigned integer */
  class uint160 : public base_uint160
  {
  public:
@@@ -509,7 -511,6 +509,7 @@@ inline const uint160 operator-(const ui
  // uint256
  //
  
 +/** 256-bit unsigned integer */
  class uint256 : public base_uint256
  {
  public:
@@@ -623,7 -624,7 +623,7 @@@ inline const uint256 operator-(const ui
  
  
  
 -
 +#ifdef TEST_UINT256
  
  inline int Testuint256AdHoc(std::vector<std::string> vArg)
  {
  }
  
  #endif
 +
 +#endif
diff --combined src/util.cpp
@@@ -4,7 -4,17 +4,18 @@@
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
  #include "strlcpy.h"
 +#include <boost/algorithm/string/join.hpp>
+ // Work around clang compilation problem in Boost 1.46:
+ // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
+ // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
+ //           http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
+ namespace boost {
+     namespace program_options {
+         std::string to_internal(const std::string&);
+     }
+ }
  #include <boost/program_options/detail/config_file.hpp>
  #include <boost/program_options/parsers.hpp>
  #include <boost/filesystem.hpp>
@@@ -31,7 -41,7 +42,7 @@@ string strMiscWarning
  bool fTestNet = false;
  bool fNoListen = false;
  bool fLogTimestamps = false;
 -
 +CMedianFilter<int64> vTimeOffsets(200,0);
  
  
  
@@@ -133,7 -143,7 +144,7 @@@ uint64 GetRand(uint64 nMax
  
      // The range of the random source must be a multiple of the modulus
      // to give every possible output value an equal possibility
 -    uint64 nRange = (UINT64_MAX / nMax) * nMax;
 +    uint64 nRange = (std::numeric_limits<uint64>::max() / nMax) * nMax;
      uint64 nRand = 0;
      do
          RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
@@@ -400,36 -410,26 +411,36 @@@ bool ParseMoney(const char* pszIn, int6
  }
  
  
 -vector<unsigned char> ParseHex(const char* psz)
 +static char phexdigit[256] =
 +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
 +  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 +
 +bool IsHex(const string& str)
  {
 -    static char phexdigit[256] =
 -    { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
 -      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 +    BOOST_FOREACH(unsigned char c, str)
 +    {
 +        if (phexdigit[c] < 0)
 +            return false;
 +    }
 +    return (str.size() > 0) && (str.size()%2 == 0);
 +}
  
 +vector<unsigned char> ParseHex(const char* psz)
 +{
      // convert hex dump to vector
      vector<unsigned char> vch;
      loop
@@@ -454,22 -454,7 +465,22 @@@ vector<unsigned char> ParseHex(const st
      return ParseHex(str.c_str());
  }
  
 -void ParseParameters(int argc, char* argv[])
 +static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
 +{
 +    // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
 +    if (name.find("-no") == 0)
 +    {
 +        std::string positive("-");
 +        positive.append(name.begin()+3, name.end());
 +        if (mapSettingsRet.count(positive) == 0)
 +        {
 +            bool value = !GetBoolArg(name);
 +            mapSettingsRet[positive] = (value ? "1" : "0");
 +        }
 +    }
 +}
 +
 +void ParseParameters(int argc, const char*const argv[])
  {
      mapArgs.clear();
      mapMultiArgs.clear();
          #endif
          if (psz[0] != '-')
              break;
 +
          mapArgs[psz] = pszValue;
          mapMultiArgs[psz].push_back(pszValue);
      }
 +
 +    // New 0.6 features:
 +    BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
 +    {
 +        string name = entry.first;
 +
 +        //  interpret --foo as -foo (as long as both are not set)
 +        if (name.find("--") == 0)
 +        {
 +            std::string singleDash(name.begin()+1, name.end());
 +            if (mapArgs.count(singleDash) == 0)
 +                mapArgs[singleDash] = entry.second;
 +            name = singleDash;
 +        }
 +
 +        // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
 +        InterpretNegativeSetting(name, mapArgs);
 +    }
 +}
 +
 +std::string GetArg(const std::string& strArg, const std::string& strDefault)
 +{
 +    if (mapArgs.count(strArg))
 +        return mapArgs[strArg];
 +    return strDefault;
 +}
 +
 +int64 GetArg(const std::string& strArg, int64 nDefault)
 +{
 +    if (mapArgs.count(strArg))
 +        return atoi64(mapArgs[strArg]);
 +    return nDefault;
 +}
 +
 +bool GetBoolArg(const std::string& strArg, bool fDefault)
 +{
 +    if (mapArgs.count(strArg))
 +    {
 +        if (mapArgs[strArg].empty())
 +            return true;
 +        return (atoi(mapArgs[strArg]) != 0);
 +    }
 +    return fDefault;
  }
  
  bool SoftSetArg(const std::string& strArg, const std::string& strValue)
      return true;
  }
  
 -bool SoftSetArg(const std::string& strArg, bool fValue)
 +bool SoftSetBoolArg(const std::string& strArg, bool fValue)
  {
      if (fValue)
          return SoftSetArg(strArg, std::string("1"));
@@@ -637,7 -578,7 +648,7 @@@ vector<unsigned char> DecodeBase64(cons
  
      while (1)
      {
-          int dec = decode64_table[*p];
+          int dec = decode64_table[(unsigned char)*p];
           if (dec == -1) break;
           p++;
           switch (mode)
                  break;
  
              case 2: // 4n+2 base64 characters processed: require '=='
-                 if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1)
+                 if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
                      *pfInvalid = true;
                  break;
  
              case 3: // 4n+3 base64 characters processed: require '='
-                 if (left || p[0] != '=' || decode64_table[p[1]] != -1)
+                 if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
                      *pfInvalid = true;
                  break;
          }
@@@ -767,6 -708,17 +778,6 @@@ void PrintException(std::exception* pex
      throw;
  }
  
 -void ThreadOneMessageBox(string strMessage)
 -{
 -    // Skip message boxes if one is already open
 -    static bool fMessageBoxOpen;
 -    if (fMessageBoxOpen)
 -        return;
 -    fMessageBoxOpen = true;
 -    ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
 -    fMessageBoxOpen = false;
 -}
 -
  void PrintExceptionContinue(std::exception* pex, const char* pszThread)
  {
      char pszMessage[10000];
      strMiscWarning = pszMessage;
  }
  
 -
 -
 -
 -
 -
 -
 -
  #ifdef WIN32
 -typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
 -
  string MyGetSpecialFolderPath(int nFolder, bool fCreate)
  {
 -    char pszPath[MAX_PATH+100] = "";
 -
 -    // SHGetSpecialFolderPath isn't always available on old Windows versions
 -    HMODULE hShell32 = LoadLibraryA("shell32.dll");
 -    if (hShell32)
 +    char pszPath[MAX_PATH] = "";
 +    if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
      {
 -        PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
 -            (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
 -        bool fSuccess = false;
 -        if (pSHGetSpecialFolderPath)
 -            fSuccess =
 -            (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
 -        FreeModule(hShell32);
 -        if (fSuccess)
 -            return pszPath;
 +        return pszPath;
      }
 -
 -    // Backup option
 -    std::string strPath;
 +    else if (nFolder == CSIDL_STARTUP)
      {
 -        const char *pszEnv;
 -        if (nFolder == CSIDL_STARTUP)
 -        {
 -            pszEnv = getenv("USERPROFILE");
 -            if (pszEnv)
 -                strPath = pszEnv;
 -            strPath += "\\Start Menu\\Programs\\Startup";
 -        }
 -        else if (nFolder == CSIDL_APPDATA)
 -        {
 -            pszEnv = getenv("APPDATA");
 -            if (pszEnv)
 -                strPath = pszEnv;
 -        }
 +        return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup";
      }
 -
 -    return strPath;
 +    else if (nFolder == CSIDL_APPDATA)
 +    {
 +        return getenv("APPDATA");
 +    }
 +    return "";
  }
  #endif
  
@@@ -874,28 -858,15 +885,28 @@@ string GetConfigFile(
      return pathConfig.string();
  }
  
 -void ReadConfigFile(map<string, string>& mapSettingsRet,
 +bool ReadConfigFile(map<string, string>& mapSettingsRet,
                      map<string, vector<string> >& mapMultiSettingsRet)
  {
      namespace fs = boost::filesystem;
      namespace pod = boost::program_options::detail;
  
 +    if (mapSettingsRet.count("-datadir"))
 +    {
 +        if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"])))
 +        {
 +            fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]);
 +            strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
 +        }
 +        else
 +        {
 +            return false;
 +        }
 +    }
 +
      fs::ifstream streamConfig(GetConfigFile());
      if (!streamConfig.good())
 -        return;
 +        return true; // No bitcoin.conf file is OK
  
      set<string> setOptions;
      setOptions.insert("*");
          // Don't overwrite existing settings so command line settings override bitcoin.conf
          string strKey = string("-") + it->string_key;
          if (mapSettingsRet.count(strKey) == 0)
 +        {
              mapSettingsRet[strKey] = it->value[0];
 +            //  interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
 +            InterpretNegativeSetting(strKey, mapSettingsRet);
 +        }
          mapMultiSettingsRet[strKey].push_back(it->value[0]);
      }
 +    return true;
  }
  
  string GetPidFile()
@@@ -1001,22 -967,25 +1012,22 @@@ int64 GetAdjustedTime(
      return GetTime() + nTimeOffset;
  }
  
 -void AddTimeData(unsigned int ip, int64 nTime)
 +void AddTimeData(const CNetAddr& ip, int64 nTime)
  {
      int64 nOffsetSample = nTime - GetTime();
  
      // Ignore duplicates
 -    static set<unsigned int> setKnown;
 +    static set<CNetAddr> setKnown;
      if (!setKnown.insert(ip).second)
          return;
  
      // Add data
 -    static vector<int64> vTimeOffsets;
 -    if (vTimeOffsets.empty())
 -        vTimeOffsets.push_back(0);
 -    vTimeOffsets.push_back(nOffsetSample);
 -    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
 +    vTimeOffsets.input(nOffsetSample);
 +    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
      if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
      {
 -        sort(vTimeOffsets.begin(), vTimeOffsets.end());
 -        int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
 +        int64 nMedian = vTimeOffsets.median();
 +        std::vector<int64> vSorted = vTimeOffsets.sorted();
          // Only let other nodes change our time by so much
          if (abs64(nMedian) < 70 * 60)
          {
              {
                  // If nobody has a time different than ours but within 5 minutes of ours, give a warning
                  bool fMatch = false;
 -                BOOST_FOREACH(int64 nOffset, vTimeOffsets)
 +                BOOST_FOREACH(int64 nOffset, vSorted)
                      if (nOffset != 0 && abs64(nOffset) < 5 * 60)
                          fMatch = true;
  
                  }
              }
          }
 -        BOOST_FOREACH(int64 n, vTimeOffsets)
 -            printf("%+"PRI64d"  ", n);
 -        printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
 +        if (fDebug) {
 +            BOOST_FOREACH(int64 n, vSorted)
 +                printf("%+"PRI64d"  ", n);
 +            printf("|  ");
 +        }
 +        printf("nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
      }
  }
  
  
  
  
 -
  string FormatVersion(int nVersion)
  {
      if (nVersion%100 == 0)
  
  string FormatFullVersion()
  {
 -    string s = FormatVersion(VERSION) + pszSubVer;
 +    string s = FormatVersion(CLIENT_VERSION);
      if (VERSION_IS_BETA) {
          s += "-";
          s += _("beta");
      return s;
  }
  
 +// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
 +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
 +{
 +    std::ostringstream ss;
 +    ss << "/";
 +    ss << name << ":" << FormatVersion(nClientVersion);
 +    if (!comments.empty())
 +        ss << "(" << boost::algorithm::join(comments, "; ") << ")";
 +    ss << "/";
 +    return ss.str();
 +}
  
  
  
@@@ -1196,18 -1152,7 +1207,18 @@@ static void pop_lock(
  void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
  {
      push_lock(this, CLockLocation(pszName, pszFile, nLine));
 +#ifdef DEBUG_LOCKCONTENTION
 +    bool result = mutex.try_lock();
 +    if (!result)
 +    {
 +        printf("LOCKCONTENTION: %s\n", pszName);
 +        printf("Locker: %s:%d\n", pszFile, nLine);
 +        mutex.lock();
 +        printf("Locked\n");
 +    }
 +#else
      mutex.lock();
 +#endif
  }
  void CCriticalSection::Leave()
  {
@@@ -1224,19 -1169,9 +1235,19 @@@ bool CCriticalSection::TryEnter(const c
  
  #else
  
 -void CCriticalSection::Enter(const char*, const char*, int)
 +void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
  {
 +#ifdef DEBUG_LOCKCONTENTION
 +    bool result = mutex.try_lock();
 +    if (!result)
 +    {
 +        printf("LOCKCONTENTION: %s\n", pszName);
 +        printf("Locker: %s:%d\n", pszFile, nLine);
 +        mutex.lock();
 +    }
 +#else
      mutex.lock();
 +#endif
  }
  
  void CCriticalSection::Leave()
@@@ -1251,4 -1186,3 +1262,4 @@@ bool CCriticalSection::TryEnter(const c
  }
  
  #endif /* DEBUG_LOCKORDER */
 +