<commit_before>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#include <QDebug>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC to %5 using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice).arg(address));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(tryAcceptOffer()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::slotConfirmedFinished(QNetworkReply * reply){
	if(reply->error() != QNetworkReply::NoError) {
		ui->confirmButton->setText(m_buttonText);
        QMessageBox::critical(this, windowTitle(),
            tr("Error making request: ") + reply->errorString(),
                QMessageBox::Ok, QMessageBox::Ok);
		return;
	}
	double valueAmount = 0;
	QString time;
	int height;

	QByteArray bytes = reply->readAll();
	QString str = QString::fromUtf8(bytes.data(), bytes.size());
	UniValue outerValue;
	bool read = outerValue.read(str.toStdString());
	if (read)
	{
		UniValue outerObj = outerValue.get_obj();
		UniValue statusValue = find_value(outerObj, "status");
		if (statusValue.isStr())
		{
			if(statusValue.get_str() != "success")
			{
				ui->confirmButton->setText(m_buttonText);
				QMessageBox::critical(this, windowTitle(),
					tr("Transaction status not successful: ") + QString::fromStdString(statusValue.get_str()),
						QMessageBox::Ok, QMessageBox::Ok);
				return;
			}
		}
		outerObj = find_value(outerObj, "data");
		UniValue heightValue = find_value(outerObj, "block");
		if (heightValue.isNum())
			height = heightValue.get_int();
		UniValue timeValue = find_value(outerObj, "time_utc");
		if (timeValue.isStr())
			time = QString::fromStdString(timeValue.get_str());
		UniValue outputsValue = find_value(outerObj, "vouts");
		if (outputsValue.isArray())
		{
			UniValue outputs = outputsValue.get_array();
			for (unsigned int idx = 0; idx < outputs.size(); idx++) {
				const UniValue& output = outputs[idx];
				UniValue addressValue = find_value(output, "address");
				if(addressValue.isStr())
				{
					qDebug() << "address";
					if(addressValue.get_str() == address.toStdString())
					{
						qDebug() << address;
						UniValue paymentValue = find_value(output, "amount");
						qDebug() << "payment";
						if(paymentValue.isStr())
						{
							qDebug() << QString::fromStdString(paymentValue.get_str());
							valueAmount += QString::fromStdString(paymentValue.get_str()).toDouble();
							qDebug() << "valueAmount";
							qDebug() << valueAmount;
							if(valueAmount >= dblPrice)
							{
								ui->confirmButton->setText(m_buttonText);
								QMessageBox::information(this, windowTitle(),
									tr("Transaction ID %1 was found in the Bitcoin blockchain! Full payment has been detected in block %2 at %3. It is recommended that you confirm payment by opening your Bitcoin wallet and seeing the funds in your account.").arg(ui->btctxidEdit->text().trimmed()).arg(height).arg(time),
									QMessageBox::Ok, QMessageBox::Ok);
								acceptOffer();
								return;
							}
						}
					}

				}
			}
		}
	}
	else
	{
		ui->confirmButton->setText(m_buttonText);
		QMessageBox::critical(this, windowTitle(),
			tr("Cannot parse JSON response: ") + str,
				QMessageBox::Ok, QMessageBox::Ok);
		return;
	}

	reply->deleteLater();
	ui->confirmButton->setText(m_buttonText);
	QMessageBox::warning(this, windowTitle(),
		tr("Payment not found in the Bitcoin blockchain! Please try again later."),
			QMessageBox::Ok, QMessageBox::Ok);
}
void OfferAcceptDialogBTC::CheckPaymentInBTC()
{
	m_buttonText = ui->confirmButton->text();
	ui->confirmButton->setText(tr("Please Wait..."));
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	connect(nam, SIGNAL(finished(QNetworkReply *)), this, SLOT(slotConfirmedFinished(QNetworkReply *)));
	QUrl url("http://btc.blockr.io/api/v1/tx/info/" + ui->btctxidEdit->text().trimmed());
	QNetworkRequest request(url);
	nam->get(request);
}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::tryAcceptOffer()
{
	if (ui->btctxidEdit->text().trimmed().isEmpty()) {
        ui->btctxidEdit->setText("");
        QMessageBox::critical(this, windowTitle(),
        tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
            QMessageBox::Ok, QMessageBox::Ok);
        return;
    }
	CheckPaymentInBTC();
}
void OfferAcceptDialogBTC::acceptOffer(){
		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().trimmed().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<commit_msg>fix crash<commit_after>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#include <QDebug>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC to %5 using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice).arg(address));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(tryAcceptOffer()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::slotConfirmedFinished(QNetworkReply * reply){
	if(reply->error() != QNetworkReply::NoError) {
		ui->confirmButton->setText(m_buttonText);
        QMessageBox::critical(this, windowTitle(),
            tr("Error making request: ") + reply->errorString(),
                QMessageBox::Ok, QMessageBox::Ok);
		return;
	}
	double valueAmount = 0;
	QString time;
	int height;

	QByteArray bytes = reply->readAll();
	QString str = QString::fromUtf8(bytes.data(), bytes.size());
	UniValue outerValue;
	bool read = outerValue.read(str.toStdString());
	if (read)
	{
		UniValue outerObj = outerValue.get_obj();
		UniValue statusValue = find_value(outerObj, "status");
		if (statusValue.isStr())
		{
			if(statusValue.get_str() != "success")
			{
				ui->confirmButton->setText(m_buttonText);
				QMessageBox::critical(this, windowTitle(),
					tr("Transaction status not successful: ") + QString::fromStdString(statusValue.get_str()),
						QMessageBox::Ok, QMessageBox::Ok);
				return;
			}
		}
		UniValue dataObj = find_value(outerObj, "data");
		UniValue heightValue = find_value(dataObj, "block");
		if (heightValue.isNum())
			height = heightValue.get_int();
		UniValue timeValue = find_value(dataObj, "time_utc");
		if (timeValue.isStr())
			time = QString::fromStdString(timeValue.get_str());
		UniValue outputsValue = find_value(dataObj, "vouts");
		if (outputsValue.isArray())
		{
			UniValue outputs = outputsValue.get_array();
			for (unsigned int idx = 0; idx < outputs.size(); idx++) {
				const UniValue& output = outputs[idx];
				UniValue addressValue = find_value(output, "address");
				if(addressValue.isStr())
				{
					qDebug() << "address";
					if(addressValue.get_str() == address.toStdString())
					{
						qDebug() << address;
						UniValue paymentValue = find_value(output, "amount");
						qDebug() << "payment";
						if(paymentValue.isStr())
						{
							qDebug() << QString::fromStdString(paymentValue.get_str());
							valueAmount += QString::fromStdString(paymentValue.get_str()).toDouble();
							qDebug() << "valueAmount";
							qDebug() << valueAmount;
							if(valueAmount >= dblPrice)
							{
								ui->confirmButton->setText(m_buttonText);
								QMessageBox::information(this, windowTitle(),
									tr("Transaction ID %1 was found in the Bitcoin blockchain! Full payment has been detected in block %2 at %3. It is recommended that you confirm payment by opening your Bitcoin wallet and seeing the funds in your account.").arg(ui->btctxidEdit->text().trimmed()).arg(height).arg(time),
									QMessageBox::Ok, QMessageBox::Ok);
								acceptOffer();
								return;
							}
						}
					}

				}
			}
		}
	}
	else
	{
		ui->confirmButton->setText(m_buttonText);
		QMessageBox::critical(this, windowTitle(),
			tr("Cannot parse JSON response: ") + str,
				QMessageBox::Ok, QMessageBox::Ok);
		return;
	}

	reply->deleteLater();
	ui->confirmButton->setText(m_buttonText);
	QMessageBox::warning(this, windowTitle(),
		tr("Payment not found in the Bitcoin blockchain! Please try again later."),
			QMessageBox::Ok, QMessageBox::Ok);
}
void OfferAcceptDialogBTC::CheckPaymentInBTC()
{
	m_buttonText = ui->confirmButton->text();
	ui->confirmButton->setText(tr("Please Wait..."));
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	connect(nam, SIGNAL(finished(QNetworkReply *)), this, SLOT(slotConfirmedFinished(QNetworkReply *)));
	QUrl url("http://btc.blockr.io/api/v1/tx/info/" + ui->btctxidEdit->text().trimmed());
	QNetworkRequest request(url);
	nam->get(request);
}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::tryAcceptOffer()
{
	if (ui->btctxidEdit->text().trimmed().isEmpty()) {
        ui->btctxidEdit->setText("");
        QMessageBox::critical(this, windowTitle(),
        tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
            QMessageBox::Ok, QMessageBox::Ok);
        return;
    }
	CheckPaymentInBTC();
}
void OfferAcceptDialogBTC::acceptOffer(){
		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().trimmed().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<|endoftext|>


<commit_before>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#include <QDebug>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC to %5 using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice).arg(address));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(tryAcceptOffer()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::slotConfirmedFinished(QNetworkReply * reply){
	if(reply->error() != QNetworkReply::NoError) {
		ui->confirmButton->setText(m_buttonText);
        QMessageBox::critical(this, windowTitle(),
            tr("Error making request: ") + reply->errorString(),
                QMessageBox::Ok, QMessageBox::Ok);
		return;
	}
	double valueAmount = 0;
	QString time;
	int height;

	QByteArray bytes = reply->readAll();
	QString str = QString::fromUtf8(bytes.data(), bytes.size());
	UniValue outerValue;
	bool read = outerValue.read(str.toStdString());
	if (read)
	{
		UniValue outerObj = outerValue.get_obj();
		UniValue statusValue = find_value(outerObj, "status");
		if (statusValue.isStr())
		{
			if(statusValue.get_str() != "success")
			{
				ui->confirmButton->setText(m_buttonText);
				QMessageBox::critical(this, windowTitle(),
					tr("Transaction status not successful: ") + QString::fromStdString(statusValue.get_str()),
						QMessageBox::Ok, QMessageBox::Ok);
				return;
			}
		}
		UniValue dataObj = find_value(outerObj, "data");
		UniValue heightValue = find_value(dataObj, "block");
		if (heightValue.isNum())
			height = heightValue.get_int();
		UniValue timeValue = find_value(dataObj, "time_utc");
		if (timeValue.isStr())
			time = QString::fromStdString(timeValue.get_str());
		UniValue outputsValue = find_value(dataObj, "vouts");
		if (outputsValue.isArray())
		{
			UniValue outputs = outputsValue.get_array();
			for (unsigned int idx = 0; idx < outputs.size(); idx++) {
				const UniValue& output = outputs[idx];
				UniValue addressValue = find_value(output, "address");
				if(addressValue.isStr())
				{
					qDebug() << "address";
					if(addressValue.get_str() == address.toStdString())
					{
						qDebug() << address;
						UniValue paymentValue = find_value(output, "amount");
						qDebug() << "payment";
						if(paymentValue.isStr())
						{
							qDebug() << QString::fromStdString(paymentValue.get_str());
							valueAmount += QString::fromStdString(paymentValue.get_str()).toDouble();
							qDebug() << "valueAmount";
							qDebug() << valueAmount;
							if(valueAmount >= dblPrice)
							{
								ui->confirmButton->setText(m_buttonText);
								QMessageBox::information(this, windowTitle(),
									tr("Transaction ID %1 was found in the Bitcoin blockchain! Full payment has been detected in block %2 at %3. It is recommended that you confirm payment by opening your Bitcoin wallet and seeing the funds in your account.").arg(ui->btctxidEdit->text().trimmed()).arg(height).arg(time),
									QMessageBox::Ok, QMessageBox::Ok);
								acceptOffer();
								return;
							}
						}
					}

				}
			}
		}
	}
	else
	{
		ui->confirmButton->setText(m_buttonText);
		QMessageBox::critical(this, windowTitle(),
			tr("Cannot parse JSON response: ") + str,
				QMessageBox::Ok, QMessageBox::Ok);
		return;
	}

	reply->deleteLater();
	ui->confirmButton->setText(m_buttonText);
	QMessageBox::warning(this, windowTitle(),
		tr("Payment not found in the Bitcoin blockchain! Please try again later."),
			QMessageBox::Ok, QMessageBox::Ok);
}
void OfferAcceptDialogBTC::CheckPaymentInBTC()
{
	m_buttonText = ui->confirmButton->text();
	ui->confirmButton->setText(tr("Please Wait..."));
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	connect(nam, SIGNAL(finished(QNetworkReply *)), this, SLOT(slotConfirmedFinished(QNetworkReply *)));
	QUrl url("http://btc.blockr.io/api/v1/tx/info/" + ui->btctxidEdit->text().trimmed());
	QNetworkRequest request(url);
	nam->get(request);
}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::tryAcceptOffer()
{
	if (ui->btctxidEdit->text().trimmed().isEmpty()) {
        ui->btctxidEdit->setText("");
        QMessageBox::critical(this, windowTitle(),
        tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
            QMessageBox::Ok, QMessageBox::Ok);
        return;
    }
	CheckPaymentInBTC();
}
void OfferAcceptDialogBTC::acceptOffer(){
		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().trimmed().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<commit_msg>fix paymment msg for buyer<commit_after>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#include <QDebug>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC to %5 using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice).arg(address));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(tryAcceptOffer()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::slotConfirmedFinished(QNetworkReply * reply){
	if(reply->error() != QNetworkReply::NoError) {
		ui->confirmButton->setText(m_buttonText);
        QMessageBox::critical(this, windowTitle(),
            tr("Error making request: ") + reply->errorString(),
                QMessageBox::Ok, QMessageBox::Ok);
		return;
	}
	double valueAmount = 0;
	QString time;
	int height;

	QByteArray bytes = reply->readAll();
	QString str = QString::fromUtf8(bytes.data(), bytes.size());
	UniValue outerValue;
	bool read = outerValue.read(str.toStdString());
	if (read)
	{
		UniValue outerObj = outerValue.get_obj();
		UniValue statusValue = find_value(outerObj, "status");
		if (statusValue.isStr())
		{
			if(statusValue.get_str() != "success")
			{
				ui->confirmButton->setText(m_buttonText);
				QMessageBox::critical(this, windowTitle(),
					tr("Transaction status not successful: ") + QString::fromStdString(statusValue.get_str()),
						QMessageBox::Ok, QMessageBox::Ok);
				return;
			}
		}
		UniValue dataObj = find_value(outerObj, "data");
		UniValue heightValue = find_value(dataObj, "block");
		if (heightValue.isNum())
			height = heightValue.get_int();
		UniValue timeValue = find_value(dataObj, "time_utc");
		if (timeValue.isStr())
			time = QString::fromStdString(timeValue.get_str());
		UniValue outputsValue = find_value(dataObj, "vouts");
		if (outputsValue.isArray())
		{
			UniValue outputs = outputsValue.get_array();
			for (unsigned int idx = 0; idx < outputs.size(); idx++) {
				const UniValue& output = outputs[idx];
				UniValue addressValue = find_value(output, "address");
				if(addressValue.isStr())
				{
					qDebug() << "address";
					if(addressValue.get_str() == address.toStdString())
					{
						qDebug() << address;
						UniValue paymentValue = find_value(output, "amount");
						qDebug() << "payment";
						if(paymentValue.isStr())
						{
							qDebug() << QString::fromStdString(paymentValue.get_str());
							valueAmount += QString::fromStdString(paymentValue.get_str()).toDouble();
							qDebug() << "valueAmount";
							qDebug() << valueAmount;
							if(valueAmount >= dblPrice)
							{
								ui->confirmButton->setText(m_buttonText);
								QMessageBox::information(this, windowTitle(),
									tr("Transaction ID %1 was found in the Bitcoin blockchain! Full payment has been detected in block %2 at %3.").arg(ui->btctxidEdit->text().trimmed()).arg(height).arg(time),
									QMessageBox::Ok, QMessageBox::Ok);
								acceptOffer();
								return;
							}
						}
					}

				}
			}
		}
	}
	else
	{
		ui->confirmButton->setText(m_buttonText);
		QMessageBox::critical(this, windowTitle(),
			tr("Cannot parse JSON response: ") + str,
				QMessageBox::Ok, QMessageBox::Ok);
		return;
	}

	reply->deleteLater();
	ui->confirmButton->setText(m_buttonText);
	QMessageBox::warning(this, windowTitle(),
		tr("Payment not found in the Bitcoin blockchain! Please try again later."),
			QMessageBox::Ok, QMessageBox::Ok);
}
void OfferAcceptDialogBTC::CheckPaymentInBTC()
{
	m_buttonText = ui->confirmButton->text();
	ui->confirmButton->setText(tr("Please Wait..."));
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	connect(nam, SIGNAL(finished(QNetworkReply *)), this, SLOT(slotConfirmedFinished(QNetworkReply *)));
	QUrl url("http://btc.blockr.io/api/v1/tx/info/" + ui->btctxidEdit->text().trimmed());
	QNetworkRequest request(url);
	nam->get(request);
}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::tryAcceptOffer()
{
	if (ui->btctxidEdit->text().trimmed().isEmpty()) {
        ui->btctxidEdit->setText("");
        QMessageBox::critical(this, windowTitle(),
        tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
            QMessageBox::Ok, QMessageBox::Ok);
        return;
    }
	CheckPaymentInBTC();
}
void OfferAcceptDialogBTC::acceptOffer(){
		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().trimmed().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace.";
	SendCoinsRecipient info;
	info.address = this->address;
	info.label = this->sellerAlias;
	info.message = message;
	ParseMoney(price.toStdString(), info.amount);
	QString uri = GUIUtil::formatBitcoinURI(info);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<|endoftext|>


<commit_before>#include "nico-live-timer.hpp"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>

NicoLiveTimer::NicoLiveTimer(
    std::function<std::chrono::milliseconds(void)> callable,
    std::chrono::milliseconds minInterval)
    : callable(callable), minInterval(minInterval), active(false), loopId(0),
      alive(std::make_shared<bool>(true))
{
}

NicoLiveTimer::~NicoLiveTimer()
{
	Stop();
	if (this->loopThread.joinable()) this->loopThread.detach();
	*this->alive = false;
	this->alive.reset();
}
void NicoLiveTimer::Start()
{
	std::lock_guard<std::mutex> lock(this->loopMutex);
	if (IsActive()) return;
	this->loopId++;
	int currentLoopId = this->loopId;
	this->active = true;
	if (this->loopThread.joinable()) this->loopThread.detach();
	this->loopThread = std::thread(Loop, currentLoopId, this);
}
void NicoLiveTimer::Stop()
{
	std::lock_guard<std::mutex> lock(this->loopMutex);
	this->active = false;
}
bool NicoLiveTimer::IsActive() const { return this->active; }

void NicoLiveTimer::Loop(int id, NicoLiveTimer *timer)
{
	std::shared_ptr<bool> timerAlive = timer->alive;
	while (*timerAlive && timer->IsActive() && id == timer->loopId) {
		auto interval_time = timer->callable();
		std::this_thread::sleep_for(
		    std::min(timer->minInterval, interval_time));
	}
	timerAlive.reset();
}
<commit_msg>常に最小になっていた。<commit_after>#include "nico-live-timer.hpp"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>

NicoLiveTimer::NicoLiveTimer(
    std::function<std::chrono::milliseconds(void)> callable,
    std::chrono::milliseconds minInterval)
    : callable(callable), minInterval(minInterval), active(false), loopId(0),
      alive(std::make_shared<bool>(true))
{
}

NicoLiveTimer::~NicoLiveTimer()
{
	Stop();
	if (this->loopThread.joinable()) this->loopThread.detach();
	*this->alive = false;
	this->alive.reset();
}
void NicoLiveTimer::Start()
{
	std::lock_guard<std::mutex> lock(this->loopMutex);
	if (IsActive()) return;
	this->loopId++;
	int currentLoopId = this->loopId;
	this->active = true;
	if (this->loopThread.joinable()) this->loopThread.detach();
	this->loopThread = std::thread(Loop, currentLoopId, this);
}
void NicoLiveTimer::Stop()
{
	std::lock_guard<std::mutex> lock(this->loopMutex);
	this->active = false;
}
bool NicoLiveTimer::IsActive() const { return this->active; }

void NicoLiveTimer::Loop(int id, NicoLiveTimer *timer)
{
	std::shared_ptr<bool> timerAlive = timer->alive;
	while (*timerAlive && timer->IsActive() && id == timer->loopId) {
		auto interval_time = timer->callable();
		std::this_thread::sleep_for(
		    std::max(timer->minInterval, interval_time));
	}
	timerAlive.reset();
}
<|endoftext|>


<commit_before><commit_msg>demos/painter_path_test: can cycle through stroking and filling anti-alias modes seperately<commit_after><|endoftext|>


<commit_before>#include "NoteArranger.h"

using namespace std;

void NoteArranger::arrange(Score *score)
{
  for (list<Note>::iterator it_notes=score->notes.begin(); it_notes!=score->notes.end(); ++it_notes) {
    vector<short> velocities;
    if (it_notes->getVelocityPointNum()>0 || (velocities=it_notes->getVelocities()).size()==0)
      continue;

    unsigned short range = (velocities.size()-1) / 2;
    unsigned short ms_front_edge=nak::ms_front_edge, ms_back_edge=nak::ms_back_edge;
    if (it_notes!=score->notes.begin() && boost::prior(it_notes)->getEnd()==it_notes->getStart() && it_notes->getOvrl()>0)
      ms_front_edge = it_notes->getOvrl();
    if (it_notes!=--score->notes.end() && boost::next(it_notes)->getStart()==it_notes->getEnd() && boost::next(it_notes)->getOvrl()>0)
      ms_back_edge = boost::next(it_notes)->getOvrl();

    it_notes->addVelocityPoint(0, 0);
    it_notes->addVelocityPoint(ms_front_edge, it_notes->getBaseVelocity());
    it_notes->addVelocityPoint(-ms_back_edge, it_notes->getBaseVelocity());
    it_notes->addVelocityPoint(-1, 0);
  }
}
<commit_msg>change arrange method<commit_after>#include "NoteArranger.h"

using namespace std;

void NoteArranger::arrange(Score *score)
{
  for (list<Note>::iterator it_notes=score->notes.begin(); it_notes!=score->notes.end(); ++it_notes) {
    vector<short> velocities;
    if (it_notes->getVelocityPointNum() > 0)
      continue;

    unsigned short range = (velocities.size()-1) / 2;
    unsigned short ms_front_edge=nak::ms_front_edge, ms_back_edge=nak::ms_back_edge;

    it_notes->addVelocityPoint(0, 0);
    it_notes->addVelocityPoint(ms_front_edge, it_notes->getBaseVelocity());
    it_notes->addVelocityPoint(-ms_back_edge, it_notes->getBaseVelocity());
    it_notes->addVelocityPoint(-1, 0);
  }
}
<|endoftext|>


<commit_before>
#include "MainWidget1.h"
#include <QApplication>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>

#include "stbtest.h"

namespace fs = std::filesystem;

//export DISPLAY=localhost:10.0

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    MainWidget1 w;
    w.show();
    std::cout << fs::current_path().c_str() << std::endl;
    return app.exec();
}
<commit_msg>linux cpp qt5 fix win remove stbtest.h<commit_after>
#include "MainWidget1.h"
#include <QApplication>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>

