Merge pull request #853 from laanwj/2012_02_altminimizetray
authorWladimir J. van der Laan <laanwj@gmail.com>
Mon, 27 Feb 2012 06:27:25 +0000 (22:27 -0800)
committerWladimir J. van der Laan <laanwj@gmail.com>
Mon, 27 Feb 2012 06:27:25 +0000 (22:27 -0800)
Yet another alternative "minimize to tray" implementation

Fixes problems with window positioning.

50 files changed:
contrib/debian/copyright
contrib/gitian-descriptors/deps-win32.yml
contrib/gitian-descriptors/gitian-win32.yml
doc/assets-attribution.txt
doc/release-process.txt
src/bignum.h
src/bitcoinrpc.cpp
src/checkpoints.cpp
src/db.cpp
src/db.h
src/init.cpp
src/irc.cpp
src/irc.h
src/key.h
src/keystore.cpp
src/keystore.h
src/main.cpp
src/main.h
src/net.cpp
src/net.h
src/netbase.cpp
src/protocol.h
src/qt/addressbookpage.cpp
src/qt/bitcoin.cpp
src/qt/bitcoin.qrc
src/qt/bitcoingui.cpp
src/qt/bitcoingui.h
src/qt/forms/messagepage.ui
src/qt/guiutil.cpp
src/qt/guiutil.h
src/qt/qrcodedialog.cpp
src/qt/qtipcserver.cpp
src/qt/res/icons/filesave.png [new file with mode: 0644]
src/qt/sendcoinsdialog.cpp
src/qt/sendcoinsdialog.h
src/qt/sendcoinsentry.cpp
src/qt/test/urltests.cpp
src/qt/transactionview.cpp
src/qt/walletmodel.cpp
src/qt/walletmodel.h
src/serialize.h
src/test/multisig_tests.cpp
src/test/script_P2SH_tests.cpp
src/test/script_tests.cpp
src/test/sigopcount_tests.cpp
src/test/transaction_tests.cpp
src/uint256.h
src/util.cpp
src/wallet.cpp
src/wallet.h

index 5db418d..71fa77c 100644 (file)
@@ -37,7 +37,7 @@ Files: src/qt/res/icons/address-book.png, src/qt/res/icons/export.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
 Copyright: David Vignoni (david@icon-king.com)
            ICON KING - www.icon-king.com
 License: LGPL
index 0107b30..776a8da 100644 (file)
@@ -7,7 +7,7 @@ architectures:
 packages: 
 - "mingw32"
 - "git-core"
-- "unzip"
+- "zip"
 - "faketime"
 - "wine"
 reference_datetime: "2011-01-30 00:00:00"
@@ -17,10 +17,14 @@ files:
 - "db-4.8.30.NC.tar.gz"
 - "miniupnpc-1.6.tar.gz"
 - "zlib-1.2.6.tar.gz"
-- "libpng-1.5.8.tar.gz"
+- "libpng-1.5.9.tar.gz"
 - "qrencode-3.2.0.tar.bz2"
 script: |
   #
+  export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
+  export FAKETIME=$REFERENCE_DATETIME
+  export TZ=UTC
+  #
   tar xzf openssl-1.0.0e.tar.gz
   cd openssl-1.0.0e
   ./Configure --cross-compile-prefix=i586-mingw32msvc- mingw
@@ -46,16 +50,22 @@ script: |
   make -f win32/Makefile.gcc PREFIX=i586-mingw32msvc- $MAKEOPTS
   cd ..
   #
-  tar xzf libpng-1.5.8.tar.gz
-  cd libpng-1.5.8
-  ./configure CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld LDFLAGS="-L../zlib-1.2.6/" CFLAGS="-I../zlib-1.2.6/"
+  tar xzf libpng-1.5.9.tar.gz
+  cd libpng-1.5.9
+  ./configure -disable-shared CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld LDFLAGS="-L../zlib-1.2.6/" CFLAGS="-I../zlib-1.2.6/"
   make $MAKEOPTS
   cd ..
   #
   tar xjf qrencode-3.2.0.tar.bz2
   cd qrencode-3.2.0
-  ./configure CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld png_LIBS="../libpng-1.5.8/.libs/libpng15.a ../zlib-1.2.6/libz.a" png_CFLAGS="-I../libpng-1.5.8"
+  ./configure CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld png_LIBS="../libpng-1.5.9/.libs/libpng15.a ../zlib-1.2.6/libz.a" png_CFLAGS="-I../libpng-1.5.9"
   make $MAKEOPTS
   cd ..
   #
-  tar cjvpf "$OUTDIR/bitcoin-deps-0.0.1.tbz2" "$HOME/build"
+  zip -r $OUTDIR/bitcoin-deps-0.0.3.zip \
+    $(ls qrencode-*/{qrencode.h,.libs/libqrencode.{,l}a} | sort) \
+    $(ls db-*/build_unix/{libdb_cxx.a,db.h,db_cxx.h,libdb.a,.libs/libdb_cxx-?.?.a} | sort) \
+    $(find openssl-* -name '*.a' -o -name '*.h' | sort) \
+    $(find miniupnpc -name '*.h' -o -name 'libminiupnpc.a' | sort)
+  # Kill wine processes as gitian won't figure out we are done otherwise
+  killall wineserver services.exe explorer.exe winedevice.exe
index 683eed3..9e372c7 100644 (file)
@@ -17,7 +17,7 @@ remotes:
 files:
 - "qt-win32-4.7.4-gitian.zip"
 - "boost-win32-1.47.0-gitian.zip"
-- "bitcoin-deps-0.0.1.tbz2"
+- "bitcoin-deps-0.0.3.zip"
 script: |
   #
   mkdir $HOME/qt
@@ -39,7 +39,7 @@ script: |
   mv include/boost .
   cd ..
   #
-  tar -C / -xjvpf bitcoin-deps-0.0.1.tbz2
+  unzip bitcoin-deps-0.0.3.zip
   #
   find -type f | xargs touch --date="$REFERENCE_DATETIME"
   #
index 5cf0a73..fabcdee 100644 (file)
@@ -7,7 +7,7 @@ Icon: src/qt/res/icons/address-book.png, src/qt/res/icons/export.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
index 8adf50d..841edbd 100644 (file)
@@ -27,7 +27,7 @@
    wget 'http://www.openssl.org/source/openssl-1.0.0e.tar.gz'
    wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
    wget 'http://zlib.net/zlib-1.2.6.tar.gz'
-   wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.8.tar.gz'
+   wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz'
    wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
    wget 'http://downloads.sourceforge.net/project/boost/boost/1.47.0/boost_1_47_0.tar.bz2'
    wget 'http://download.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.7.4.tar.gz'
index 4143f60..a750025 100644 (file)
@@ -243,7 +243,7 @@ public:
     std::vector<unsigned char> getvch() const
     {
         unsigned int nSize = BN_bn2mpi(this, NULL);
-        if (nSize < 4)
+        if (nSize <= 4)
             return std::vector<unsigned char>();
         std::vector<unsigned char> vch(nSize);
         BN_bn2mpi(this, &vch[0]);
index cf5bc64..c677b17 100644 (file)
@@ -120,6 +120,17 @@ 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)
 {
     int confirms = wtx.GetDepthInMainChain();
@@ -147,11 +158,13 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
 {
     Object result;
     result.push_back(Pair("hash", block.GetHash().GetHex()));
-    result.push_back(Pair("blockcount", blockindex->nHeight));
+    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)
@@ -159,9 +172,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
     result.push_back(Pair("tx", txhashes));
 
     if (blockindex->pprev)
-        result.push_back(Pair("hashprevious", blockindex->pprev->GetBlockHash().GetHex()));
+        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
     if (blockindex->pnext)
-        result.push_back(Pair("hashnext", blockindex->pnext->GetBlockHash().GetHex()));
+        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
     return result;
 }
 
