diff --git a/doc/assets-attribution.txt b/doc/assets-attribution.txt index fabcdeea762..0b0e3770652 100644 --- a/doc/assets-attribution.txt +++ b/doc/assets-attribution.txt @@ -1,3 +1,7 @@ +Code: src/strlcpy.h +Author: Todd C. Miller +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 diff --git a/scripts/qt/make_windows_icon.py b/scripts/qt/make_windows_icon.py deleted file mode 100755 index bf607b1c623..00000000000 --- a/scripts/qt/make_windows_icon.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# create multiresolution windows icon -ICON_SRC=../../src/qt/res/icons/bitcoin.png -ICON_DST=../../src/qt/res/icons/bitcoin.ico -convert ${ICON_SRC} -resize 16x16 bitcoin-16.png -convert ${ICON_SRC} -resize 32x32 bitcoin-32.png -convert ${ICON_SRC} -resize 48x48 bitcoin-48.png -convert bitcoin-16.png bitcoin-32.png bitcoin-48.png ${ICON_DST} - diff --git a/scripts/qt/make_windows_icon.py b/scripts/qt/make_windows_icon.py new file mode 120000 index 00000000000..f51c32a2158 --- /dev/null +++ b/scripts/qt/make_windows_icon.py @@ -0,0 +1 @@ +make_windows_icon.sh \ No newline at end of file diff --git a/scripts/qt/make_windows_icon.sh b/scripts/qt/make_windows_icon.sh new file mode 100755 index 00000000000..bf607b1c623 --- /dev/null +++ b/scripts/qt/make_windows_icon.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# create multiresolution windows icon +ICON_SRC=../../src/qt/res/icons/bitcoin.png +ICON_DST=../../src/qt/res/icons/bitcoin.ico +convert ${ICON_SRC} -resize 16x16 bitcoin-16.png +convert ${ICON_SRC} -resize 32x32 bitcoin-32.png +convert ${ICON_SRC} -resize 48x48 bitcoin-48.png +convert bitcoin-16.png bitcoin-32.png bitcoin-48.png ${ICON_DST} + diff --git a/src/bignum.h b/src/bignum.h index c7c2ff17304..9962b78372f 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -301,7 +301,7 @@ public: while (isxdigit(*psz)) { *this <<= 4; - int n = phexdigit[*psz++]; + int n = phexdigit[(unsigned char)*psz++]; *this += n; } if (fNegative) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 98702ee7cb2..e9056ca0af2 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1293,14 +1293,21 @@ Value listtransactions(const Array& params, bool fHelp) 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 TxPair; typedef multimap 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::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); @@ -1313,10 +1320,8 @@ Value listtransactions(const Array& params, bool fHelp) 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) @@ -1325,18 +1330,21 @@ Value listtransactions(const Array& params, bool fHelp) 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; } @@ -2361,6 +2369,10 @@ void ThreadRPCServer(void* parg) printf("ThreadRPCServer exiting\n"); } +#ifdef QT_GUI +extern bool HACK_SHUTDOWN; +#endif + void ThreadRPCServer2(void* parg) { printf("ThreadRPCServer started\n"); @@ -2397,9 +2409,27 @@ void ThreadRPCServer2(void* parg) 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); diff --git a/src/keystore.h b/src/keystore.h index c32db2620a8..52f5f21aa92 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -15,6 +15,8 @@ protected: mutable CCriticalSection cs_KeyStore; public: + virtual ~CKeyStore() {} + // Add a key to the store. virtual bool AddKey(const CKey& key) =0; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 8fd6d52b7e1..5d724ea1d10 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -27,8 +27,9 @@ struct AddressTableEntry }; // Private implementation -struct AddressTablePriv +class AddressTablePriv { +public: CWallet *wallet; QList cachedAddressTable; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 71e2daf9318..c7f0092df97 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -9,6 +9,7 @@ #include "headers.h" #include "init.h" #include "qtipcserver.h" +#include "util.h" #include #include @@ -40,7 +41,7 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption, if (modal) while (!guiref) - sleep(1); + Sleep(1000); // Message from network thread if(guiref) @@ -130,6 +131,15 @@ 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[]) { @@ -286,9 +296,9 @@ int main(int argc, char *argv[]) return 1; } } catch (std::exception& e) { - PrintException(&e, "Runaway exception"); + handleRunawayException(&e); } catch (...) { - PrintException(NULL, "Runaway exception"); + handleRunawayException(NULL); } return 0; } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 4a9b420485f..1c4d665bee8 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -4,6 +4,9 @@ * W.J. van der Laan 20011-2012 * The Bitcoin Developers 20011-2012 */ + +#include "checkpoints.h" + #include "bitcoingui.h" #include "transactiontablemodel.h" #include "addressbookpage.h" @@ -515,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 +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); } diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 8cc3c85d7ae..cecb8aecd79 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -106,6 +106,9 @@ void EditAddressDialog::accept() tr("New key generation failed."), QMessageBox::Ok, QMessageBox::Ok); return; + case AddressTableModel::OK: + // Failed with unknown reason. Just reject. + break; } return; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 75fd4ccf186..0025337ab82 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -278,7 +278,8 @@ DisplayOptionsPage::DisplayOptionsPage(QWidget *parent): layout->addLayout(unit_hbox); - display_addresses = new QCheckBox(tr("Display addresses in transaction list"), this); + display_addresses = new QCheckBox(tr("&Display addresses in transaction list"), this); + display_addresses->setToolTip(tr("Whether to show Bitcoin addresses in the transaction list")); layout->addWidget(display_addresses); layout->addStretch(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 592ae6f45ab..b4029aa0d22 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -154,6 +154,8 @@ void SendCoinsDialog::on_sendButton_clicked() 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; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 480d4ac25e0..28620bf3aa2 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -45,8 +45,9 @@ struct TxLessThan }; // Private implementation -struct TransactionTablePriv +class TransactionTablePriv { +public: TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent): wallet(wallet), parent(parent) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 4123240e90a..e78773f8a33 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -34,8 +34,7 @@ public: DuplicateAddress, TransactionCreationFailed, // Error returned when wallet is still locked TransactionCommitFailed, - Aborted, - MiscError + Aborted }; enum EncryptionStatus diff --git a/src/uint256.h b/src/uint256.h index cfc2eb128eb..0947816785e 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -308,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; diff --git a/src/util.cpp b/src/util.cpp index 08752e69307..5ba650420b8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -5,6 +5,17 @@ #include "headers.h" #include "strlcpy.h" #include + +// 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 #include #include @@ -637,7 +648,7 @@ vector DecodeBase64(const char* p, bool* pfInvalid) while (1) { - int dec = decode64_table[*p]; + int dec = decode64_table[(unsigned char)*p]; if (dec == -1) break; p++; switch (mode) @@ -677,12 +688,12 @@ vector DecodeBase64(const char* p, bool* pfInvalid) 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; }