// #include "stbtest.h"

namespace fs = std::filesystem;

//export DISPLAY=localhost:10.0

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    MainWidget1 w;
    w.show();
    std::cout << fs::current_path().c_str() << std::endl;
    return app.exec();
}
<|endoftext|>


<commit_before><commit_msg>Focus on scene name when creating new scene<commit_after><|endoftext|>


<commit_before>#include "ethernet_monitor.h"
#include "net\inet_headers.h"
#include "net\parser_states.h"
#include "application\application.h"

#define TIMEOUT_SEND	10
#define MAXIMUM_SEND	5

EthernetMonitor::EthernetMonitor(pcap_t *fp, const std::string& mac)
	: m_fp(fp), m_mac(mac), m_timeoutCount(TIMEOUT_SEND), m_currentPADISend(0)
{
	ManagersContainer::GetInstance().AddManager(static_cast<IManager*>(this));
}

EthernetMonitor::~EthernetMonitor()
{
}

void EthernetMonitor::ManagerStart()
{
	if(!m_fp)
	{
		return;
	}

	bpf_program fcode;
	int res = pcap_compile(m_fp, &fcode, "pppoed or pppoes", 1, 0xffffff);
    res = pcap_setfilter(m_fp, &fcode);
}

void EthernetMonitor::ManagerFunc()
{
	if(!m_fp)
	{
		return;
	}

	//send PADI request with timeout
	if(m_currentPADISend < MAXIMUM_SEND && ++m_timeoutCount >= TIMEOUT_SEND)
	{
		int len = 0;
		unsigned char* data = 0;
		//Send PADI
		PPPoEDContainer padi(m_mac, "ff:ff:ff:ff:ff:ff", PPPOE_PADI);
		padi.deserialize(0, len);
		data = new unsigned char[len];
		if(padi.deserialize((char*)data, len))
		{
			pcap_sendpacket(m_fp, data, len);
		}
		delete data;
		data = 0;
		m_timeoutCount = 0;
		m_currentPADISend++;
	}

	//get inet data
	pcap_pkthdr* header;
	const unsigned char* inetdata = 0;
	if (pcap_next_ex(m_fp, &header, &inetdata) < 0)
	{
		Stop();
		return;
	}
	if(!inetdata)
	{
		return;
	}

	BasicState state(this);
	BasicState *nextState = &state;
	while(nextState)
	{
		nextState = nextState->NextState((char*)inetdata, header->len);
	}
}