@@ -1816,7 +1829,7 @@ Value getwork(const Array& params, bool fHelp)
         }
 
         // Update nTime
-        pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+        pblock->UpdateTime(pindexPrev);
         pblock->nNonce = 0;
 
         // Update nExtraNonce
@@ -1916,7 +1929,7 @@ Value getmemorypool(const Array& params, bool fHelp)
         }
 
         // Update nTime
-        pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+        pblock->UpdateTime(pindexPrev);
         pblock->nNonce = 0;
 
         Array transactions;
@@ -1939,13 +1952,7 @@ Value getmemorypool(const Array& params, bool fHelp)
         result.push_back(Pair("time", (int64_t)pblock->nTime));
         result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
         result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
-
-        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("bits", HexBits(pblock->nBits)));
 
         return result;
     }
@@ -2355,15 +2362,15 @@ 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");
@@ -2443,7 +2450,7 @@ void ThreadRPCServer2(void* parg)
 #endif
 
         ip::tcp::endpoint peer;
-        vnThreadsRunning[4]--;
+        vnThreadsRunning[THREAD_RPCSERVER]--;
 #ifdef USE_SSL
         acceptor.accept(sslStream.lowest_layer(), peer);
 #else
index f78712e..f5ce053 100644 (file)
@@ -30,6 +30,7 @@ namespace Checkpoints
         (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553"))
         (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
         (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))
+        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
         ;
 
     bool CheckBlock(int nHeight, const uint256& hash)
index 3bdda61..ea6d46a 100644 (file)
@@ -6,6 +6,7 @@
 #include "headers.h"
 #include "db.h"
 #include "net.h"
+#include <boost/version.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 
@@ -939,6 +940,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
                 ssValue >> nMinVersion;
                 if (nMinVersion > CLIENT_VERSION)
                     return DB_TOO_NEW;
+                pwallet->LoadMinVersion(nMinVersion);
             }
             else if (strType == "cscript")
             {
@@ -1064,14 +1066,19 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
                 filesystem::path pathDest(strDest);
                 if (filesystem::is_directory(pathDest))
                     pathDest = pathDest / wallet.strWalletFile;
+
+                try {
 #if BOOST_VERSION >= 104000
-                filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
+                    filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
 #else
-                filesystem::copy_file(pathSrc, pathDest);
+                    filesystem::copy_file(pathSrc, pathDest);
 #endif
-                printf("copied wallet.dat to %s\n", pathDest.string().c_str());
-
-                return true;
+                    printf("copied wallet.dat to %s\n", pathDest.string().c_str());
+                    return true;
+                } catch(const filesystem::filesystem_error &e) {
+                    printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
+                    return false;
+                }
             }
         }
         Sleep(100);
index 27479fe..2611faa 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -486,6 +486,11 @@ public:
         return Write(std::make_pair(std::string("setting"), strKey), value);
     }
 
+    bool WriteMinVersion(int nVersion)
+    {
+        return Write(std::string("minversion"), nVersion);
+    }
+
     bool ReadAccount(const std::string& strAccount, CAccount& account);
     bool WriteAccount(const std::string& strAccount, const CAccount& account);
     bool WriteAccountingEntry(const CAccountingEntry& acentry);
index 22f34aa..3a8fcdf 100644 (file)
@@ -187,6 +187,7 @@ bool AppInit2(int argc, char* argv[])
             "  -gen             \t\t  " + _("Generate coins") + "\n" +
             "  -gen=0           \t\t  " + _("Don't generate coins") + "\n" +
             "  -min             \t\t  " + _("Start minimized") + "\n" +
+            "  -splash          \t\t  " + _("Show splash screen on startup (default: 1)") + "\n" +
             "  -datadir=<dir>   \t\t  " + _("Specify data directory") + "\n" +
             "  -timeout=<n>     \t  "   + _("Specify connection timeout (in milliseconds)") + "\n" +
             "  -proxy=<ip:port> \t  "   + _("Connect through socks4 proxy") + "\n" +
@@ -197,6 +198,9 @@ bool AppInit2(int argc, char* argv[])
             "  -connect=<ip>    \t\t  " + _("Connect only to the specified node") + "\n" +
             "  -irc             \t  "   + _("Find peers using internet relay chat (default: 0)") + "\n" +
             "  -listen          \t  "   + _("Accept connections from outside (default: 1)") + "\n" +
+#ifdef QT_GUI
+            "  -lang=<lang>     \t\t  " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
+#endif
             "  -dnsseed         \t  "   + _("Find peers using DNS lookup (default: 1)") + "\n" +
             "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
             "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
@@ -210,10 +214,10 @@ bool AppInit2(int argc, char* argv[])
 #endif
 #endif
             "  -paytxfee=<amt>  \t  "   + _("Fee per KB to add to transactions you send") + "\n" +
-#ifdef GUI
+#ifdef QT_GUI
             "  -server          \t\t  " + _("Accept command line and JSON-RPC commands") + "\n" +
 #endif
-#ifndef WIN32
+#if !defined(WIN32) && !defined(QT_GUI)
             "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands") + "\n" +
 #endif
             "  -testnet         \t\t  " + _("Use the test network") + "\n" +
@@ -246,14 +250,24 @@ bool AppInit2(int argc, char* argv[])
 
         // Remove tabs
         strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
+#if defined(QT_GUI) && defined(WIN32)
+        // On windows, show a message box, as there is no stderr
+        wxMessageBox(strUsage, "Usage");
+#else
         fprintf(stderr, "%s", strUsage.c_str());
+#endif
         return false;
     }
 
     fTestNet = GetBoolArg("-testnet");
+    if (fTestNet)
+    {
+        SoftSetBoolArg("-irc", true);
+    }
+
     fDebug = GetBoolArg("-debug");
 
-#ifndef WIN32
+#if !defined(WIN32) && !defined(QT_GUI)
     fDaemon = GetBoolArg("-daemon");
 #else
     fDaemon = false;
@@ -284,7 +298,7 @@ bool AppInit2(int argc, char* argv[])
     }
 #endif
 
-#ifndef WIN32
+#if !defined(WIN32) && !defined(QT_GUI)
     if (fDaemon)
     {
         // Daemonize
index e795772..7a6f40c 100644 (file)
@@ -76,57 +76,6 @@ static bool Send(SOCKET hSocket, const char* pszSend)
     return true;
 }
 
-bool RecvLine(SOCKET hSocket, string& strLine)
-{
-    strLine = "";
-    loop
-    {
-        char c;
-        int nBytes = recv(hSocket, &c, 1, 0);
-        if (nBytes > 0)
-        {
-            if (c == '\n')
-                continue;
-            if (c == '\r')
-                return true;
-            strLine += c;
-            if (strLine.size() >= 9000)
-                return true;
-        }
-        else if (nBytes <= 0)
-        {
-            if (fShutdown)
-                return false;
-            if (nBytes < 0)
-            {
-                int nErr = WSAGetLastError();
-                if (nErr == WSAEMSGSIZE)
-                    continue;
-                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
-                {
-                    Sleep(10);
-                    continue;
-                }
-            }
-            if (!strLine.empty())
-                return true;
-            if (nBytes == 0)
-            {
-                // socket closed
-                printf("IRC socket closed\n");
-                return false;
-            }
-            else
-            {
-                // socket error
-                int nErr = WSAGetLastError();
-                printf("IRC recv failed: %d\n", nErr);
-                return false;
-            }
-        }
-    }
-}
-
 bool RecvLineIRC(SOCKET hSocket, string& strLine)
 {
     loop
index f5adaa1..08d62b8 100644 (file)
--- a/src/irc.h
+++ b/src/irc.h
@@ -5,7 +5,6 @@
 #ifndef BITCOIN_IRC_H
 #define BITCOIN_IRC_H
 
-bool RecvLine(SOCKET hSocket, std::string& strLine);
 void ThreadIRCSeed(void* parg);
 
 extern int nGotIRCAddresses;
index 9e92897..4058f11 100644 (file)
--- a/src/key.h
+++ b/src/key.h
@@ -114,7 +114,7 @@ public:
         return fCompressedPubKey;
     }
 
