text: // Copyright (c) 2011-2019 The Bitcoin Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifdef HAVE_CONFIG_H
  
  #endif
  
  #include <transactiondesc.h>
  
  #include <bitcoinunits.h>
  #include <guiutil.h>
  #include <transactionrecord.h>
  
  #include <interfaces/node.h>
  #include <interfaces/wallet.h>
  
  #include <stdint.h>
  #include <string>
  
  QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks)
  {
      //    if (!status.is_final)
      //    {
      //        if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
      //            return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - numBlocks);
      //        else
      //            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
      //    }
      //    else
      //    {
      //        int nDepth = status.depth_in_main_chain;
      //        if (nDepth < 0)
      //            return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
      //        else if (nDepth == 0)
      //            return tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : "");
      //        else if (nDepth < 6)
      //            return tr("%1/unconfirmed").arg(nDepth);
      //        else
      //            return tr("%1 confirmations").arg(nDepth);
      //    }
  
      return {"tx_status"};
  }
  
  // Takes an encoded PaymentRequest as a string and tries to find the Common Name of the X.509 certificate
  // used to sign the PaymentRequest.
  bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
  {
      // Search for the supported pki type strings
      if (pr.find(std::string({0x12, 0x0b}) + "x509+sha256") != std::string::npos || pr.find(std::string({0x12, 0x09}) + "x509+sha1") != std::string::npos) {
          // We want the common name of the Subject of the cert. This should be the second occurrence
          // of the bytes 0x0603550403. The first occurrence of those is the common name of the issuer.
          // After those bytes will be either 0x13 or 0x0C, then length, then either the ascii or utf8
          // string with the common name which is the merchant name
          size_t cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03});
          if (cn_pos != std::string::npos) {
              cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03}, cn_pos + 5);
              if (cn_pos != std::string::npos) {
                  cn_pos += 5;
                  if (pr[cn_pos] == 0x13 || pr[cn_pos] == 0x0c) {
                      cn_pos++; // Consume the type
                      int str_len = pr[cn_pos];
                      cn_pos++; // Consume the string length
                      merchant = QString::fromUtf8(pr.data() + cn_pos, str_len);
                      return true;
                  }
              }
          }
      }
      return false;
  }
  
  QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
  {
      int numBlocks;
      interfaces::WalletTxStatus status;
      interfaces::WalletOrderForm orderForm;
      bool inMempool;
      interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks);
  
      QString strHTML;
  
      strHTML.reserve(4000);
      strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
  
      int64_t nTime = wtx.time;
      CAmount nCredit = wtx.credit;
      CAmount nDebit = wtx.debit;
      CAmount nNet = nCredit - nDebit;
  
      strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks);
      strHTML += "<br>";
  
      strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
  
      //
      // From
      //
      if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
      {
          // Online transaction
          strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.value_map["from"]) + "<br>";
      }
      else
      {
          // Offline transaction
          if (nNet > 0)
          {
              // Credit
              auto address = rec->address;
              if (!address.empty()) {
                  std::string name;
                  strHTML += "<b>" + tr("From") + ":</b> " + tr("own address") + "<br>";
                  strHTML += "<b>" + tr("To") + ":</b> ";
                  strHTML += GUIUtil::HtmlEscape(rec->address);
                  strHTML += "<br>";
              }
          }
          else
          {
              strHTML += "<b>" + tr("To") + ":</b> " + GUIUtil::HtmlEscape(rec->address) + "<br>";
          }
      }
  
      strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
  
      //
      // Message
      //
      if (wtx.value_map.count("message") && !wtx.value_map["message"].empty())
          strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["message"], true) + "<br>";
      if (wtx.value_map.count("comment") && !wtx.value_map["comment"].empty())
          strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["comment"], true) + "<br>";
  
      strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>";
  
      // Message from normal bitcoin:URI (bitcoin:123...?message=example)
      for (const std::pair<std::string, std::string>& r : orderForm) {
          if (r.first == "Message")
              strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
  
          //
          // PaymentRequest info:
          //
          if (r.first == "PaymentRequest")
          {
              QString merchant;
              if (!GetPaymentRequestMerchant(r.second, merchant)) {
                  merchant.clear();
              } else {
                  merchant += tr(" (Certificate was not verified)");
              }
              if (!merchant.isNull()) {
                  strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
              }
          }
      }
  
      strHTML += "</font></html>";
      return strHTML;
  }
  