void EthernetMonitor::ManagerStop()
{
	if(!m_fp)
	{
		return;
	}

	int len = 0;
	PPPoEDContainer padt(m_mac, ETHER_BROADCAST, PPPOE_PADT);
	padt.deserialize(0, len);
	unsigned char *data = new unsigned char[len];
	if(padt.deserialize((char*)data, len))
	{
		pcap_sendpacket(m_fp, data, len);
	}
	delete data;
	data = 0;

	pcap_close(m_fp);
	m_fp = 0;
}

void EthernetMonitor::OnPacket(const PPPoEDContainer& container)
{
	if(!m_fp || const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_VS] != PPPOED_DEFAULT_VENDOR)
		return;

	if (_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), ETHER_BROADCAST) == 0 &&
		_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost).c_str(), m_mac.c_str()) != 0)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost));

		switch(container.m_pppoeHeader.code)
		{
			case PPPOE_PADI:
			{
				if(!Application::GetInstance().AddContact(addr))
					break;

				int len = 0;
				PPPoEDContainer pado(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADO);
				pado.deserialize(0, len);
				unsigned char *data = new unsigned char[len];
				if(pado.deserialize((char*)data, len))
				{
					pcap_sendpacket(m_fp, data, len);
				}
				delete data;
				data = 0;

				break;
			}
			case PPPOE_PADT:
			{
				Application::GetInstance().RemoveContact(addr);
				break;
			}
		}
	}
	else if(_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), ETHER_BROADCAST) != 0 &&
			_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost).c_str(), m_mac.c_str()) != 0 &&
			container.m_pppoeHeader.code == PPPOE_PADR)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), rand());
		if(Application::GetInstance().GetContact(addr.m_hostId).m_sessionId != 0)
			return;

		int len = 0;
		PPPoEDContainer pads(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADS);
		pads.m_pppoeHeader.sessionId = addr.m_sessionId;
		pads.deserialize(0, len);
		unsigned char *data = new unsigned char[len];
		if(pads.deserialize((char*)data, len))
		{
			pcap_sendpacket(m_fp, data, len);
		}
		delete data;
		data = 0;

		Application::GetInstance().UpdateContact(addr);
	}
	else if(_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), m_mac.c_str()) == 0)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost),
						container.m_pppoeHeader.sessionId);

		switch(container.m_pppoeHeader.code)
		{
			case PPPOE_PADO:
			{
				if(!Application::GetInstance().AddContact(addr) &&
					( Application::GetInstance().GetContact(addr.m_hostId).m_sessionId != 0||
					addr.m_hostId < getCpuHash()))
					break;

				int len = 0;
				PPPoEDContainer padr(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADR);
				padr.deserialize(0, len);
				unsigned char *data = new unsigned char[len];
				if(padr.deserialize((char*)data, len))
				{
					pcap_sendpacket(m_fp, data, len);
				}
				delete data;
				data = 0;

				break;
			}
			case PPPOE_PADS:
			{
				Application::GetInstance().UpdateContact(addr);
				break;
			}
		}
	}
}
<commit_msg>little fix<commit_after>#include "ethernet_monitor.h"
#include "net\inet_headers.h"
#include "net\parser_states.h"
#include "application\application.h"