-    void MakeNewKey(bool fCompressed = true)
+    void MakeNewKey(bool fCompressed)
     {
         if (!EC_KEY_generate_key(pkey))
             throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
@@ -141,10 +141,13 @@ public:
         if (vchSecret.size() != 32)
             throw key_error("CKey::SetSecret() : secret must be 32 bytes");
         BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
-        if (bn == NULL) 
+        if (bn == NULL)
             throw key_error("CKey::SetSecret() : BN_bin2bn failed");
         if (!EC_KEY_regenerate_key(pkey,bn))
+        {
+            BN_clear_free(bn);
             throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
+        }
         BN_clear_free(bn);
         fSet = true;
         if (fCompressed || fCompressedPubKey)
index 18e5c37..e76f779 100644 (file)
@@ -8,16 +8,6 @@
 #include "db.h"
 #include "script.h"
 
-std::vector<unsigned char> CKeyStore::GenerateNewKey()
-{
-    RandAddSeedPerfmon();
-    CKey key;
-    key.MakeNewKey();
-    if (!AddKey(key))
-        throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
-    return key.GetPubKey();
-}
-
 bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
 {
     CKey key;
index 7eea02d..6757834 100644 (file)
@@ -29,8 +29,6 @@ public:
     virtual bool HaveCScript(const uint160 &hash) const =0;
     virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0;
 
-    // Generate a new key, and add it to the store
-    virtual std::vector<unsigned char> GenerateNewKey();
     virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const
     {
         CKey key;
index e4c6714..a9311e2 100644 (file)
@@ -21,7 +21,7 @@ using namespace boost;
 // Name of client reported in the 'version' message. Report the same name
 // for both bitcoind and bitcoin-qt, to make it harder for attackers to
 // target servers or GUI users specifically.
-const std::string CLIENT_NAME("bitcoin-qt");
+const std::string CLIENT_NAME("Satoshi");
 
 CCriticalSection cs_setpwalletRegistered;
 set<CWallet*> setpwalletRegistered;
@@ -922,6 +922,15 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
         printf("InvalidChainFound: WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.\n");
 }
 
+void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
+{
+    nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+
+    // Updating time can change work required on testnet:
+    if (fTestNet)
+        nBits = GetNextWorkRequired(pindexPrev, this);
+}
+
 
 
 
@@ -1396,6 +1405,9 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
     BOOST_FOREACH(CTransaction& tx, vDelete)
         tx.RemoveFromMemoryPool();
 
+    printf("REORGANIZE: Disconnected %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
+    printf("REORGANIZE: Connected %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
+
     return true;
 }
 
@@ -1643,7 +1655,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
         int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
         if (deltaTime < 0)
         {
-            pfrom->Misbehaving(100);
+            if (pfrom)
+                pfrom->Misbehaving(100);
             return error("ProcessBlock() : block with timestamp before last checkpoint");
         }
         CBigNum bnNewBlock;
@@ -1652,7 +1665,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
         bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
         if (bnNewBlock > bnRequired)
         {
-            pfrom->Misbehaving(100);
+            if (pfrom)
+                pfrom->Misbehaving(100);
             return error("ProcessBlock() : block with too little proof-of-work");
         }
     }
@@ -2091,18 +2105,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         CAddress addrFrom;
         uint64 nNonce = 1;
         vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
+        if (pfrom->nVersion < 209)
+        {
+            // Since Februari 20, 2012, the protocol is initiated at version 209,
+            // and earlier versions are no longer supported
+            printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
+            pfrom->fDisconnect = true;
+            return false;
+        }
+
         if (pfrom->nVersion == 10300)
             pfrom->nVersion = 300;
-        if (pfrom->nVersion >= 106 && !vRecv.empty())
+        if (!vRecv.empty())
             vRecv >> addrFrom >> nNonce;
-        if (pfrom->nVersion >= 106 && !vRecv.empty())
+        if (!vRecv.empty())
             vRecv >> pfrom->strSubVer;
-        if (pfrom->nVersion >= 209 && !vRecv.empty())
+        if (!vRecv.empty())
             vRecv >> pfrom->nStartingHeight;
 
-        if (pfrom->nVersion == 0)
-            return false;
-
         // Disconnect if we connected to ourself
         if (nNonce == nLocalHostNonce && nNonce > 1)
         {
@@ -2120,11 +2140,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         AddTimeData(pfrom->addr, nTime);
 
         // Change version
-        if (pfrom->nVersion >= 209)
-            pfrom->PushMessage("verack");
+        pfrom->PushMessage("verack");
         pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
-        if (pfrom->nVersion < 209)
-            pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
 
         if (!pfrom->fInbound)
         {
@@ -2188,8 +2205,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         vRecv >> vAddr;
 
         // Don't want addr from older versions unless seeding
-        if (pfrom->nVersion < 209)
-            return true;
         if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
             return true;
         if (vAddr.size() > 1000)
@@ -2651,17 +2666,14 @@ bool ProcessMessages(CNode* pfrom)
         }
 
         // Checksum
-        if (vRecv.GetVersion() >= 209)
+        uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+        unsigned int nChecksum = 0;
+        memcpy(&nChecksum, &hash, sizeof(nChecksum));
+        if (nChecksum != hdr.nChecksum)
         {
-            uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
-            unsigned int nChecksum = 0;
-            memcpy(&nChecksum, &hash, sizeof(nChecksum));
-            if (nChecksum != hdr.nChecksum)
-            {
-                printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
-                       strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
-                continue;
-            }
+            printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+               strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+            continue;
         }
 
         // Copy message to its own buffer
@@ -3168,7 +3180,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
     // Fill in header
     pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
     pblock->hashMerkleRoot = pblock->BuildMerkleTree();
-    pblock->nTime          = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+    pblock->UpdateTime(pindexPrev);
     pblock->nBits          = GetNextWorkRequired(pindexPrev, pblock.get());
     pblock->nNonce         = 0;
 
@@ -3326,6 +3338,7 @@ void static BitcoinMiner(CWallet *pwallet)
         FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
 
         unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
+        unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8);
         unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
 
 
@@ -3390,7 +3403,7 @@ void static BitcoinMiner(CWallet *pwallet)
                         {
                             nLogTime = GetTime();
                             printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
-                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
+                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
                         }
                     }
                 }
@@ -3401,7 +3414,7 @@ void static BitcoinMiner(CWallet *pwallet)
                 return;
             if (!fGenerateBitcoins)
                 return;
-            if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
+            if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors)
                 return;
             if (vNodes.empty())
                 break;
@@ -3413,8 +3426,14 @@ void static BitcoinMiner(CWallet *pwallet)
                 break;
 
             // Update nTime every few seconds
-            pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+            pblock->UpdateTime(pindexPrev);
             nBlockTime = ByteReverse(pblock->nTime);
+            if (fTestNet)
+            {
+                // Changing pblock->nTime can change work required on testnet:
+                nBlockBits = ByteReverse(pblock->nBits);
+                hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+            }
         }
     }
 }
