9 #include "ui_rpcconsole.h"
22 #endif // ENABLE_WALLET
26 #include <openssl/crypto.h>
36 #include <QSignalMapper>
40 #include <QStringList>
53 const QString
RESCAN(
"-rescan");
54 const QString
ZAPTXES1(
"-zapwallettxes=1");
55 const QString
ZAPTXES2(
"-zapwallettxes=2");
57 const QString
REINDEX(
"-reindex");
58 const QString
RESYNC(
"-resync");
64 {
"cmd-request",
":/icons/tx_input"},
65 {
"cmd-reply",
":/icons/tx_output"},
66 {
"cmd-error",
":/icons/tx_output"},
67 {
"misc",
":/icons/tx_inout"},
77 void request(
const QString& command);
80 void reply(
int category,
const QString& command);
94 timer.setSingleShot(
true);
103 boost::function<void(
void)>
func;
110 const char *
Name() {
return "Qt"; }
117 #include "rpcconsole.moc"
141 STATE_ESCAPE_DOUBLEQUOTED
142 } state = STATE_EATING_SPACES;
144 Q_FOREACH (
char ch, strCommand) {
147 case STATE_EATING_SPACES:
150 state = STATE_DOUBLEQUOTED;
153 state = STATE_SINGLEQUOTED;
156 state = STATE_ESCAPE_OUTER;
161 if (state == STATE_ARGUMENT)
163 args.push_back(curarg);
166 state = STATE_EATING_SPACES;
170 state = STATE_ARGUMENT;
173 case STATE_SINGLEQUOTED:
176 state = STATE_ARGUMENT;
182 case STATE_DOUBLEQUOTED:
185 state = STATE_ARGUMENT;
188 state = STATE_ESCAPE_DOUBLEQUOTED;
194 case STATE_ESCAPE_OUTER:
196 state = STATE_ARGUMENT;
198 case STATE_ESCAPE_DOUBLEQUOTED:
199 if (ch !=
'"' && ch !=
'\\') curarg +=
'\\';
201 state = STATE_DOUBLEQUOTED;
207 case STATE_EATING_SPACES:
210 args.push_back(curarg);
219 std::vector<std::string> args;
227 std::string strPrint;
232 RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
237 else if (result.
isStr())
240 strPrint = result.
write(2);
243 }
catch (
const UniValue& objError) {
249 }
catch (
const std::runtime_error&)
253 }
catch (
const std::exception& e) {
258 RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint),
263 peersTableContextMenu(0),
264 banTableContextMenu(0)
270 ui->openDebugLogfileButton->setIcon(QIcon(
":/icons/export"));
274 ui->lineEdit->installEventFilter(
this);
275 ui->messagesWidget->installEventFilter(
this);
277 connect(
ui->clearButton, SIGNAL(clicked()),
this, SLOT(
clear()));
278 connect(
ui->btnClearTrafficGraph, SIGNAL(clicked()),
ui->trafficGraph, SLOT(
clear()));
281 connect(
ui->btn_salvagewallet, SIGNAL(clicked()),
this, SLOT(
walletSalvage()));
282 connect(
ui->btn_rescan, SIGNAL(clicked()),
this, SLOT(
walletRescan()));
283 connect(
ui->btn_zapwallettxes1, SIGNAL(clicked()),
this, SLOT(
walletZaptxes1()));
284 connect(
ui->btn_zapwallettxes2, SIGNAL(clicked()),
this, SLOT(
walletZaptxes2()));
285 connect(
ui->btn_upgradewallet, SIGNAL(clicked()),
this, SLOT(
walletUpgrade()));
286 connect(
ui->btn_reindex, SIGNAL(clicked()),
this, SLOT(
walletReindex()));
287 connect(
ui->btn_resync, SIGNAL(clicked()),
this, SLOT(
walletResync()));
290 ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
292 std::string strPathCustom =
GetArg(
"-backuppath",
"");
293 int nCustomBackupThreshold =
GetArg(
"-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD);
295 if(!strPathCustom.empty()) {
296 ui->wallet_custombackuppath->setText(QString::fromStdString(strPathCustom));
297 ui->wallet_custombackuppath_label->show();
298 ui->wallet_custombackuppath->show();
301 if(!strPathCustom.empty() && nCustomBackupThreshold > 0) {
302 ui->wallet_custombackupthreshold->setText(QString::fromStdString(std::to_string(nCustomBackupThreshold)));
303 ui->wallet_custombackupthreshold_label->setVisible(
true);
304 ui->wallet_custombackupthreshold->setVisible(
true);
307 ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0));
308 ui->wallet_path->setText(QString::fromStdString(
GetDataDir().
string() + QDir::separator().toLatin1() +
GetArg(
"-wallet",
"wallet.dat")));
310 ui->label_berkeleyDBVersion->hide();
311 ui->berkeleyDBVersion->hide();
322 ui->peerHeading->setText(tr(
"Select a peer to view detailed information."));
340 if (event->type() == QEvent::KeyPress)
342 QKeyEvent* keyevt =
static_cast<QKeyEvent*
>(event);
343 int key = keyevt->key();
344 Qt::KeyboardModifiers mod = keyevt->modifiers();
347 if (obj ==
ui->lineEdit) {
353 if (obj ==
ui->lineEdit) {
359 case Qt::Key_PageDown:
360 if (obj ==
ui->lineEdit) {
361 QApplication::postEvent(
ui->messagesWidget,
new QKeyEvent(*keyevt));
369 QApplication::postEvent(
ui->lineEdit,
new QKeyEvent(*keyevt));
376 if (obj ==
ui->messagesWidget && ((!mod && !keyevt->text().isEmpty() &&
key != Qt::Key_Tab) ||
377 ((mod & Qt::ControlModifier) &&
key == Qt::Key_V) ||
378 ((mod & Qt::ShiftModifier) &&
key == Qt::Key_Insert))) {
379 ui->lineEdit->setFocus();
380 QApplication::postEvent(
ui->lineEdit,
new QKeyEvent(*keyevt));
385 return QDialog::eventFilter(obj, event);
391 ui->trafficGraph->setClientModel(model);
395 connect(model, SIGNAL(numConnectionsChanged(
int)),
this, SLOT(
setNumConnections(
int)));
398 connect(model, SIGNAL(numBlocksChanged(
int)),
this, SLOT(
setNumBlocks(
int)));
401 connect(model, SIGNAL(strMasternodesChanged(QString)),
this, SLOT(
setMasternodeCount(QString)));
404 connect(model, SIGNAL(bytesChanged(quint64, quint64)),
this, SLOT(
updateTrafficStats(quint64, quint64)));
408 ui->peerWidget->verticalHeader()->hide();
409 ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
410 ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
411 ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
412 ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
416 ui->peerWidget->horizontalHeader()->setStretchLastSection(
true);
419 QAction* disconnectAction =
new QAction(tr(
"&Disconnect Node"),
this);
420 QAction* banAction1h =
new QAction(tr(
"Ban Node for") +
" " + tr(
"1 &hour"),
this);
421 QAction* banAction24h =
new QAction(tr(
"Ban Node for") +
" " + tr(
"1 &day"),
this);
422 QAction* banAction7d =
new QAction(tr(
"Ban Node for") +
" " + tr(
"1 &week"),
this);
423 QAction* banAction365d =
new QAction(tr(
"Ban Node for") +
" " + tr(
"1 &year"),
this);
436 QSignalMapper* signalMapper =
new QSignalMapper(
this);
437 signalMapper->setMapping(banAction1h, 60*60);
438 signalMapper->setMapping(banAction24h, 60*60*24);
439 signalMapper->setMapping(banAction7d, 60*60*24*7);
440 signalMapper->setMapping(banAction365d, 60*60*24*365);
442 connect(banAction1h, SIGNAL(triggered()), signalMapper, SLOT(map()));
443 connect(banAction24h, SIGNAL(triggered()), signalMapper, SLOT(map()));
444 connect(banAction7d, SIGNAL(triggered()), signalMapper, SLOT(map()));
445 connect(banAction365d, SIGNAL(triggered()), signalMapper, SLOT(map()));
446 connect(signalMapper, SIGNAL(mapped(
int)),
this, SLOT(
banSelectedNode(
int)));
453 connect(
ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(
const QItemSelection&,
const QItemSelection&)),
454 this, SLOT(
peerSelected(
const QItemSelection &,
const QItemSelection &)));
460 ui->banlistWidget->verticalHeader()->hide();
461 ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
462 ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
463 ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
464 ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
467 ui->banlistWidget->horizontalHeader()->setStretchLastSection(
true);
470 QAction* unbanAction =
new QAction(tr(
"&Unban Node"),
this);
477 connect(
ui->banlistWidget, SIGNAL(customContextMenuRequested(
const QPoint&)),
this, SLOT(
showBanTableContextMenu(
const QPoint&)));
481 connect(
ui->banlistWidget, SIGNAL(clicked(
const QModelIndex&)),
this, SLOT(
clearSelectedNode()));
492 ui->networkName->setText(QString::fromStdString(
Params().NetworkIDString()));
495 QStringList wordList;
497 for (
size_t i = 0; i < commandList.size(); ++i)
499 wordList << commandList[i].c_str();
510 static QString categoryClass(
int category)
514 return "cmd-request";
566 QString resyncWarning = tr(
"This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.<br /><br />");
567 resyncWarning += tr(
"This needs quite some time and downloads a lot of data.<br /><br />");
568 resyncWarning += tr(
"Your transactions and funds will be visible again after the download has completed.<br /><br />");
569 resyncWarning += tr(
"Do you want to continue?.<br />");
570 QMessageBox::StandardButton retval = QMessageBox::question(
this, tr(
"Confirm resync Blockchain"),
572 QMessageBox::Yes | QMessageBox::Cancel,
573 QMessageBox::Cancel);
575 if (retval != QMessageBox::Yes) {
588 QStringList args = QApplication::arguments();
608 ui->messagesWidget->clear();
611 ui->lineEdit->clear();
612 ui->lineEdit->setFocus();
617 ui->messagesWidget->document()->addResource(
618 QTextDocument::ImageResource,
624 ui->messagesWidget->document()->setDefaultStyleSheet(
626 "td.time { color: #808080; padding-top: 3px; } "
627 "td.message { font-family: Courier, Courier New, Lucida Console, monospace; font-size: 12px; } "
628 "td.cmd-request { color: #006060; } "
629 "td.cmd-error { color: red; } "
630 ".secwarning { color: red; }"
631 "b { color: #006060; } ");
634 QString clsKey =
"(⌘)-L";
636 QString clsKey =
"Ctrl-L";
640 tr(
"Use up and down arrows to navigate history, and %1 to clear screen.").arg(
"<b>"+clsKey+
"</b>") +
"<br>" +
641 tr(
"Type <b>help</b> for an overview of available commands.") +
642 "<br><span class=\"secwarning\"><br>" +
643 tr(
"WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
651 if (windowType() != Qt::Widget)
657 QTime time = QTime::currentTime();
658 QString timeString = time.toString();
660 out +=
"<table><tr><td class=\"time\" width=\"65\">" + timeString +
"</td>";
661 out +=
"<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(category) +
"\"></td>";
662 out +=
"<td class=\"message " + categoryClass(category) +
"\" valign=\"middle\">";
667 out +=
"</td></tr></table>";
668 ui->messagesWidget->append(out);
676 QString connections = QString::number(count) +
" (";
680 ui->numberOfConnections->setText(connections);
685 ui->numberOfBlocks->setText(QString::number(count));
694 ui->masternodeCount->setText(strMasternodes);
699 QString cmd =
ui->lineEdit->text();
700 ui->lineEdit->clear();
702 if (!cmd.isEmpty()) {
729 ui->lineEdit->setText(cmd);
734 QThread* thread =
new QThread;
736 executor->moveToThread(thread);
739 connect(executor, SIGNAL(reply(
int, QString)),
this, SLOT(
message(
int, QString)));
741 connect(
this, SIGNAL(
cmdRequest(QString)), executor, SLOT(request(QString)));
746 connect(
this, SIGNAL(
stopExecutor()), executor, SLOT(deleteLater()));
747 connect(
this, SIGNAL(
stopExecutor()), thread, SLOT(quit()));
749 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
758 if (
ui->tabWidget->widget(index) ==
ui->tab_console) {
759 ui->lineEdit->setFocus();
760 }
else if (
ui->tabWidget->widget(index) !=
ui->tab_peers) {
772 QScrollBar* scrollbar =
ui->messagesWidget->verticalScrollBar();
773 scrollbar->setValue(scrollbar->maximum());
778 const int multiplier = 5;
779 int mins = value * multiplier;
785 ui->trafficGraph->setGraphRangeMins(mins);
797 ui->tabWidget->setCurrentIndex(0);
803 ui->tabWidget->setCurrentIndex(1);
809 ui->tabWidget->setCurrentIndex(2);
815 ui->tabWidget->setCurrentIndex(3);
821 ui->tabWidget->setCurrentIndex(4);
837 Q_UNUSED(deselected);
853 bool fUnselect =
false;
854 bool fReselect =
false;
860 int selectedRow = -1;
861 QModelIndexList selectedModelIndex =
ui->peerWidget->selectionModel()->selectedIndexes();
863 if (!selectedModelIndex.isEmpty()) {
864 selectedRow = selectedModelIndex.first().row();
871 if (detailNodeRow < 0) {
875 if (detailNodeRow != selectedRow) {
885 if (fUnselect && selectedRow >= 0) {
890 ui->peerWidget->selectRow(detailNodeRow);
903 QString peerAddrDetails(QString::fromStdString(stats->
nodeStats.
addrName) +
" ");
904 peerAddrDetails += tr(
"(node id: %1)").arg(QString::number(stats->
nodeStats.
nodeid));
906 peerAddrDetails +=
"<br />" + tr(
"via %1").arg(QString::fromStdString(stats->
nodeStats.
addrLocal));
907 ui->peerHeading->setText(peerAddrDetails);
933 ui->peerSyncHeight->setText(tr(
"Unknown"));
939 ui->peerCommonHeight->setText(tr(
"Unknown"));
942 ui->detailWidget->show();
947 QWidget::resizeEvent(event);
952 QWidget::showEvent(event);
964 QWidget::hideEvent(event);
991 QModelIndex index =
ui->peerWidget->indexAt(point);
998 QModelIndex index =
ui->banlistWidget->indexAt(point);
1013 if(detailNodeRow < 0)
1019 bannedNode->CloseSocketDisconnect();
1034 if(detailNodeRow < 0)
1047 if (!
LookupHost(addr.c_str(), resolved,
false))
1064 LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
1074 ui->peerWidget->selectionModel()->clearSelection();
1076 ui->detailWidget->hide();
1077 ui->peerHeading->setText(tr(
"Select a peer to view detailed information."));
1085 ui->banlistWidget->setVisible(visible);
1086 ui->banHeading->setVisible(visible);