#define TIMEOUT_SEND	10
#define MAXIMUM_SEND	5

EthernetMonitor::EthernetMonitor(pcap_t *fp, const std::string& mac)
	: m_fp(fp), m_mac(mac), m_timeoutCount(TIMEOUT_SEND), m_currentPADISend(0)
{
	ManagersContainer::GetInstance().AddManager(static_cast<IManager*>(this));
}

EthernetMonitor::~EthernetMonitor()
{
}

void EthernetMonitor::ManagerStart()
{
	if(!m_fp)
	{
		return;
	}

	bpf_program fcode;
	int res = pcap_compile(m_fp, &fcode, "pppoed or pppoes", 1, 0xffffff);
    res = pcap_setfilter(m_fp, &fcode);
}

void EthernetMonitor::ManagerFunc()
{
	if(!m_fp)
	{
		return;
	}

	//send PADI request with timeout
	if(m_currentPADISend < MAXIMUM_SEND && ++m_timeoutCount >= TIMEOUT_SEND)
	{
		int len = 0;
		unsigned char* data = 0;
		//Send PADI
		PPPoEDContainer padi(m_mac, ETHER_BROADCAST, PPPOE_PADI);
		padi.deserialize(0, len);
		data = new unsigned char[len];
		if(padi.deserialize((char*)data, len))
		{
			pcap_sendpacket(m_fp, data, len);
		}
		delete data;
		data = 0;
		m_timeoutCount = 0;
		m_currentPADISend++;
	}

	//get inet data
	pcap_pkthdr* header;
	const unsigned char* inetdata = 0;
	if (pcap_next_ex(m_fp, &header, &inetdata) < 0)
	{
		Stop();
		return;
	}
	if(!inetdata)
	{
		return;
	}

	BasicState state(this);
	BasicState *nextState = &state;
	while(nextState)
	{
		nextState = nextState->NextState((char*)inetdata, header->len);
	}
}