@@ -3424,22 +3443,22 @@ void static ThreadBitcoinMiner(void* parg)
     CWallet* pwallet = (CWallet*)parg;
     try
     {
-        vnThreadsRunning[3]++;
+        vnThreadsRunning[THREAD_MINER]++;
         BitcoinMiner(pwallet);
-        vnThreadsRunning[3]--;
+        vnThreadsRunning[THREAD_MINER]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[3]--;
+        vnThreadsRunning[THREAD_MINER]--;
         PrintException(&e, "ThreadBitcoinMiner()");
     } catch (...) {
-        vnThreadsRunning[3]--;
+        vnThreadsRunning[THREAD_MINER]--;
         PrintException(NULL, "ThreadBitcoinMiner()");
     }
     UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
     nHPSTimerStart = 0;
-    if (vnThreadsRunning[3] == 0)
+    if (vnThreadsRunning[THREAD_MINER] == 0)
         dHashesPerSec = 0;
-    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
+    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]);
 }
 
 
@@ -3459,7 +3478,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
             nProcessors = 1;
         if (fLimitProcessors && nProcessors > nLimitProcessors)
             nProcessors = nLimitProcessors;
-        int nAddThreads = nProcessors - vnThreadsRunning[3];
+        int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER];
         printf("Starting %d BitcoinMiner threads\n", nAddThreads);
         for (int i = 0; i < nAddThreads; i++)
         {
index 908ada7..d9f976c 100644 (file)
@@ -913,6 +913,7 @@ public:
         return (int64)nTime;
     }
 
+    void UpdateTime(const CBlockIndex* pindexPrev);
 
 
     uint256 BuildMerkleTree() const
index 3a1777f..546bc6a 100644 (file)
@@ -38,8 +38,6 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
 
 
 
-
-
 //
 // Global state variables
 //
@@ -49,7 +47,7 @@ uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
 CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
 static CNode* pnodeLocalHost = NULL;
 uint64 nLocalHostNonce = 0;
-array<int, 10> vnThreadsRunning;
+array<int, THREAD_MAX> vnThreadsRunning;
 static SOCKET hListenSocket = INVALID_SOCKET;
 
 vector<CNode*> vNodes;
@@ -67,7 +65,6 @@ CCriticalSection cs_setservAddNodeAddresses;
 
 
 
-
 unsigned short GetListenPort()
 {
     return (unsigned short)(GetArg("-port", GetDefaultPort()));
@@ -86,6 +83,57 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
 
 
 
+bool RecvLine(SOCKET hSocket, string& strLine)
+{
+    strLine = "";
+    loop
+    {
+        char c;
+        int nBytes = recv(hSocket, &c, 1, 0);
+        if (nBytes > 0)
+        {
+            if (c == '\n')
+                continue;
+            if (c == '\r')
+                return true;
+            strLine += c;
+            if (strLine.size() >= 9000)
+                return true;
+        }
+        else if (nBytes <= 0)
+        {
+            if (fShutdown)
+                return false;
+            if (nBytes < 0)
+            {
+                int nErr = WSAGetLastError();
+                if (nErr == WSAEMSGSIZE)
+                    continue;
+                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
+                {
+                    Sleep(10);
+                    continue;
+                }
+            }
+            if (!strLine.empty())
+                return true;
+            if (nBytes == 0)
+            {
+                // socket closed
+                printf("socket closed\n");
+                return false;
+            }
+            else
+            {
+                // socket error
+                int nErr = WSAGetLastError();
+                printf("recv failed: %d\n", nErr);
+                return false;
+            }
+        }
+    }
+}
+
 
 
 bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
@@ -602,15 +650,15 @@ void ThreadSocketHandler(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
     try
     {
-        vnThreadsRunning[0]++;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]++;
         ThreadSocketHandler2(parg);
-        vnThreadsRunning[0]--;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[0]--;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
         PrintException(&e, "ThreadSocketHandler()");
     } catch (...) {
-        vnThreadsRunning[0]--;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
         throw; // support pthread_cancel()
     }
     printf("ThreadSocketHandler exiting\n");
@@ -712,9 +760,9 @@ void ThreadSocketHandler2(void* parg)
             }
         }
 
-        vnThreadsRunning[0]--;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
         int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
-        vnThreadsRunning[0]++;
+        vnThreadsRunning[THREAD_SOCKETHANDLER]++;
         if (fShutdown)
             return;
         if (nSelect == SOCKET_ERROR)
@@ -927,15 +975,15 @@ void ThreadMapPort(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
     try
     {
-        vnThreadsRunning[5]++;
+        vnThreadsRunning[THREAD_UPNP]++;
         ThreadMapPort2(parg);
-        vnThreadsRunning[5]--;
+        vnThreadsRunning[THREAD_UPNP]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[5]--;
+        vnThreadsRunning[THREAD_UPNP]--;
         PrintException(&e, "ThreadMapPort()");
     } catch (...) {
-        vnThreadsRunning[5]--;
+        vnThreadsRunning[THREAD_UPNP]--;
         PrintException(NULL, "ThreadMapPort()");
     }
     printf("ThreadMapPort exiting\n");
@@ -1056,7 +1104,7 @@ void MapPort(bool fMapPort)
         fUseUPnP = fMapPort;
         WriteSetting("fUseUPnP", fUseUPnP);
     }
-    if (fUseUPnP && vnThreadsRunning[5] < 1)
+    if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
     {
         if (!CreateThread(ThreadMapPort, NULL))
             printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
@@ -1090,15 +1138,15 @@ void ThreadDNSAddressSeed(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
     try
     {
-        vnThreadsRunning[6]++;
+        vnThreadsRunning[THREAD_DNSSEED]++;
         ThreadDNSAddressSeed2(parg);
-        vnThreadsRunning[6]--;
+        vnThreadsRunning[THREAD_DNSSEED]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[6]--;
+        vnThreadsRunning[THREAD_DNSSEED]--;
         PrintException(&e, "ThreadDNSAddressSeed()");
     } catch (...) {
-        vnThreadsRunning[6]--;
+        vnThreadsRunning[THREAD_DNSSEED]--;
         throw; // support pthread_cancel()
     }
     printf("ThreadDNSAddressSeed exiting\n");
@@ -1236,15 +1284,15 @@ void ThreadOpenConnections(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
     try
     {
-        vnThreadsRunning[1]++;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
         ThreadOpenConnections2(parg);
-        vnThreadsRunning[1]--;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[1]--;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
         PrintException(&e, "ThreadOpenConnections()");
     } catch (...) {
-        vnThreadsRunning[1]--;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
         PrintException(NULL, "ThreadOpenConnections()");
     }
     printf("ThreadOpenConnections exiting\n");
@@ -1278,9 +1326,9 @@ void ThreadOpenConnections2(void* parg)
     int64 nStart = GetTime();
     loop
     {
-        vnThreadsRunning[1]--;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
         Sleep(500);
-        vnThreadsRunning[1]++;
+        vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
         if (fShutdown)
             return;
 
@@ -1296,9 +1344,9 @@ void ThreadOpenConnections2(void* parg)
             nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
             if (nOutbound < nMaxOutboundConnections)
                 break;
-            vnThreadsRunning[1]--;
+            vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
             Sleep(2000);
-            vnThreadsRunning[1]++;
+            vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
             if (fShutdown)
                 return;
         }
@@ -1410,15 +1458,15 @@ void ThreadOpenAddedConnections(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg));
     try
     {
-        vnThreadsRunning[7]++;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
         ThreadOpenAddedConnections2(parg);
-        vnThreadsRunning[7]--;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[7]--;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
         PrintException(&e, "ThreadOpenAddedConnections()");
     } catch (...) {
-        vnThreadsRunning[7]--;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
         PrintException(NULL, "ThreadOpenAddedConnections()");
     }
     printf("ThreadOpenAddedConnections exiting\n");
@@ -1467,9 +1515,9 @@ void ThreadOpenAddedConnections2(void* parg)
         }
         if (fShutdown)
             return;
-        vnThreadsRunning[7]--;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
         Sleep(120000); // Retry every 2 minutes
-        vnThreadsRunning[7]++;
+        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
         if (fShutdown)
             return;
     }