void EthernetMonitor::ManagerStop()
{
	if(!m_fp)
	{
		return;
	}

	int len = 0;
	PPPoEDContainer padt(m_mac, ETHER_BROADCAST, PPPOE_PADT);
	padt.deserialize(0, len);
	unsigned char *data = new unsigned char[len];
	if(padt.deserialize((char*)data, len))
	{
		pcap_sendpacket(m_fp, data, len);
	}
	delete data;
	data = 0;

	pcap_close(m_fp);
	m_fp = 0;
}

void EthernetMonitor::OnPacket(const PPPoEDContainer& container)
{
	if(!m_fp || const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_VS] != PPPOED_DEFAULT_VENDOR)
		return;

	if (_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), ETHER_BROADCAST) == 0 &&
		_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost).c_str(), m_mac.c_str()) != 0)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost));

		switch(container.m_pppoeHeader.code)
		{
			case PPPOE_PADI:
			{
				if(!Application::GetInstance().AddContact(addr))
					break;

				int len = 0;
				PPPoEDContainer pado(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADO);
				pado.deserialize(0, len);
				unsigned char *data = new unsigned char[len];
				if(pado.deserialize((char*)data, len))
				{
					pcap_sendpacket(m_fp, data, len);
				}
				delete data;
				data = 0;

				break;
			}
			case PPPOE_PADT:
			{
				Application::GetInstance().RemoveContact(addr);
				break;
			}
		}
	}
	else if(_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), ETHER_BROADCAST) != 0 &&
			_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost).c_str(), m_mac.c_str()) != 0 &&
			container.m_pppoeHeader.code == PPPOE_PADR)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), rand());
		if(Application::GetInstance().GetContact(addr.m_hostId).m_sessionId != 0)
			return;

		int len = 0;
		PPPoEDContainer pads(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADS);
		pads.m_pppoeHeader.sessionId = addr.m_sessionId;
		pads.deserialize(0, len);
		unsigned char *data = new unsigned char[len];
		if(pads.deserialize((char*)data, len))
		{
			pcap_sendpacket(m_fp, data, len);
		}
		delete data;
		data = 0;

		Application::GetInstance().UpdateContact(addr);
	}
	else if(_stricmp(EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_dhost).c_str(), m_mac.c_str()) == 0)
	{
		HostAddress addr((unsigned short)const_cast<PPPoEDContainer&>(container).m_tags[PPPOED_HU].c_str(),
						EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost),
						container.m_pppoeHeader.sessionId);

		switch(container.m_pppoeHeader.code)
		{
			case PPPOE_PADO:
			{
				if(!Application::GetInstance().AddContact(addr) &&
					( Application::GetInstance().GetContact(addr.m_hostId).m_sessionId != 0||
					addr.m_hostId < getCpuHash()))
					break;

				int len = 0;
				PPPoEDContainer padr(m_mac, EtherNetContainer::MacToString((char*)container.m_ethHeader.ether_shost), PPPOE_PADR);
				padr.deserialize(0, len);
				unsigned char *data = new unsigned char[len];
				if(padr.deserialize((char*)data, len))
				{
					pcap_sendpacket(m_fp, data, len);
				}
				delete data;
				data = 0;

				break;
			}
			case PPPOE_PADS:
			{
				Application::GetInstance().UpdateContact(addr);
				break;
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * SessionDependencies.cpp
 *
 * Copyright (C) 2009-19 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionDependencies.hpp"

#include <boost/bind.hpp>
#include <boost/algorithm/string/join.hpp>

#include <shared_core/Error.hpp>
#include <core/Exec.hpp>
#include <core/system/Environment.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/session/RSessionUtils.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionConsoleProcess.hpp>
#include <session/projects/SessionProjects.hpp>
#include <session/prefs/UserPrefs.hpp>

#include "jobs/ScriptJob.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {

namespace {

struct EmbeddedPackage
{
   bool empty() const { return archivePath.empty(); }

   std::string name;
   std::string version;
   std::string sha1;
   std::string archivePath;
};

EmbeddedPackage embeddedPackageInfo(const std::string& name)
{
   // determine location of archives
   FilePath archivesDir = session::options().sessionPackageArchivesPath();
   std::vector<FilePath> children;
   Error error = archivesDir.getChildren(children);
   if (error)
   {
      LOG_ERROR(error);
      return EmbeddedPackage();
   }

   // we saw the regex with explicit character class ranges fail to match
   // on a windows 8.1 system so we are falling back to a simpler regex
   //
   // (note see below for another approach involving setting the locale
   // of the regex directly -- this assumes that the matching issue is
   // somehow related to locales)
   boost::regex re(name + "_([^_]+)_([^\\.]+)\\.tar\\.gz");

   /* another approach (which we didn't try) based on setting the regex locale
   boost::regex re;
   re.imbue(std::locale("en_US.UTF-8"));
   re.assign(name + "_([0-9]+\\.[0-9]+\\.[0-9]+)_([\\d\\w]+)\\.tar\\.gz");
   */

   for (const FilePath& child : children)
   {
      boost::smatch match;
      std::string filename = child.getFilename();
      if (regex_utils::match(filename, match, re))
      {
         EmbeddedPackage pkg;
         pkg.name = name;
         pkg.version = match[1];
         pkg.sha1 = match[2];
         pkg.archivePath = string_utils::utf8ToSystem(child.getAbsolutePath());
         return pkg;
      }
   }

   // none found
   return EmbeddedPackage();
}

} // anonymous namespace

namespace modules {
namespace dependencies {

namespace {

#define kCRANPackageDependency "cran"
#define kEmbeddedPackageDependency "embedded"

struct Dependency
{
   Dependency() :
      location(kCRANPackageDependency),
      source(false),
      versionSatisfied(true) {}

   bool empty() const { return name.empty(); }

   std::string location;
   std::string name;
   std::string version;
   bool source;
   std::string availableVersion;
   bool versionSatisfied;
};

std::string nameFromDep(const Dependency& dep)
{
   return dep.name;
}

std::vector<std::string> packageNames(const std::vector<Dependency> deps)
{
   std::vector<std::string> names;
   std::transform(deps.begin(),
                  deps.end(),
                  std::back_inserter(names),
                  nameFromDep);
   return names;
}

std::vector<Dependency> dependenciesFromJson(const json::Array& depsJson)
{
   std::vector<Dependency> deps;
   for (const json::Value& depJsonValue : depsJson)
   {
      if (json::isType<json::Object>(depJsonValue))
      {
         Dependency dep;
         const json::Object& depJson = depJsonValue.getObject();
         Error error = json::readObject(depJson,
                                        "location", &(dep.location),
                                        "name", &(dep.name),
                                        "version", &(dep.version),
                                        "source", &(dep.source));
         if (!error)
         {
            deps.push_back(dep);
         }
         else
         {
            LOG_ERROR(error);
         }
      }
   }
   return deps;
}

json::Array dependenciesToJson(const std::vector<Dependency>& deps)
{
   json::Array depsJson;
   for (const Dependency& dep : deps)
   {
      json::Object depJson;
      depJson["location"] = dep.location;
      depJson["name"] = dep.name;
      depJson["version"] = dep.version;
      depJson["source"] = dep.source;
      depJson["available_version"] = dep.availableVersion;
      depJson["version_satisfied"] = dep.versionSatisfied;
      depsJson.push_back(depJson);
   }
   return depsJson;
}

bool embeddedPackageRequiresUpdate(const EmbeddedPackage& pkg)
{
   // if this package came from the rstudio ide then check if it needs
   // an update (i.e. has a different SHA1)
   r::exec::RFunction func(".rs.rstudioIDEPackageRequiresUpdate",
                           pkg.name, pkg.sha1);
   bool requiresUpdate = false;
   Error error = func.call(&requiresUpdate);
   if (error)
      LOG_ERROR(error);

   return requiresUpdate;
}

void silentUpdateEmbeddedPackage(const EmbeddedPackage& pkg)
{
   // suppress output which occurs during silent update
   r::session::utils::SuppressOutputInScope suppressOutput;

   Error error = r::exec::RFunction(".rs.updateRStudioIDEPackage",
                             pkg.name, pkg.archivePath).call();
   if (error)
      LOG_ERROR(error);
}

Error unsatisfiedDependencies(const json::JsonRpcRequest& request,
                              json::JsonRpcResponse* pResponse)
{
   // get list of dependencies and silentUpdate flag
   json::Array depsJson;
   bool silentUpdate;
   Error error = json::readParams(request.params, &depsJson, &silentUpdate);
   if (error)
      return error;
   std::vector<Dependency> deps = dependenciesFromJson(depsJson);

   // build the list of unsatisifed dependencies
   using namespace module_context;
   std::vector<Dependency> unsatisfiedDeps;
   for (Dependency& dep : deps)
   {
      if (dep.location == kCRANPackageDependency)
      {
         if (!isPackageVersionInstalled(dep.name, dep.version))
         {
            // presume package is available unless we can demonstrate otherwise
            // (we don't want to block installation attempt unless we're
            // reasonably confident it will not result in a viable version)
            r::sexp::Protect protect;
            SEXP versionInfo = R_NilValue;

            // find the version that will be installed from CRAN
            error = r::exec::RFunction(".rs.packageCRANVersionAvailable",
                  dep.name, dep.version, dep.source).call(&versionInfo, &protect);
            if (error) {
               LOG_ERROR(error);
            } else {
               // if these fail, we'll fall back on defaults set above
               r::sexp::getNamedListElement(versionInfo, "version",
                     &dep.availableVersion);
               r::sexp::getNamedListElement(versionInfo, "satisfied",
                     &dep.versionSatisfied);
            }

            unsatisfiedDeps.push_back(dep);
         }
      }
      else if (dep.location == kEmbeddedPackageDependency)
      {
         EmbeddedPackage pkg = embeddedPackageInfo(dep.name);

         // package isn't installed so report that it reqires installation
         if (!isPackageInstalled(dep.name))
         {
            unsatisfiedDeps.push_back(dep);
         }
         // silent update if necessary (as long as we aren't packified)
         else if (silentUpdate && !packratContext().packified)
         {
            // package installed was from IDE but is out of date
            if (embeddedPackageRequiresUpdate(pkg))
            {
               silentUpdateEmbeddedPackage(pkg);
            }
            // package installed wasn't from the IDE but is older than
            // the version we currently have embedded
            else if (!isPackageVersionInstalled(pkg.name, pkg.version))
            {
               silentUpdateEmbeddedPackage(pkg);
            }
            else
            {
               // the only remaining case is a newer version of the package is
               // already installed (e.g. directly from github). in this case
               // we do nothing
            }
         }
      }
   }

   // return unsatisfied dependencies
   pResponse->setResult(dependenciesToJson(unsatisfiedDeps));
   return Success();
}

Error installDependencies(const json::JsonRpcRequest& request,
                          json::JsonRpcResponse* pResponse)
{
   // get list of dependencies
   json::Array depsJson;
   std::string context;
   Error error = json::readParams(request.params, &context, &depsJson);
   if (error)
      return error;
   std::vector<Dependency> deps = dependenciesFromJson(depsJson);

   // Ensure we have a writeable user library
   error = r::exec::RFunction(".rs.ensureWriteableUserLibrary").call();
   if (error)
      return error;

   // force unload as necessary
   std::vector<std::string> names = packageNames(deps);
   error = r::exec::RFunction(".rs.forceUnloadForPackageInstall", names).call();
   if (error)
      LOG_ERROR(error);

   // Start script with all the CRAN download settings
   std::string script = module_context::CRANDownloadOptions() + "\n\n";

   // Emit a message to the user at the beginning of the script declaring what we're about to do
   if (deps.size() > 1)
   {
      script += "cat('** ";
      if (context.empty())
         script += "Installing R Packages: ";
      else
         script += "Installing R Package Dependencies for " + context + ": ";
      for (size_t i = 0; i < deps.size(); i++)
      {
         script += "\\'" + deps[i].name + "\\'";
         if (i < deps.size() - 1)
            script += ", ";
      }
      script += "\\n\\n')\n";
   }
   else
   {
      if (context.empty())
         script += "cat('Installing \\'" + deps[0].name + "\\' ...\\n\\n')\n";
      else
         script += "cat('Installing \\'" + deps[0].name + "\\' for " + context +
            "...\\n\\n')\n";
   }

   for (size_t i = 0; i < deps.size(); i++)
   {
      const Dependency& dep = deps[i];

      // Add a comment header with the name of the package. This will result in better progress
      // treatment, since comment headers are used to show the currently executing section of a
      // script.
      script += "# " + dep.name + " -------------\n\n";

      // If there's more than one dependency, indicate which one is being installed.
      if (deps.size() > 1)
      {
         script += "cat('\\n[" +
            safe_convert::numberToString(i + 1) +
            "/" +
            safe_convert::numberToString(deps.size()) +
            "] Installing " + dep.name + "...\\n\\n')\n";
      }

      if (dep.location == kCRANPackageDependency)
      {
         // Build install command for CRAN. We specify lock = TRUE (here and elsewhere) to ensure
         // that the package directory is locked during installation; since this will run in the
         // background we want reduce the odds of corruption via a competing package install attempt
         // in another process.
         script += "utils::install.packages('" + dep.name + "', " +
                "repos = '"+ module_context::CRANReposURL() + "'";

         if (dep.source)
         {
            // Install from source if requested
            script += ", type = 'source'";
         }

         script += ", lock = TRUE)";
      }
      else if (dep.location == kEmbeddedPackageDependency)
      {
         EmbeddedPackage pkg = embeddedPackageInfo(dep.name);

         // Build install command for bundled archive
         script += "utils::install.packages('" + pkg.archivePath +
            "', repos = NULL, type = 'source', lock = TRUE)";
      }

      script += "\n\n";
   }

   bool packrat = module_context::packratContext().modeOn;
   jobs::ScriptLaunchSpec installJob(
         // Supply job name; use context if we have one, otherwise auto-generate from dependency list
         context.empty() ?
            (deps.size() == 1 ?
                ("Install '" + deps[0].name + "'") :
                ("Install R packages")) :
            context + " Dependencies",

         // Script to run for job
         script,

         // Directory in which to run job
         packrat ?
            projects::projectContext().directory() :
            FilePath(),

         false, // Import environment
         "");

   // Run in a vanilla session if Packrat mode isn't on (prevents problematic startup scripts/etc
   // from causing install trouble)
   if (!packrat)
      installJob.setProcOptions(async_r::R_PROCESS_VANILLA);

   std::string jobId;
   error = jobs::startScriptJob(installJob, &jobId);

   // Return handle to script job
   pResponse->setResult(jobId);

   return Success();
}

} // anonymous namespace

Error initialize()
{
   // install handlers
   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "unsatisfied_dependencies", unsatisfiedDependencies))
      (bind(registerRpcMethod, "install_dependencies", installDependencies));
   return initBlock.execute();
}

} // namespace dependencies
} // namespace modules

namespace module_context {

Error installEmbeddedPackage(const std::string& name)
{
   EmbeddedPackage pkg = embeddedPackageInfo(name);
   return module_context::installPackage(pkg.archivePath);
}

} // anonymous namespace

} // namespace session
} // namespace rstudio

<commit_msg>emit message at end of package installation script<commit_after>/*
 * SessionDependencies.cpp
 *
 * Copyright (C) 2009-20 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionDependencies.hpp"

#include <boost/bind.hpp>
#include <boost/algorithm/string/join.hpp>

#include <shared_core/Error.hpp>
#include <core/Exec.hpp>
#include <core/system/Environment.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/session/RSessionUtils.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionConsoleProcess.hpp>
#include <session/projects/SessionProjects.hpp>
#include <session/prefs/UserPrefs.hpp>

#include "jobs/ScriptJob.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {

namespace {

struct EmbeddedPackage
{
   bool empty() const { return archivePath.empty(); }

   std::string name;
   std::string version;
   std::string sha1;
   std::string archivePath;
};

EmbeddedPackage embeddedPackageInfo(const std::string& name)
{
   // determine location of archives
   FilePath archivesDir = session::options().sessionPackageArchivesPath();
   std::vector<FilePath> children;
   Error error = archivesDir.getChildren(children);
   if (error)
   {
      LOG_ERROR(error);
      return EmbeddedPackage();
   }

   // we saw the regex with explicit character class ranges fail to match
   // on a windows 8.1 system so we are falling back to a simpler regex
   //
   // (note see below for another approach involving setting the locale
   // of the regex directly -- this assumes that the matching issue is
   // somehow related to locales)
   boost::regex re(name + "_([^_]+)_([^\\.]+)\\.tar\\.gz");

   /* another approach (which we didn't try) based on setting the regex locale
   boost::regex re;
   re.imbue(std::locale("en_US.UTF-8"));
   re.assign(name + "_([0-9]+\\.[0-9]+\\.[0-9]+)_([\\d\\w]+)\\.tar\\.gz");
   */

   for (const FilePath& child : children)
   {
      boost::smatch match;
      std::string filename = child.getFilename();
      if (regex_utils::match(filename, match, re))
      {
         EmbeddedPackage pkg;
         pkg.name = name;
         pkg.version = match[1];
         pkg.sha1 = match[2];
         pkg.archivePath = string_utils::utf8ToSystem(child.getAbsolutePath());
         return pkg;
      }
   }

   // none found
   return EmbeddedPackage();
}

} // anonymous namespace