@@ -1486,9 +1534,9 @@ bool OpenNetworkConnection(const CAddress& addrConnect)
         FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
         return false;
 
-    vnThreadsRunning[1]--;
+    vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
     CNode* pnode = ConnectNode(addrConnect);
-    vnThreadsRunning[1]++;
+    vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
     if (fShutdown)
         return false;
     if (!pnode)
@@ -1510,15 +1558,15 @@ void ThreadMessageHandler(void* parg)
     IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
     try
     {
-        vnThreadsRunning[2]++;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
         ThreadMessageHandler2(parg);
-        vnThreadsRunning[2]--;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
     }
     catch (std::exception& e) {
-        vnThreadsRunning[2]--;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
         PrintException(&e, "ThreadMessageHandler()");
     } catch (...) {
-        vnThreadsRunning[2]--;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
         PrintException(NULL, "ThreadMessageHandler()");
     }
     printf("ThreadMessageHandler exiting\n");
@@ -1566,11 +1614,11 @@ void ThreadMessageHandler2(void* parg)
         // Wait and allow messages to bunch up.
         // Reduce vnThreadsRunning so StopNode has permission to exit while
         // we're sleeping, but we must always check fShutdown after doing this.
-        vnThreadsRunning[2]--;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
         Sleep(100);
         if (fRequestShutdown)
             Shutdown(NULL);
-        vnThreadsRunning[2]++;
+        vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
         if (fShutdown)
             return;
     }
@@ -1773,23 +1821,26 @@ bool StopNode()
     fShutdown = true;
     nTransactionsUpdated++;
     int64 nStart = GetTime();
-    while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
-        || (fHaveUPnP && vnThreadsRunning[5] > 0) || vnThreadsRunning[6] > 0 || vnThreadsRunning[7] > 0
-    )
+    do
     {
+        int nThreadsRunning = 0;
+        for (int n = 0; n < THREAD_MAX; n++)
+            nThreadsRunning += vnThreadsRunning[n];
+        if (nThreadsRunning == 0)
+            break;
         if (GetTime() - nStart > 20)
             break;
         Sleep(20);
-    }
-    if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
-    if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
-    if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
-    if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
-    if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
-    if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
-    if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
-    if (vnThreadsRunning[7] > 0) printf("ThreadOpenAddedConnections still running\n");
-    while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
+    } while(true);
+    if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
+    if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
+    if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
+    if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n");
+    if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n");
+    if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
+    if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
+    if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
+    while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0)
         Sleep(20);
     Sleep(50);
 
index a66bc15..51a816d 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -29,6 +29,7 @@ inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer"
 inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
 static const unsigned int PUBLISH_HOPS = 5;
 
+bool RecvLine(SOCKET hSocket, std::string& strLine);
 bool GetMyExternalIP(CNetAddr& ipRet);
 bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
 void AddressCurrentlyConnected(const CService& addr);
@@ -68,14 +69,26 @@ public:
 
 
 
-
+enum threadId
+{
+    THREAD_SOCKETHANDLER,
+    THREAD_OPENCONNECTIONS,
+    THREAD_MESSAGEHANDLER,
+    THREAD_MINER,
+    THREAD_RPCSERVER,
+    THREAD_UPNP,
+    THREAD_DNSSEED,
+    THREAD_ADDEDCONNECTIONS,
+
+    THREAD_MAX
+};
 
 extern bool fClient;
 extern bool fAllowDNS;
 extern uint64 nLocalServices;
 extern CAddress addrLocalHost;
 extern uint64 nLocalHostNonce;
-extern boost::array<int, 10> vnThreadsRunning;
+extern boost::array<int, THREAD_MAX> vnThreadsRunning;
 
 extern std::vector<CNode*> vNodes;
 extern CCriticalSection cs_vNodes;
@@ -154,15 +167,9 @@ public:
         nServices = 0;
         hSocket = hSocketIn;
         vSend.SetType(SER_NETWORK);
-        vSend.SetVersion(0);
         vRecv.SetType(SER_NETWORK);
-        vRecv.SetVersion(0);
-        // Version 0.2 obsoletes 20 Feb 2012
-        if (GetTime() > 1329696000)
-        {
-            vSend.SetVersion(209);
-            vRecv.SetVersion(209);
-        }
+        vSend.SetVersion(209);
+        vRecv.SetVersion(209);
         nLastSend = 0;
         nLastRecv = 0;
         nLastSendEmpty = GetTime();
@@ -321,14 +328,11 @@ public:
         memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
 
         // Set the checksum
-        if (vSend.GetVersion() >= 209)
-        {
-            uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
-            unsigned int nChecksum = 0;
-            memcpy(&nChecksum, &hash, sizeof(nChecksum));
-            assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
-            memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
-        }
+        uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
+        unsigned int nChecksum = 0;
+        memcpy(&nChecksum, &hash, sizeof(nChecksum));
+        assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
+        memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
 
         if (fDebug) {
             printf("(%d bytes)\n", nSize);
index 54aa933..7799a65 100644 (file)
@@ -402,7 +402,7 @@ bool CNetAddr::IsRFC6145() const
 
 bool CNetAddr::IsRFC4843() const
 {
-    return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && GetByte(12) & 0xF0 == 0x10);
+    return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
 }
 
 bool CNetAddr::IsLocal() const
index 9ebbfad..b70dd71 100644 (file)
@@ -45,7 +45,6 @@ class CMessageHeader
              READWRITE(FLATDATA(pchMessageStart));
              READWRITE(FLATDATA(pchCommand));
              READWRITE(nMessageSize);
-             if (nVersion >= 209)
              READWRITE(nChecksum);
             )
 
index b5a798c..76aa87b 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <QSortFilterProxyModel>
 #include <QClipboard>
-#include <QFileDialog>
 #include <QMessageBox>
 #include <QMenu>
 