namespace modules {
namespace dependencies {

namespace {

#define kCRANPackageDependency "cran"
#define kEmbeddedPackageDependency "embedded"

struct Dependency
{
   Dependency() :
      location(kCRANPackageDependency),
      source(false),
      versionSatisfied(true) {}

   bool empty() const { return name.empty(); }

   std::string location;
   std::string name;
   std::string version;
   bool source;
   std::string availableVersion;
   bool versionSatisfied;
};

std::string nameFromDep(const Dependency& dep)
{
   return dep.name;
}

std::vector<std::string> packageNames(const std::vector<Dependency> deps)
{
   std::vector<std::string> names;
   std::transform(deps.begin(),
                  deps.end(),
                  std::back_inserter(names),
                  nameFromDep);
   return names;
}

std::vector<Dependency> dependenciesFromJson(const json::Array& depsJson)
{
   std::vector<Dependency> deps;
   for (const json::Value& depJsonValue : depsJson)
   {
      if (json::isType<json::Object>(depJsonValue))
      {
         Dependency dep;
         const json::Object& depJson = depJsonValue.getObject();
         Error error = json::readObject(depJson,
                                        "location", &(dep.location),
                                        "name", &(dep.name),
                                        "version", &(dep.version),
                                        "source", &(dep.source));
         if (!error)
         {
            deps.push_back(dep);
         }
         else
         {
            LOG_ERROR(error);
         }
      }
   }
   return deps;
}

json::Array dependenciesToJson(const std::vector<Dependency>& deps)
{
   json::Array depsJson;
   for (const Dependency& dep : deps)
   {
      json::Object depJson;
      depJson["location"] = dep.location;
      depJson["name"] = dep.name;
      depJson["version"] = dep.version;
      depJson["source"] = dep.source;
      depJson["available_version"] = dep.availableVersion;
      depJson["version_satisfied"] = dep.versionSatisfied;
      depsJson.push_back(depJson);
   }
   return depsJson;
}

bool embeddedPackageRequiresUpdate(const EmbeddedPackage& pkg)
{
   // if this package came from the rstudio ide then check if it needs
   // an update (i.e. has a different SHA1)
   r::exec::RFunction func(".rs.rstudioIDEPackageRequiresUpdate",
                           pkg.name, pkg.sha1);
   bool requiresUpdate = false;
   Error error = func.call(&requiresUpdate);
   if (error)
      LOG_ERROR(error);

   return requiresUpdate;
}

void silentUpdateEmbeddedPackage(const EmbeddedPackage& pkg)
{
   // suppress output which occurs during silent update
   r::session::utils::SuppressOutputInScope suppressOutput;

   Error error = r::exec::RFunction(".rs.updateRStudioIDEPackage",
                             pkg.name, pkg.archivePath).call();
   if (error)
      LOG_ERROR(error);
}

Error unsatisfiedDependencies(const json::JsonRpcRequest& request,
                              json::JsonRpcResponse* pResponse)
{
   // get list of dependencies and silentUpdate flag
   json::Array depsJson;
   bool silentUpdate;
   Error error = json::readParams(request.params, &depsJson, &silentUpdate);
   if (error)
      return error;
   std::vector<Dependency> deps = dependenciesFromJson(depsJson);

   // build the list of unsatisifed dependencies
   using namespace module_context;
   std::vector<Dependency> unsatisfiedDeps;
   for (Dependency& dep : deps)
   {
      if (dep.location == kCRANPackageDependency)
      {
         if (!isPackageVersionInstalled(dep.name, dep.version))
         {
            // presume package is available unless we can demonstrate otherwise
            // (we don't want to block installation attempt unless we're
            // reasonably confident it will not result in a viable version)
            r::sexp::Protect protect;
            SEXP versionInfo = R_NilValue;

            // find the version that will be installed from CRAN
            error = r::exec::RFunction(".rs.packageCRANVersionAvailable",
                  dep.name, dep.version, dep.source).call(&versionInfo, &protect);
            if (error) {
               LOG_ERROR(error);
            } else {
               // if these fail, we'll fall back on defaults set above
               r::sexp::getNamedListElement(versionInfo, "version",
                     &dep.availableVersion);
               r::sexp::getNamedListElement(versionInfo, "satisfied",
                     &dep.versionSatisfied);
            }

            unsatisfiedDeps.push_back(dep);
         }
      }
      else if (dep.location == kEmbeddedPackageDependency)
      {
         EmbeddedPackage pkg = embeddedPackageInfo(dep.name);

         // package isn't installed so report that it reqires installation
         if (!isPackageInstalled(dep.name))
         {
            unsatisfiedDeps.push_back(dep);
         }
         // silent update if necessary (as long as we aren't packified)
         else if (silentUpdate && !packratContext().packified)
         {
            // package installed was from IDE but is out of date
            if (embeddedPackageRequiresUpdate(pkg))
            {
               silentUpdateEmbeddedPackage(pkg);
            }
            // package installed wasn't from the IDE but is older than
            // the version we currently have embedded
            else if (!isPackageVersionInstalled(pkg.name, pkg.version))
            {
               silentUpdateEmbeddedPackage(pkg);
            }
            else
            {
               // the only remaining case is a newer version of the package is
               // already installed (e.g. directly from github). in this case
               // we do nothing
            }
         }
      }
   }

   // return unsatisfied dependencies
   pResponse->setResult(dependenciesToJson(unsatisfiedDeps));
   return Success();
}

Error installDependencies(const json::JsonRpcRequest& request,
                          json::JsonRpcResponse* pResponse)
{
   // get list of dependencies
   json::Array depsJson;
   std::string context;
   Error error = json::readParams(request.params, &context, &depsJson);
   if (error)
      return error;
   std::vector<Dependency> deps = dependenciesFromJson(depsJson);

   // Ensure we have a writeable user library
   error = r::exec::RFunction(".rs.ensureWriteableUserLibrary").call();
   if (error)
      return error;

   // force unload as necessary
   std::vector<std::string> names = packageNames(deps);
   error = r::exec::RFunction(".rs.forceUnloadForPackageInstall", names).call();
   if (error)
      LOG_ERROR(error);

   // Start script with all the CRAN download settings
   std::string script = module_context::CRANDownloadOptions() + "\n\n";

   // Emit a message to the user at the beginning of the script declaring what we're about to do
   if (deps.size() > 1)
   {
      script += "cat('** ";
      if (context.empty())
         script += "Installing R Packages: ";
      else
         script += "Installing R Package Dependencies for " + context + ": ";
      for (size_t i = 0; i < deps.size(); i++)
      {
         script += "\\'" + deps[i].name + "\\'";
         if (i < deps.size() - 1)
            script += ", ";
      }
      script += "\\n\\n')\n";
   }
   else
   {
      if (context.empty())
         script += "cat('Installing \\'" + deps[0].name + "\\' ...\\n\\n')\n";
      else
         script += "cat('Installing \\'" + deps[0].name + "\\' for " + context +
            "...\\n\\n')\n";
   }

   for (size_t i = 0; i < deps.size(); i++)
   {
      const Dependency& dep = deps[i];

      // Add a comment header with the name of the package. This will result in better progress
      // treatment, since comment headers are used to show the currently executing section of a
      // script.
      script += "# " + dep.name + " -------------\n\n";

      // If there's more than one dependency, indicate which one is being installed.
      if (deps.size() > 1)
      {
         script += "cat('\\n\\n[" +
            safe_convert::numberToString(i + 1) +
            "/" +
            safe_convert::numberToString(deps.size()) +
            "] Installing " + dep.name + "...\\n\\n')\n";
      }

      if (dep.location == kCRANPackageDependency)
      {
         // Build install command for CRAN. We specify lock = TRUE (here and elsewhere) to ensure
         // that the package directory is locked during installation; since this will run in the
         // background we want reduce the odds of corruption via a competing package install attempt
         // in another process.
         script += "utils::install.packages('" + dep.name + "', " +
                "repos = '"+ module_context::CRANReposURL() + "'";

         if (dep.source)
         {
            // Install from source if requested
            script += ", type = 'source'";
         }

         script += ", lock = TRUE)";
      }
      else if (dep.location == kEmbeddedPackageDependency)
      {
         EmbeddedPackage pkg = embeddedPackageInfo(dep.name);

         // Build install command for bundled archive
         script += "utils::install.packages('" + pkg.archivePath +
            "', repos = NULL, type = 'source', lock = TRUE)";
      }

      script += "\n\n";
   }

   // Emit a message indicating that we're done. The script aborts on error, so if we get here we
   // can presume everything installed successfully.
   script += "message('\\n\\n\\u2714 ";  // Heavy checkmark
   if (deps.size() < 2)
      script += "Package install completed.";
   else
      script += safe_convert::numberToString(deps.size()) + " packages installed.";
   script += "')\n\n";

   bool packrat = module_context::packratContext().modeOn;
   jobs::ScriptLaunchSpec installJob(
         // Supply job name; use context if we have one, otherwise auto-generate from dependency list
         context.empty() ?
            (deps.size() == 1 ?
                ("Install '" + deps[0].name + "'") :
                ("Install R packages")) :
            context + " Dependencies",

         // Script to run for job
         script,

         // Directory in which to run job
         packrat ?
            projects::projectContext().directory() :
            FilePath(),

         false, // Import environment
         "");

   // Run in a vanilla session if Packrat mode isn't on (prevents problematic startup scripts/etc
   // from causing install trouble)
   if (!packrat)
      installJob.setProcOptions(async_r::R_PROCESS_VANILLA);

   std::string jobId;
   error = jobs::startScriptJob(installJob, &jobId);

   // Return handle to script job
   pResponse->setResult(jobId);

   return Success();
}

} // anonymous namespace

Error initialize()
{
   // install handlers
   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "unsatisfied_dependencies", unsatisfiedDependencies))
      (bind(registerRpcMethod, "install_dependencies", installDependencies));
   return initBlock.execute();
}

} // namespace dependencies
} // namespace modules

namespace module_context {

Error installEmbeddedPackage(const std::string& name)
{
   EmbeddedPackage pkg = embeddedPackageInfo(name);
   return module_context::installPackage(pkg.archivePath);
}

} // anonymous namespace

} // namespace session
} // namespace rstudio

<|endoftext|>


<commit_before><commit_msg>[localoperator.codim0] deprecate<commit_after><|endoftext|>


<commit_before><commit_msg>[grid] fixes the cube provider<commit_after><|endoftext|>