@@ -277,10 +276,9 @@ void AddressBookPage::done(int retval)
 void AddressBookPage::exportClicked()
 {
     // CSV is currently the only supported format
-    QString filename = QFileDialog::getSaveFileName(
+    QString filename = GUIUtil::getSaveFileName(
             this,
-            tr("Export Address Book Data"),
-            QDir::currentPath(),
+            tr("Export Address Book Data"), QString(),
             tr("Comma separated file (*.csv)"));
 
     if (filename.isNull()) return;
index 8c4b0e6..03b89f0 100644 (file)
@@ -27,18 +27,10 @@ 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;
 }
 
@@ -162,11 +154,13 @@ int main(int argc, char *argv[])
 
     ParseParameters(argc, argv);
 
-    // Load language files for system locale:
+    // 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;
 
@@ -189,9 +183,12 @@ int main(int argc, char *argv[])
     app.setApplicationName(QApplication::translate("main", "Bitcoin-Qt"));
 
     QSplashScreen splash(QPixmap(":/images/splash"), 0);
-    splash.show();
-    splash.setAutoFillBackground(true);
-    splashref = &splash;
+    if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
+    {
+        splash.show();
+        splash.setAutoFillBackground(true);
+        splashref = &splash;
+    }
 
     app.processEvents();
 
@@ -205,7 +202,8 @@ int main(int argc, char *argv[])
                 // Put this in a block, so that BitcoinGUI is cleaned up properly before
                 // calling Shutdown() in case of exceptions.
                 BitcoinGUI window;
-                splash.finish(&window);
+                if (splashref)
+                    splash.finish(&window);
                 OptionsModel optionsModel(pwalletMain);
                 ClientModel clientModel(&optionsModel);
                 WalletModel walletModel(pwalletMain, &optionsModel);
index 5693ae1..d823752 100644 (file)
@@ -37,6 +37,7 @@
         <file alias="lock_closed">res/icons/lock_closed.png</file>
         <file alias="lock_open">res/icons/lock_open.png</file>
         <file alias="key">res/icons/key.png</file>
+        <file alias="filesave">res/icons/filesave.png</file>
     </qresource>
     <qresource prefix="/images">
         <file alias="about">res/images/about.png</file>
index 3d6d7d7..abf2c38 100644 (file)
@@ -46,6 +46,8 @@
 #include <QStackedWidget>
 #include <QDateTime>
 #include <QMovie>
+#include <QFileDialog>
+#include <QDesktopServices>
 
 #include <QDragEnterEvent>
 #include <QUrl>
@@ -159,6 +161,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
 
 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
@@ -238,6 +242,8 @@ void BitcoinGUI::createActions()
     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"));
 
@@ -247,6 +253,7 @@ void BitcoinGUI::createActions()
     connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
     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()));
 }
 
@@ -262,11 +269,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);
-    file->addSeparator();
 #endif
+    file->addSeparator();
     file->addAction(quitAction);
 
     QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
@@ -484,7 +492,11 @@ void BitcoinGUI::setNumBlocks(int count)
     QString text;
 
     // Represent time from last generated block in human readable text
-    if(secs < 60)
+    if(secs <= 0)
+    {
+        // Fully up to date. Leave text empty.
+    }
+    else if(secs < 60)
     {
         text = tr("%n second(s) ago","",secs);
     }
@@ -504,7 +516,7 @@ void BitcoinGUI::setNumBlocks(int count)
     // Set icon state: spinning if catching up, tick otherwise
     if(secs < 30*60)
     {
-        tooltip = tr("Up to date") + QString("\n") + tooltip;
+        tooltip = tr("Up to date") + QString(".\n") + tooltip;
         labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
     }
     else
@@ -514,8 +526,11 @@ void BitcoinGUI::setNumBlocks(int count)
         syncIconMovie->start();
     }
 
-    tooltip += QString("\n");
-    tooltip += tr("Last received block was generated %1.").arg(text);
+    if(!text.isEmpty())
+    {
+        tooltip += QString("\n");
+        tooltip += tr("Last received block was generated %1.").arg(text);
+    }
 
     labelBlocksIcon->setToolTip(tooltip);
     progressBarLabel->setToolTip(tooltip);
@@ -714,7 +729,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
         QList<QUrl> urls = event->mimeData()->urls();
         foreach(const QUrl &url, urls)
         {
-            sendCoinsPage->handleURL(&url);
+            sendCoinsPage->handleURL(url.toString());
         }
     }
 
@@ -724,8 +739,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
 void BitcoinGUI::handleURL(QString strURL)
 {
     gotoSendCoinsPage();
-    QUrl url = QUrl(strURL);
-    sendCoinsPage->handleURL(&url);
+    sendCoinsPage->handleURL(strURL);
 }
 
 void BitcoinGUI::setEncryptionStatus(int status)
@@ -769,6 +783,17 @@ void BitcoinGUI::encryptWallet(bool status)
     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);
index f996e6b..dbc3264 100644 (file)
@@ -84,6 +84,7 @@ private:
     QAction *openBitcoinAction;
     QAction *exportAction;
     QAction *encryptWalletAction;
+    QAction *backupWalletAction;
     QAction *changePassphraseAction;
     QAction *aboutQtAction;
 
@@ -158,6 +159,8 @@ private slots:
     void incomingTransaction(const QModelIndex & parent, int start, int end);
     /** Encrypt the wallet */
     void encryptWallet(bool status);
+    /** Backup the wallet */
+    void backupWallet();
     /** Change encrypted wallet passphrase */
     void changePassphrase();
     /** Ask for pass phrase to unlock wallet temporarily */
index 8afa4b5..131e15b 100644 (file)
@@ -17,7 +17,7 @@
    <item>
     <widget class="QLabel" name="labelExplanation">
      <property name="text">
-      <string>You can sign messages with your addresses to prove you own them. Be careful to only sign statement you agree to with full details, as phishing attacks may try to trick you into signing access to them.</string>
+      <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string>
      </property>
      <property name="textFormat">
       <enum>Qt::AutoText</enum>
index 29ef554..ac69bd0 100644 (file)
@@ -15,6 +15,8 @@
 #include <QAbstractItemView>
 #include <QApplication>
 #include <QClipboard>
+#include <QFileDialog>
+#include <QDesktopServices>
 
 QString GUIUtil::dateTimeStr(qint64 nTime)
 {
@@ -49,15 +51,15 @@ void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
     widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
 }
 
-bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out)
+bool GUIUtil::parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out)
 {
-    if(url->scheme() != QString("bitcoin"))
+    if(url.scheme() != QString("bitcoin"))
         return false;
 
     SendCoinsRecipient rv;
-    rv.address = url->path();
+    rv.address = url.path();
     rv.amount = 0;
-    QList<QPair<QString, QString> > items = url->queryItems();
+    QList<QPair<QString, QString> > items = url.queryItems();
     for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
     {
         bool fShouldReturnFalse = false;
@@ -94,6 +96,20 @@ bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out)
     return true;
 }
 
+bool GUIUtil::parseBitcoinURL(QString url, SendCoinsRecipient *out)
+{
+    // Convert bitcoin:// to bitcoin:
+    //
+    //    Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host,
+    //    which will lowercase it (and thus invalidate the address).
+    if(url.startsWith("bitcoin://"))
+    {
+        url.replace(0, 10, "bitcoin:");
+    }
+    QUrl urlInstance(url);
+    return parseBitcoinURL(urlInstance, out);
+}
+
 QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine)
 {
     QString escaped = Qt::escape(str);
@@ -121,3 +137,50 @@ void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role)
         QApplication::clipboard()->setText(selection.at(0).data(role).toString());
     }
 }
+
+QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
+                                 const QString &dir,
+                                 const QString &filter,
+                                 QString *selectedSuffixOut)
+{
+    QString selectedFilter;
+    QString myDir;
+    if(dir.isEmpty()) // Default to user documents location
+    {
+        myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+    }
+    else
+    {
+        myDir = dir;
+    }
+    QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);
+
+    /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
+    QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
+    QString selectedSuffix;
+    if(filter_re.exactMatch(selectedFilter))
+    {
+        selectedSuffix = filter_re.cap(1);
+    }
+
+    /* Add suffix if needed */
+    QFileInfo info(result);
+    if(!result.isEmpty())
+    {
+        if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
+        {
+            /* No suffix specified, add selected suffix */
+            if(!result.endsWith("."))
+                result.append(".");
+            result.append(selectedSuffix);
+        }
+    }
+
+    /* Return selected suffix if asked to */
+    if(selectedSuffixOut)
+    {
+        *selectedSuffixOut = selectedSuffix;
+    }
+    return result;
+}
+
index 3a81bd2..75ba53f 100644 (file)
@@ -31,7 +31,8 @@ public:
 
     // Parse "bitcoin:" URL into recipient object, return true on succesful parsing
     // See Bitcoin URL definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
-    static bool parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out);
+    static bool parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out);
+    static bool parseBitcoinURL(QString url, SendCoinsRecipient *out);
 
     // HTML escaping for rich text controls
     static QString HtmlEscape(const QString& str, bool fMultiLine=false);
@@ -45,6 +46,20 @@ public:
      */
     static void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
 
+    /** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
+        when no suffix is provided by the user.
+
+      @param[in] parent  Parent window (or 0)
+      @param[in] caption Window caption (or empty, for default)
+      @param[in] dir     Starting directory (or empty, to default to documents directory)
+      @param[in] filter  Filter specification such as "Comma Separated Files (*.csv)"
+      @param[out] selectedSuffixOut  Pointer to return the suffix (file type) that was selected (or 0).
+                  Can be useful when choosing the save file format based on suffix.
+     */
+    static QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
+                                   const QString &dir=QString(), const QString &filter=QString(),
+                                   QString *selectedSuffixOut=0);
+
 };
 
 #endif // GUIUTIL_H
index ed4c758..8295983 100644 (file)
@@ -1,9 +1,9 @@
 #include "qrcodedialog.h"
 #include "ui_qrcodedialog.h"
+#include "guiutil.h"
+
 #include <QPixmap>
 #include <QUrl>
-#include <QFileDialog>
-#include <QDesktopServices>
 #include <QDebug>
 
 #include <qrencode.h>
@@ -34,8 +34,8 @@ QRCodeDialog::~QRCodeDialog()
     delete ui;
 }
 
-void QRCodeDialog::genCode() {
-
+void QRCodeDialog::genCode()
+{
     QString uri = getURI();
     //qDebug() << "Encoding:" << uri.toUtf8().constData();
     QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
@@ -52,7 +52,8 @@ void QRCodeDialog::genCode() {
     ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
 }
 
-QString QRCodeDialog::getURI() {
+QString QRCodeDialog::getURI()
+{
     QString ret = QString("bitcoin:%1").arg(address);
 
     int paramCount = 0;
@@ -80,21 +81,24 @@ QString QRCodeDialog::getURI() {
     return ret;
 }
 
-void QRCodeDialog::on_lnReqAmount_textChanged(const QString &) {
+void QRCodeDialog::on_lnReqAmount_textChanged(const QString &)
+{
     genCode();
 }
 
-void QRCodeDialog::on_lnLabel_textChanged(const QString &) {
+void QRCodeDialog::on_lnLabel_textChanged(const QString &)
+{
     genCode();
 }
 
-void QRCodeDialog::on_lnMessage_textChanged(const QString &) {
+void QRCodeDialog::on_lnMessage_textChanged(const QString &)
+{
     genCode();
 }
 
 void QRCodeDialog::on_btnSaveAs_clicked()
 {
-    QString fn = QFileDialog::getSaveFileName(this, "Save Image...", QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation), "Images (*.png)");
+    QString fn = GUIUtil::getSaveFileName(this, tr("Save Image..."), QString(), tr("PNG Images (*.png)"));
     if(!fn.isEmpty()) {
         myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
     }
index 90d5c14..018461a 100644 (file)
@@ -30,16 +30,7 @@ void ipcThread(void* parg)
         ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
         if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
         {
-            strBuf[nSize] = '\0';
-            // Convert bitcoin:// URLs to bitcoin: URIs
-            if (strBuf[8] == '/' && strBuf[9] == '/')
-            {
-                for (int i = 8; i < 256; i++)
-                {
-                    strBuf[i] = strBuf[i+2];
-                }
-            }
-            ThreadSafeHandleURL(strBuf);
+            ThreadSafeHandleURL(std::string(strBuf, nSize));
             Sleep(1000);
         }
         if (fShutdown)
@@ -66,16 +57,7 @@ void ipcInit()
             ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
             if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
             {
-                strBuf[nSize] = '\0';
-                // Convert bitcoin:// URLs to bitcoin: URIs
-                if (strBuf[8] == '/' && strBuf[9] == '/')
-                {
-                    for (int i = 8; i < 256; i++)
-                    {
-                        strBuf[i] = strBuf[i+2];
-                    }
-                }
-                ThreadSafeHandleURL(strBuf);
+                ThreadSafeHandleURL(std::string(strBuf, nSize));
             }
             else
                 break;
diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png
new file mode 100644 (file)
index 0000000..ae13a15
Binary files /dev/null and b/src/qt/res/icons/filesave.png differ
index 0d9a604..964313e 100644 (file)
@@ -265,7 +265,7 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
 }
 
 
-void SendCoinsDialog::handleURL(const QUrl *url)
+void SendCoinsDialog::handleURL(const QString &url)
 {
     SendCoinsRecipient rv;
     if(!GUIUtil::parseBitcoinURL(url, &rv))
index 847ee8b..4dc3f08 100644 (file)
@@ -30,7 +30,7 @@ public:
     QWidget *setupTabChain(QWidget *prev);
 
     void pasteEntry(const SendCoinsRecipient &rv);
-    void handleURL(const QUrl *url);
+    void handleURL(const QString &url);
 
 public slots:
     void clear();
index ab5460f..d98400c 100644 (file)
@@ -59,8 +59,9 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
 {
     if(!model)
         return;
-    ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));
-}
+    // Fill in label from address book, if no label is filled in yet
+    if(ui->addAsLabel->text().isEmpty())
+        ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));}
 
 void SendCoinsEntry::setModel(WalletModel *model)
 {
index 5ecc846..1f11795 100644 (file)
@@ -18,51 +18,54 @@ void URLTests::urlTests()
     SendCoinsRecipient rv;
     QUrl url;
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist="));
-    QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv));
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist="));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString());
     QVERIFY(rv.amount == 0);
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Wikipedia Example Address"));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString("Wikipedia Example Address"));
     QVERIFY(rv.amount == 0);
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=0.001"));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString());
     QVERIFY(rv.amount == 100000);
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1.001"));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString());
     QVERIFY(rv.amount == 100100000);
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=100&label=Wikipedia Example"));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.amount == 10000000000);
     QVERIFY(rv.label == QString("Wikipedia Example"));
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address"));
-    QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(GUIUtil::parseBitcoinURL(url, &rv));
     QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString());
+
+    QVERIFY(GUIUtil::parseBitcoinURL("bitcoin://175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address", &rv));
+    QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
     QVERIFY(rv.label == QString());
 
     // We currently dont implement the message paramenter (ok, yea, we break spec...)
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address"));
-    QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv));
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example"));
-    QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv));
 
     url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example"));
-    QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv));
+    QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv));
 }
index 4c357d1..eaed48b 100644 (file)
@@ -21,7 +21,6 @@
 #include <QTableView>
 #include <QHeaderView>
 #include <QPushButton>
-#include <QFileDialog>
 #include <QMessageBox>
 #include <QPoint>
 #include <QMenu>
@@ -264,10 +263,9 @@ void TransactionView::changedAmount(const QString &amount)
 void TransactionView::exportClicked()
 {
     // CSV is currently the only supported format
-    QString filename = QFileDialog::getSaveFileName(
+    QString filename = GUIUtil::getSaveFileName(
             this,
-            tr("Export Transaction Data"),
-            QDir::currentPath(),
+            tr("Export Transaction Data"), QString(),
             tr("Comma separated file (*.csv)"));
 
     if (filename.isNull()) return;
index f028f10..8344a65 100644 (file)
@@ -5,6 +5,7 @@
 #include "transactiontablemodel.h"
 
 #include "headers.h"
+#include "db.h" // for BackupWallet
 
 #include <QTimer>
 #include <QSet>
@@ -239,6 +240,11 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
     return retval;
 }
 
+bool WalletModel::backupWallet(const QString &filename)
+{
+    return BackupWallet(*wallet, filename.toLocal8Bit().data());
+}
+
 // WalletModel::UnlockContext implementation
 WalletModel::UnlockContext WalletModel::requestUnlock()
 {
index 89e8cdd..4123240 100644 (file)
@@ -77,6 +77,8 @@ public:
     // 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
index 6eb4f4e..c046bf3 100644 (file)
@@ -23,6 +23,7 @@ typedef long long  int64;
 typedef unsigned long long  uint64;
 
 #ifdef WIN32
+#define _WIN32_WINNT 0x0501
 #include <windows.h>
 // This is used to attempt to keep keying material out of swap
 // Note that VirtualLock does not provide this as a guarantee on Windows,
index 56b1804..8ae9290 100644 (file)
@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
 {
     CKey key[4];
     for (int i = 0; i < 4; i++)
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
 
     CScript a_and_b;
     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
 {
     CKey key[4];
     for (int i = 0; i < 4; i++)
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
 
     CScript a_and_b;
     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     CBitcoinAddress keyaddr[3];
     for (int i = 0; i < 3; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keyaddr[i].SetPubKey(key[i].GetPubKey());
     }
@@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
     }
 
index e389911..aa72c00 100644 (file)
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(sign)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
     }
 
@@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(set)
     std::vector<CKey> keys;
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keys.push_back(key[i]);
     }
@@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
     vector<CKey> keys;
     for (int i = 0; i < 3; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keys.push_back(key[i]);
     }
index 79dd7f1..493ea69 100644 (file)
@@ -72,9 +72,9 @@ sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
 {
     CKey key1, key2, key3;
-    key1.MakeNewKey();
-    key2.MakeNewKey();
-    key3.MakeNewKey();
+    key1.MakeNewKey(true);
+    key2.MakeNewKey(false);
+    key3.MakeNewKey(true);
 
     CScript scriptPubKey12;
     scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -105,10 +105,10 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
 {
     CKey key1, key2, key3, key4;
-    key1.MakeNewKey();
-    key2.MakeNewKey();
-    key3.MakeNewKey();
-    key4.MakeNewKey();
+    key1.MakeNewKey(true);
+    key2.MakeNewKey(false);
+    key3.MakeNewKey(true);
+    key4.MakeNewKey(false);
 
     CScript scriptPubKey23;
     scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
index 0b0a4a6..d301313 100644 (file)
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
     for (int i = 0; i < 3; i++)
     {
         CKey k;
-        k.MakeNewKey();
+        k.MakeNewKey(true);
         keys.push_back(k);
     }
     CScript s2;
index cd4d7ee..99163e5 100644 (file)
@@ -38,7 +38,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(i % 2);
         keystoreRet.AddKey(key[i]);
     }
 
index 5b1ba9f..caf6fa1 100644 (file)
@@ -92,13 +92,6 @@ public:
         return *this;
     }
 
-    base_uint& operator&=(uint64 b)
-    {
-        pn[0] &= (unsigned int)b;
-        pn[1] &= (unsigned int)(b >> 32);
-        return *this;
-    }
-
     base_uint& operator|=(uint64 b)
     {
         pn[0] |= (unsigned int)b;
index 12ac076..f1af91d 100644 (file)
@@ -454,6 +454,21 @@ vector<unsigned char> ParseHex(const string& str)
     return ParseHex(str.c_str());
 }
 
+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();
@@ -494,17 +509,8 @@ void ParseParameters(int argc, const char*const argv[])
             name = singleDash;
         }
 
-        //  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 (mapArgs.count(positive) == 0)
-            {
-                bool value = !GetBoolArg(name);
-                mapArgs[positive] = (value ? "1" : "0");
-            }
-        }
+        // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
+        InterpretNegativeSetting(name, mapArgs);
     }
 }
 
@@ -920,7 +926,11 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
         // 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]);
     }
 }
index 1e769d7..30590c8 100644 (file)
@@ -15,6 +15,23 @@ using namespace std;
 // mapWallet
 //
 
+std::vector<unsigned char> CWallet::GenerateNewKey()
+{
+    bool fCompressed = true; // default to compressed public keys
+
+    RandAddSeedPerfmon();
+    CKey key;
+    key.MakeNewKey(fCompressed);
+
+    // Compressed public keys were introduced in version 0.6.0
+    if (fCompressed)
+        SetMinVersion(59900);
+
+    if (!AddKey(key))
+        throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
+    return key.GetPubKey();
+}
+
 bool CWallet::AddKey(const CKey& key)
 {
     if (!CCryptoKeyStore::AddKey(key))
@@ -131,6 +148,32 @@ public:
     )
 };
 
+bool CWallet::SetMinVersion(int nVersion, CWalletDB* pwalletdbIn)
+{
+    if (nWalletVersion >= nVersion)
+        return true;
+
+    nWalletVersion = nVersion;
+
+    if (fFileBacked)
+    {
+        CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
+        if (nWalletVersion >= 40000)
+        {
+            // Versions prior to 0.4.0 did not support the "minversion" record.
+            // Use a CCorruptAddress to make them crash instead.
+            CCorruptAddress corruptAddress;
+            pwalletdb->WriteSetting("addrIncoming", corruptAddress);
+        }
+        if (nWalletVersion > 40000)
+            pwalletdb->WriteMinVersion(nWalletVersion);
+        if (!pwalletdbIn)
+            delete pwalletdb;
+    }
+
+    return true;
+}
+
 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
 {
     if (IsCrypted())
@@ -184,14 +227,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
             exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
         }
 
+        // Encryption was introduced in version 0.4.0
+        SetMinVersion(40000, pwalletdbEncryption);
+
         if (fFileBacked)
         {
-            CCorruptAddress corruptAddress;
-            pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
             if (!pwalletdbEncryption->TxnCommit())
                 exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
 
-            pwalletdbEncryption->Close();
+            delete pwalletdbEncryption;
             pwalletdbEncryption = NULL;
         }
 
index 3fdef50..fea3297 100644 (file)
@@ -25,6 +25,8 @@ private:
 
     CWalletDB *pwalletdbEncryption;
 
+    int nWalletVersion;
+
 public:
     mutable CCriticalSection cs_wallet;
 
@@ -33,18 +35,21 @@ public:
 
     std::set<int64> setKeyPool;
 
+
     typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
     MasterKeyMap mapMasterKeys;
     unsigned int nMasterKeyMaxID;
 
     CWallet()
     {
+        nWalletVersion = 0;
         fFileBacked = false;
         nMasterKeyMaxID = 0;
         pwalletdbEncryption = NULL;
     }
     CWallet(std::string strWalletFileIn)
     {
+        nWalletVersion = 0;
         strWalletFile = strWalletFileIn;
         fFileBacked = true;
         nMasterKeyMaxID = 0;
@@ -61,11 +66,15 @@ public:
     std::vector<unsigned char> vchDefaultKey;
 
     // keystore implementation
+    // Generate a new key
+    std::vector<unsigned char> GenerateNewKey();
     // Adds a key to the store, and saves it to disk.
     bool AddKey(const CKey& key);
     // Adds a key to the store, without saving it to disk (used by LoadWallet)
     bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
 
+    bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; return true; }
+
     // Adds an encrypted key to the store, and saves it to disk.
     bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
     // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
@@ -206,6 +215,8 @@ public:
     bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
 
     bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
+
+    bool SetMinVersion(int nVersion, CWalletDB* pwalletdbIn = NULL);
 };