PageRenderTime 93ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 2ms

/src/core/moneychanger.cpp

http://github.com/FellowTraveler/Moneychanger
C++ | 8161 lines | 3371 code | 1077 blank | 3713 comment | 608 complexity | cce05d675dee3ab5a9537a61bc3a4fb3 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * MoneyChanger
  3. * moneychanger.cpp
  4. *
  5. * File organized as follows:
  6. *
  7. * /-- Constructor (Lengthy)--/
  8. * /-- Destructor --/
  9. *
  10. * /-- Systray Functions --/
  11. *
  12. * /-- Menu Dialog Functions --/
  13. *
  14. */
  15. #ifndef __STABLE_HPP__
  16. #include <core/stable.hpp>
  17. #endif
  18. #include <core/moneychanger.hpp>
  19. #include <core/handlers/DBHandler.hpp>
  20. #include <core/handlers/contacthandler.hpp>
  21. #include <core/handlers/modeltradearchive.hpp>
  22. #include <gui/widgets/compose.hpp>
  23. #include <gui/widgets/overridecursor.hpp>
  24. #include <gui/widgets/editdetails.hpp>
  25. #include <gui/widgets/requestdlg.hpp>
  26. #include <gui/widgets/dlgchooser.hpp>
  27. #include <gui/widgets/senddlg.hpp>
  28. #include <gui/widgets/proposeplandlg.hpp>
  29. #include <gui/widgets/createinsurancecompany.hpp>
  30. #include <gui/widgets/wizardconfirmsmartcontract.hpp>
  31. #include <gui/widgets/wizardrunsmartcontract.hpp>
  32. #include <gui/widgets/wizardpartyacct.hpp>
  33. #include <gui/widgets/settings.hpp>
  34. #include <gui/ui/dlgimport.hpp>
  35. #include <gui/ui/dlglog.hpp>
  36. #include <gui/ui/dlgmenu.hpp>
  37. #include <gui/ui/dlgmarkets.hpp>
  38. #include <gui/ui/dlgtradearchive.hpp>
  39. #include <gui/ui/dlgencrypt.hpp>
  40. #include <gui/ui/dlgdecrypt.hpp>
  41. #include <gui/ui/dlginbailment.hpp>
  42. #include <gui/ui/dlgpairnode.hpp>
  43. #include <gui/ui/dlgpassphrasemanager.hpp>
  44. #include <gui/ui/messages.hpp>
  45. #include <gui/ui/payments.hpp>
  46. #include <gui/ui/agreements.hpp>
  47. #include <gui/ui/activity.hpp>
  48. #include <gui/ui/getstringdialog.hpp>
  49. #include <opentxs/opentxs.hpp>
  50. #include <QMenu>
  51. #include <QApplication>
  52. #include <QFile>
  53. #include <QDateTime>
  54. #include <QDebug>
  55. #include <QMessageBox>
  56. #include <QSystemTrayIcon>
  57. #include <QTimer>
  58. #include <QRegExp>
  59. #include <QFlags>
  60. #include <chrono>
  61. #include <functional>
  62. #include <sstream>
  63. #include <utility>
  64. #include <memory>
  65. template class opentxs::Pimpl<opentxs::network::zeromq::PairEventCallback>;
  66. template class std::shared_ptr<const opentxs::OTPayment>;
  67. bool Moneychanger::is_base64(QString string)
  68. {
  69. QRegExp rx("[^a-zA-Z0-9+/=]");
  70. if ( rx.indexIn(string) == -1
  71. && (string.length()%4) == 0
  72. && string.length()>=4) {
  73. return true;
  74. }
  75. return false;
  76. }
  77. /**
  78. * Constructor & Destructor
  79. **/
  80. // Ownership passes to caller.
  81. //static
  82. Moneychanger * Moneychanger::Instantiate(const opentxs::api::client::Manager& manager, QWidget *parent/*=0*/)
  83. {
  84. return new Moneychanger(manager, parent);
  85. }
  86. static Moneychanger * It(bool bShuttingDown = false,
  87. QScopedPointer<Moneychanger> * pMoneychangerMain = nullptr);
  88. // NOT owned by caller.
  89. //static
  90. Moneychanger * Moneychanger::It(bool bShuttingDown/*=false*/, QScopedPointer<Moneychanger> * pMoneychangerMain/*=nullptr*/)
  91. {
  92. // See main.cpp
  93. static QScopedPointer<Moneychanger> & pMoneychanger = *pMoneychangerMain;
  94. if (bShuttingDown)
  95. {
  96. // bShuttingDown is only passed in the very last time this is called,
  97. // (at application shutdown.)
  98. //
  99. // (If we don't delete it at this time, then it won't get deleted until
  100. // the static objects are deleted, which causes a crash since apparently
  101. // that's too late to be deleting the widgets.)
  102. //
  103. pMoneychanger->disconnect();
  104. delete pMoneychanger.take();
  105. return nullptr;
  106. }
  107. // -------------------------------------
  108. if (pMoneychanger.isNull())
  109. return nullptr;
  110. return pMoneychanger.data();
  111. }
  112. Moneychanger::Moneychanger(const opentxs::api::client::Manager& manager, QWidget *parent)
  113. : QWidget(parent),
  114. ot_(manager),
  115. notify_bailment_callback_(opentxs::network::zeromq::ListenCallback::Factory(
  116. [this](const opentxs::network::zeromq::Message& message) -> void {
  117. this->process_notify_bailment(message);
  118. })),
  119. notify_bailment_(ot_.ZMQ().Context().SubscribeSocket(notify_bailment_callback_)),
  120. pair_event_callback_(opentxs::network::zeromq::PairEventCallback::Factory(
  121. [this](const opentxs::proto::PairEvent& event) -> void {
  122. this->process_pair_event(event);
  123. })),
  124. pair_events_(ot_.ZMQ().Context().PairEventListener(pair_event_callback_, ot_.Instance())),
  125. widget_update_callback_(opentxs::network::zeromq::ListenCallback::Factory(
  126. [this](const opentxs::network::zeromq::Message& message) -> void {
  127. this->process_widget_update(message);
  128. })),
  129. widget_update_(ot_.ZMQ().Context().SubscribeSocket(widget_update_callback_)),
  130. // m_list(*(new MTNameLookupQT)),
  131. mc_overall_init(false)
  132. {
  133. /**
  134. ** Init variables *
  135. **/
  136. refresh_count_.store(0);
  137. notify_bailment_->Start(ot_.Endpoints().PendingBailment());
  138. widget_update_->Start(ot_.Endpoints().WidgetUpdate());
  139. ot_.Schedule(
  140. std::chrono::seconds(5),
  141. [&]()->void
  142. {
  143. const auto count =
  144. ot_.Sync().RefreshCount();
  145. const auto existing = refresh_count_.load();
  146. if (existing < count) {
  147. refresh_count_.store(count);
  148. accept_cheques();
  149. //emit needToPopulateRecordlist();
  150. }
  151. }
  152. );
  153. ot_.Schedule(
  154. std::chrono::seconds(20),
  155. [this]()->void{ ot_.Sync().Refresh(); },
  156. (std::chrono::seconds(std::time(nullptr))));
  157. //SQLite database
  158. // This can be moved very easily into a different class
  159. // Which I will inevitably end up doing.
  160. /** Default Nym **/
  161. qDebug() << "Setting up Nym table";
  162. if (0 == DBHandler::getInstance()->querySize("SELECT `nym` FROM `default_nym` WHERE `default_id`='1' LIMIT 0,1"))
  163. {
  164. qDebug() << "Default Nym wasn't set in the database. Inserting blank record...";
  165. DBHandler::getInstance()->runQuery("INSERT INTO `default_nym` (`default_id`,`nym`) VALUES('1','')"); // Blank Row
  166. }
  167. else
  168. {
  169. if (DBHandler::getInstance()->isNext("SELECT `nym` FROM `default_nym` WHERE `default_id`='1' LIMIT 0,1"))
  170. {
  171. default_nym_id = DBHandler::getInstance()->queryString("SELECT `nym` FROM `default_nym` WHERE `default_id`='1' LIMIT 0,1", 0, 0);
  172. }
  173. // -------------------------------------------------
  174. // if (default_nym_id.isEmpty() && (ot_.Exec().GetNymCount() > 0))
  175. // {
  176. // default_nym_id = QString::fromStdString(ot_.Exec().GetNym_ID(0));
  177. // }
  178. // // -------------------------------------------------
  179. // //Ask OT what the display name of this nym is and store it for quick retrieval later on(mostly for "Default Nym" displaying purposes)
  180. // if (!default_nym_id.isEmpty())
  181. // {
  182. // default_nym_name = QString::fromStdString(ot_.Exec().GetNym_Name(default_nym_id.toStdString()));
  183. // }
  184. // else
  185. // qDebug() << "Error loading DEFAULT NYM from SQL";
  186. }
  187. /** Default Server **/
  188. //Query for the default server (So we know for setting later on -- Auto select server associations on later dialogs)
  189. if (DBHandler::getInstance()->querySize("SELECT `server` FROM `default_server` WHERE `default_id`='1' LIMIT 0,1") == 0)
  190. {
  191. qDebug() << "Default Server wasn't set in the database. Inserting blank record...";
  192. DBHandler::getInstance()->runQuery("INSERT INTO `default_server` (`default_id`, `server`) VALUES('1','')"); // Blank Row
  193. }
  194. else
  195. {
  196. if (DBHandler::getInstance()->runQuery("SELECT `server` FROM `default_server` WHERE `default_id`='1' LIMIT 0,1"))
  197. {
  198. default_notary_id = DBHandler::getInstance()->queryString("SELECT `server` FROM `default_server` WHERE `default_id`='1' LIMIT 0,1", 0, 0);
  199. }
  200. // -------------------------------------------------
  201. // if (default_notary_id.isEmpty() && (ot_.Exec().GetServerCount() > 0))
  202. // {
  203. // default_notary_id = QString::fromStdString(ot_.Exec().GetServer_ID(0));
  204. // }
  205. // // -------------------------------------------------
  206. // //Ask OT what the display name of this server is and store it for a quick retrieval later on(mostly for "Default Server" displaying purposes)
  207. // if (!default_notary_id.isEmpty())
  208. // {
  209. // default_server_name = QString::fromStdString(ot_.Exec().GetServer_Name(default_notary_id.toStdString()));
  210. // }
  211. // else
  212. // qDebug() << "Error loading DEFAULT SERVER from SQL";
  213. }
  214. /** Default Asset Type **/
  215. //Query for the default asset (So we know for setting later on -- Auto select asset associations on later dialogs)
  216. if (DBHandler::getInstance()->querySize("SELECT `asset` FROM `default_asset` WHERE `default_id`='1' LIMIT 0,1") == 0)
  217. {
  218. qDebug() << "Default Asset Type wasn't set in the database. Inserting blank record...";
  219. DBHandler::getInstance()->runQuery("INSERT INTO `default_asset` (`default_id`,`asset`) VALUES('1','')"); // Blank Row
  220. }
  221. else
  222. {
  223. if (DBHandler::getInstance()->runQuery("SELECT `asset` FROM `default_asset` WHERE `default_id`='1' LIMIT 0,1"))
  224. {
  225. default_asset_id = DBHandler::getInstance()->queryString("SELECT `asset` FROM `default_asset` WHERE `default_id`='1' LIMIT 0,1", 0, 0);
  226. }
  227. // -------------------------------------------------
  228. // if (default_asset_id.isEmpty() && (ot_.Exec().GetAssetTypeCount() > 0))
  229. // {
  230. // default_asset_id = QString::fromStdString(ot_.Exec().GetAssetType_ID(0));
  231. // }
  232. // // -------------------------------------------------
  233. // //Ask OT what the display name of this asset type is and store it for a quick retrieval later on(mostly for "Default Asset" displaying purposes)
  234. // if (!default_asset_id.isEmpty())
  235. // {
  236. // default_asset_name = QString::fromStdString(ot_.Exec().GetAssetType_Name(default_asset_id.toStdString()));
  237. // }
  238. // else
  239. // qDebug() << "Error loading DEFAULT ASSET from SQL";
  240. }
  241. /** Default Account **/
  242. //Query for the default account (So we know for setting later on -- Auto select account associations on later dialogs)
  243. if (DBHandler::getInstance()->querySize("SELECT `account` FROM `default_account` WHERE `default_id`='1' LIMIT 0,1") == 0)
  244. {
  245. qDebug() << "Default Account wasn't set in the database. Inserting blank record...";
  246. DBHandler::getInstance()->runQuery("INSERT INTO `default_account` (`default_id`,`account`) VALUES('1','')"); // Blank Row
  247. }
  248. else
  249. {
  250. if (DBHandler::getInstance()->runQuery("SELECT `account` FROM `default_account` WHERE `default_id`='1' LIMIT 0,1"))
  251. {
  252. default_account_id = DBHandler::getInstance()->queryString("SELECT `account` FROM `default_account` WHERE `default_id`='1' LIMIT 0,1", 0, 0);
  253. }
  254. // -------------------------------------------------
  255. // if (default_account_id.isEmpty() && (ot_.Exec().GetAccountCount() > 0))
  256. // {
  257. // default_account_id = QString::fromStdString(ot_.Exec().GetAccountWallet_ID(0));
  258. // }
  259. // // -------------------------------------------------
  260. // //Ask OT what the display name of this account is and store it for a quick retrieval later on(mostly for "Default Account" displaying purposes)
  261. // if (!default_account_id.isEmpty())
  262. // {
  263. // default_account_name = QString::fromStdString(ot_.Exec().GetAccountWallet_Name(default_account_id.toStdString()));
  264. // }
  265. // else
  266. // qDebug() << "Error loading DEFAULT ACCOUNT from SQL";
  267. }
  268. // ----------------------------------------------------------------------------
  269. //Ask OT for "cash account" information (might be just "Account" balance)
  270. //Ask OT the purse information
  271. /* *** *** ***
  272. * Init Memory Trackers (there may be other int below than just memory trackers but generally there will be mostly memory trackers below)
  273. * Allows the program to boot with a low footprint -- keeps start times low no matter the program complexity;
  274. * Memory will expand as the operator opens dialogs;
  275. * Also prevents HTTP requests from overloading or spamming the operators device by only allowing one window of that request;
  276. * *** *** ***/
  277. //Init MC System Tray Icon
  278. mc_systrayIcon = new QSystemTrayIcon(this);
  279. mc_systrayIcon->setIcon(QIcon(":/icons/moneychanger"));
  280. //Init Icon resources (Loading resources/access Harddrive first; then send to GPU; This specific order will in theory prevent bottle necking between HDD/GPU)
  281. mc_systrayIcon_shutdown = QIcon(":/icons/quit");
  282. mc_systrayIcon_overview = QIcon(":/icons/overview");
  283. mc_systrayIcon_nym = QIcon(":/icons/icons/identity_BW2.png");
  284. mc_systrayIcon_server = QIcon(":/icons/server");
  285. mc_systrayIcon_goldaccount = QIcon(":/icons/icons/safe_box.png");
  286. mc_systrayIcon_purse = QIcon(":/icons/icons/assets.png");
  287. // mc_systrayIcon_sendfunds = QIcon(":/icons/icons/fistful_of_cash_72.png");
  288. mc_systrayIcon_sendfunds = QIcon(":/icons/icons/money_fist4_small.png");
  289. // mc_systrayIcon_sendfunds = QIcon(":/icons/sendfunds");
  290. mc_systrayIcon_requestfunds = QIcon(":/icons/requestpayment");
  291. mc_systrayIcon_proposeplan = QIcon(":/icons/icons/timer.png");
  292. // mc_systrayIcon_contacts = QIcon(":/icons/addressbook");
  293. mc_systrayIcon_contacts = QIcon(":/icons/icons/rolodex_card2");
  294. mc_systrayIcon_composemessage = QIcon(":/icons/icons/pencil.png");
  295. // mc_systrayIcon_composemessage = QIcon(":/icons/icons/compose.png");
  296. mc_systrayIcon_markets = QIcon(":/icons/markets");
  297. mc_systrayIcon_trade_archive = QIcon(":/icons/overview");
  298. mc_systrayIcon_active_agreements = QIcon(":/icons/agreements");
  299. mc_systrayIcon_pending = QIcon(":/icons/icons/pending.png");
  300. // ---------------------------------------------------------------
  301. mc_systrayIcon_bitcoin = QIcon(":/icons/icons/bitcoin.png");
  302. mc_systrayIcon_crypto = QIcon(":/icons/icons/lock.png");
  303. //Submenu
  304. mc_systrayIcon_crypto_encrypt = QIcon(":/icons/icons/lock.png");
  305. mc_systrayIcon_crypto_decrypt = QIcon(":/icons/icons/padlock_open.png");
  306. mc_systrayIcon_crypto_sign = QIcon(":/icons/icons/signature-small.png");
  307. mc_systrayIcon_crypto_verify = QIcon(":/icons/icons/check-mark-small.png");
  308. // ---------------------------------------------------------------
  309. mc_systrayIcon_advanced = QIcon(":/icons/advanced");
  310. //Submenu
  311. mc_systrayIcon_advanced_import = QIcon(":/icons/icons/request.png");
  312. mc_systrayIcon_advanced_smartcontracts = QIcon(":/icons/icons/smart_contract_64.png");
  313. mc_systrayIcon_advanced_corporations = QIcon(":/icons/icons/buildings.png");
  314. mc_systrayIcon_advanced_transport = QIcon(":/icons/icons/p2p.png");
  315. mc_systrayIcon_advanced_log = QIcon(":/icons/icons/p2p.png");
  316. mc_systrayIcon_settings = QIcon(":/icons/settings");
  317. // ----------------------------------------------
  318. QString qstrExpertMode = MTContactHandler::getInstance()->
  319. GetValueByID("expertmode", "parameter1", "settings", "setting");
  320. bExpertMode_ = (0 == qstrExpertMode.compare("on"));
  321. // -------------------------------------------------
  322. QString qstrHideNav = MTContactHandler::getInstance()->
  323. GetValueByID("hidenav", "parameter1", "settings", "setting");
  324. bHideNav_ = (0 == qstrHideNav.compare("on"));
  325. // -------------------------------------------------
  326. // setupRecordList();
  327. mc_overall_init = true;
  328. }
  329. void Moneychanger::accept_cheques() const
  330. {
  331. const auto nyms = ot_.OTAPI().LocalNymList();
  332. for (const auto& nym : nyms) {
  333. ot_.Sync().DepositCheques(nym);
  334. }
  335. }
  336. void Moneychanger::process_notify_bailment(
  337. const opentxs::network::zeromq::Message& multipartMessage)
  338. {
  339. OT_ASSERT(1 == multipartMessage.Body().size());
  340. std::string message(*multipartMessage.Body().begin());
  341. auto request =
  342. opentxs::proto::TextToProto<opentxs::proto::PeerRequest>(message);
  343. if (false == opentxs::proto::Validate(request, false)) {
  344. std::cout << __FUNCTION__ << ": Invalid peer request" << std::endl;
  345. return;
  346. }
  347. if (opentxs::proto::PEERREQUEST_PENDINGBAILMENT != request.type()) {
  348. std::cout << __FUNCTION__ << ": Not a notify bailment request"
  349. << std::endl;
  350. return;
  351. }
  352. QString txid = QString::fromStdString(request.pendingbailment().txid());
  353. QString msg = QString(tr("Received notice of pending deposit from "
  354. "blockchain: ")) + txid;
  355. emit appendToLog(msg);
  356. std::cout << __FUNCTION__ << ": Received notice of pending bailment: "
  357. << request.pendingbailment().txid().c_str() << std::endl;
  358. }
  359. void Moneychanger::process_pair_event(const opentxs::proto::PairEvent& event)
  360. {
  361. std::cout << __FUNCTION__ << ": Received pair event" << std::endl;
  362. switch (event.type()) {
  363. case opentxs::proto::PAIREVENT_RENAME: {
  364. std::cout << __FUNCTION__ << ": Issuer " << event.issuer()
  365. << " is ready to be renamed." << std::endl;
  366. } break;
  367. case opentxs::proto::PAIREVENT_STORESECRET: {
  368. QString msg(tr("Your seed backup has been stored on your Stash "
  369. "Node Pro. You may now remove the backup USB device "
  370. "and store it in a safe location."));
  371. emit appendToLog(msg);
  372. std::cout << __FUNCTION__ << ": Issuer " << event.issuer()
  373. << " has stored a seed backup for us." << std::endl;
  374. } break;
  375. case opentxs::proto::PAIREVENT_ERROR:
  376. default: {
  377. std::cout << __FUNCTION__ << ": Unknown or invalid event type"
  378. << std::endl;
  379. }
  380. }
  381. }
  382. void Moneychanger::process_widget_update(
  383. const opentxs::network::zeromq::Message& multipartMessage)
  384. {
  385. OT_ASSERT(1 == multipartMessage.Body().size());
  386. std::string message(*multipartMessage.Body().begin());
  387. const std::string str_msg = std::string(message);
  388. const QString qstrMsg = QString::fromStdString(str_msg);
  389. emit opentxsWidgetUpdated(qstrMsg);
  390. }
  391. // RETRIEVE NYM INTERMEDIARY FILES
  392. // Returns:
  393. // True if I have enough numbers, or if there was success getting more
  394. // transaction numbers.
  395. // False if I didn't have enough numbers, tried to get more, and failed
  396. // somehow.
  397. //
  398. bool Moneychanger::retrieve_nym(
  399. const std::string& strNotaryID,
  400. const std::string& strMyNymID) const
  401. {
  402. auto context = ot_.Wallet().mutable_ServerContext(
  403. opentxs::Identifier::Factory(strMyNymID), opentxs::Identifier::Factory(strNotaryID));
  404. opentxs::Utility MsgUtil(context.It(), ot_);
  405. if (0 >= context.It().UpdateRequestNumber()) {
  406. return false;
  407. }
  408. bool msgWasSent = false;
  409. std::int32_t nGetAndProcessNymbox = MsgUtil.getAndProcessNymbox_4(
  410. strNotaryID, strMyNymID, msgWasSent, true);
  411. if (0 > nGetAndProcessNymbox) {
  412. return false;
  413. }
  414. return true;
  415. }
  416. void Moneychanger::onNeedToCheckNym(QString myNymId, QString hisNymId, QString notaryId)
  417. {
  418. if (hisNymId.isEmpty())
  419. {
  420. qDebug() << __FUNCTION__ << ": ERROR: no hisNymId passed in! (Returning.)";
  421. return;
  422. }
  423. // ---------------------------
  424. if (myNymId.isEmpty())
  425. myNymId = getDefaultNymID();
  426. if (myNymId.isEmpty())
  427. {
  428. //Count nyms
  429. const int32_t nym_count = ot_.Exec().GetNymCount();
  430. if (nym_count > 0)
  431. myNymId = QString::fromStdString(ot_.Exec().GetNym_ID(0));
  432. }
  433. if (myNymId.isEmpty())
  434. {
  435. qDebug() << __FUNCTION__ << ": no myNymId passed in, and unable to figure out one on my own! (Returning.)";
  436. return;
  437. }
  438. // ---------------------------
  439. // If a notary was passed in, let's make sure we have its contract!
  440. //
  441. if (!notaryId.isEmpty())
  442. {
  443. const std::string str_notary_contract = ot_.Exec().GetServer_Contract(notaryId.toStdString());
  444. if (str_notary_contract.empty())
  445. {
  446. notaryId = QString("");
  447. qDebug() << __FUNCTION__ << ": We don't have the server contract for the specified notary ID. "
  448. "(I guess we'll try the default, it may yet work.) TODO: Download it from the DHT.";
  449. }
  450. }
  451. // ---------------------------
  452. mapIDName mapServers;
  453. bool bGotServersForNym = false;
  454. // Hmm, no notary ID was passed. Perhaps one wasn't available.
  455. // In that case we'll see if there are any known notaries for hisNymId.
  456. // If so, we'll use them all.
  457. // Otherwise, we'll try to use the default notary instead.
  458. // Otherwise we'll give up :P
  459. //
  460. if (notaryId.isEmpty())
  461. bGotServersForNym = MTContactHandler::getInstance()->GetServers(mapServers, hisNymId);
  462. else
  463. mapServers.insert(notaryId, "Server Name Unused Here");
  464. if (mapServers.size() < 1)
  465. {
  466. notaryId = getDefaultNotaryID();
  467. if (!notaryId.isEmpty())
  468. mapServers.insert(notaryId, "Server Name Unused Here");
  469. }
  470. // Oh well. We tried.
  471. if (mapServers.size() < 1)
  472. {
  473. qDebug() << __FUNCTION__ << ": no notaryId passed in, and unable to figure out one on my own! (Returning.)";
  474. return;
  475. }
  476. // --------------------------------
  477. const std::string my_nym_id = myNymId.toStdString();
  478. const std::string his_nym_id = hisNymId.toStdString();
  479. for (mapIDName::iterator it_servers = mapServers.begin(); it_servers != mapServers.end(); ++it_servers)
  480. {
  481. QString qstrNotaryID = it_servers.key();
  482. // QString qstrNotaryName = it_servers.value();
  483. if (qstrNotaryID.isEmpty()) // Weird, should never happen.
  484. {
  485. qDebug() << __FUNCTION__ << ": Unexpectedly empty NotaryID, should not happen. (Returning.)";
  486. return;
  487. }
  488. const std::string notary_id = qstrNotaryID.toStdString();
  489. // ---------------------------------------------
  490. // Need to verify that I'M registered at this server, before I try to
  491. // download some guy's credentials from a "server he's known to use."
  492. // I may not even be registered there, in which case the check_nym call would fail.
  493. //
  494. // And how do I know if I even have the server contract at all?
  495. //
  496. const std::string str_server_contract = ot_.Exec().GetServer_Contract(notary_id);
  497. if (str_server_contract.empty())
  498. {
  499. qDebug() << __FUNCTION__ << ": We don't have the server contract for this notary ID. (Skipping.) TODO: Download it from the DHT.";
  500. continue;
  501. }
  502. // ---------------------------------------------
  503. const bool isReg = ot_.Exec().IsNym_RegisteredAtServer(my_nym_id, notary_id);
  504. if (!isReg)
  505. {
  506. std::string response;
  507. {
  508. MTSpinner theSpinner;
  509. response = opentxs::String::Factory(ot_.Sync().RegisterNym(opentxs::Identifier::Factory(my_nym_id), opentxs::Identifier::Factory(notary_id), true))->Get();
  510. if (response.empty() && !ot_.Exec().CheckConnection(notary_id))
  511. {
  512. QString qstrErrorMsg;
  513. qstrErrorMsg = QString("%1: %2. %3.").
  514. arg(tr("Failed trying to contact notary")).
  515. arg(qstrNotaryID).arg(tr("Perhaps it is down, or there might be a network problem"));
  516. emit appendToLog(qstrErrorMsg);
  517. continue;
  518. }
  519. }
  520. if (!opentxs::VerifyMessageSuccess(ot_, response)) {
  521. Moneychanger::It()->HasUsageCredits(notary_id, my_nym_id);
  522. continue;
  523. }
  524. else
  525. MTContactHandler::getInstance()->NotifyOfNymServerPair(myNymId, qstrNotaryID);
  526. }
  527. // ------------------------------
  528. {
  529. std::string response;
  530. {
  531. MTSpinner theSpinner;
  532. const auto notaryID = opentxs::Identifier::Factory(notary_id);
  533. const auto myNymID = opentxs::Identifier::Factory(my_nym_id);
  534. const auto hisNymID = opentxs::Identifier::Factory(his_nym_id);
  535. auto action = ot_.ServerAction().DownloadNym(myNymID, notaryID, hisNymID);
  536. response = action->Run();
  537. }
  538. if (response.empty() && !ot_.Exec().CheckConnection(notary_id))
  539. {
  540. QString qstrErrorMsg;
  541. qstrErrorMsg = QString("%1: %2. %3.").
  542. arg(tr("Failed trying to contact notary")).
  543. arg(qstrNotaryID).arg(tr("Perhaps it is down, or there might be a network problem"));
  544. emit appendToLog(qstrErrorMsg);
  545. continue;
  546. }
  547. int32_t nReturnVal = opentxs::VerifyMessageSuccess(ot_, response);
  548. if (1 == nReturnVal)
  549. {
  550. emit nymWasJustChecked(hisNymId);
  551. break;
  552. }
  553. }
  554. } // for (servers)
  555. }
  556. //QString getBitmessageAddressFromClaims(const QString & claimant_nym_id);
  557. //QString getDisplayNameFromClaims(const QString & claimant_nym_id);
  558. // Someone did this: OT_ME::check_nym(id); emit nymWasJustChecked(id);
  559. //
  560. void Moneychanger::onCheckNym(QString nymId)
  561. {
  562. // ----------------------------------------------
  563. auto strNymId = opentxs::String::Factory(nymId.toStdString());
  564. auto id_nym = opentxs::Identifier::Factory(strNymId);
  565. // ----------------------------------------------
  566. // Get the Nym. Make sure we have the latest copy, since his credentials were apparently
  567. // just downloaded and overwritten.
  568. //
  569. std::shared_ptr<const opentxs::Nym> pCurrentNym =
  570. ot_.Wallet().Nym(id_nym);
  571. if (false == bool(pCurrentNym))
  572. {
  573. qDebug() << "onCheckNym: Loading the nym failed. (Which should NOT happen since we supposedly JUST downloaded that Nym's credentials...)";
  574. return;
  575. }
  576. // // ------------------------------------------------
  577. // // Clear the claims and verifications we already have in the database. (If any.)
  578. // //
  579. // MTContactHandler::getInstance()->clearClaimsForNym(nymId);
  580. // // ----------------------------------------------
  581. // // Import the claims.
  582. // const std::string str_checked_nym_id(strNymId.Get());
  583. // const auto data =
  584. // ot_.Exec().GetContactData(nymId.toStdString());
  585. // auto claims =
  586. // opentxs::proto::DataToProto<opentxs::proto::ContactData>
  587. // (opentxs::Data::Factory(data.c_str(), static_cast<uint32_t>(data.length())));
  588. // for (const auto& section: claims.section()) {
  589. // for (const auto& claim: section.item()) {
  590. // // ---------------------------------------
  591. // const uint32_t claim_section = section.name();
  592. // const uint32_t claim_type = claim.type();
  593. // const QString claim_value = QString::fromStdString(claim.value());
  594. // // Add the claim to the database if not there already.
  595. // const bool upserted =
  596. // MTContactHandler::getInstance()->upsertClaim(
  597. // *pCurrentNym,
  598. // claim_section,
  599. // claim);
  600. // if (!upserted) {
  601. // qDebug() << "onCheckNym: the call to upsertClaim just failed. "
  602. // << "(Returning.)";
  603. // return;
  604. // }
  605. // bool claim_att_active = false;
  606. // bool claim_att_primary = false;
  607. // for (const auto& attribute : claim.attribute()) {
  608. // if (opentxs::proto::CITEMATTR_ACTIVE == attribute) {
  609. // claim_att_active = true;
  610. // }
  611. // if (opentxs::proto::CITEMATTR_PRIMARY == attribute) {
  612. // claim_att_primary = true;
  613. // }
  614. // }
  615. // if (claim_att_active && claim_att_primary) {
  616. // if (claim_section == opentxs::proto::CONTACTSECTION_IDENTIFIER) {
  617. // MTContactHandler::getInstance()->NotifyOfNymNamePair(
  618. // nymId,
  619. // claim_value);
  620. // }
  621. // if ((claim_section == opentxs::proto::CONTACTSECTION_COMMUNICATION) &&
  622. // (claim_type == opentxs::proto::CITEMTYPE_BITMESSAGE)) {
  623. // // NOTE: May not need to do anything here. We already
  624. // // imported the claims, and we can already search the
  625. // // claims for Bitmessage address and NymID, which we
  626. // // are already doing.
  627. // }
  628. // }
  629. // }
  630. // }
  631. // // -------------------------------------------------------
  632. // // Import the verifications.
  633. // //
  634. // const auto ver_data =
  635. // ot_.Exec().GetVerificationSet(nymId.toStdString());
  636. // auto the_set =
  637. // opentxs::proto::DataToProto<opentxs::proto::VerificationSet>
  638. // (opentxs::Data::Factory(ver_data.c_str(), ver_data.length()));
  639. // // Internal verifications:
  640. // // Here I'm looping through pCurrentNym's verifications of other people's claims.
  641. // for (auto& claimant: the_set.internal().identity()) {
  642. // // Here we're looping through those other people. (Claimants.)
  643. // const std::string& str_claimant_id = claimant.nym();
  644. // for (auto& verification : claimant.verification()) {
  645. // const bool success =
  646. // MTContactHandler::getInstance()->upsertClaimVerification(
  647. // str_claimant_id,
  648. // str_checked_nym_id,
  649. // verification,
  650. // true); //bIsInternal=true
  651. // if (!success) {
  652. // qDebug() << "onCheckNym: the call to "
  653. // << "upsertInternalClaimVerification just failed. "
  654. // << "(Returning.)";
  655. // return;
  656. // }
  657. // }
  658. // }
  659. // // External verifications:
  660. // // Here I'm looping through other people's verifications of pCurrentNym's claims.
  661. // for (auto& verifier: the_set.external().identity()) {
  662. // const std::string& str_verifier_id = verifier.nym();
  663. // for (auto& verification : verifier.verification()) {
  664. // const bool success =
  665. // MTContactHandler::getInstance()->upsertClaimVerification(
  666. // str_checked_nym_id,
  667. // str_verifier_id,
  668. // verification,
  669. // false); //bIsInternal=true by default.
  670. // if (!success) {
  671. // qDebug() << "onCheckNym: the call to "
  672. // << "upsertExternalClaimVerification just failed. "
  673. // << "(Returning.)";
  674. // return;
  675. // }
  676. // }
  677. // }
  678. // // -------------------------------------------------------
  679. // // Import the repudiations.
  680. // // -------------------------------------------------------
  681. // // emit signal that claims / verifications were updated.
  682. // //
  683. emit claimsUpdatedForNym(nymId);
  684. }
  685. static void blah()
  686. {
  687. //resume
  688. //todo
  689. // OT_API.hpp
  690. //EXPORT VerificationSet GetVerificationSet(const Nym& fromNym) const;
  691. // EXPORT bool SetVerifications(Nym& onNym,
  692. // const proto::VerificationSet&) const;
  693. // Nym.hpp
  694. // std::shared_ptr<proto::VerificationSet> VerificationSet() const;
  695. // bool SetVerificationSet(const proto::VerificationSet& data);
  696. //
  697. // proto::Verification Sign(
  698. // const std::string& claim,
  699. // const bool polarity,
  700. // const int64_t start = 0,
  701. // const int64_t end = 0,
  702. // const OTPasswordData* pPWData = nullptr) const;
  703. // bool Verify(const proto::Verification& item) const;
  704. // VerificationSet has 2 groups, internal and external.
  705. // Internal is for your signatures on other people's claims.
  706. // External is for other people's signatures on your claims.
  707. // When you find that in the external, you copy it to your own credential.
  708. // So external is for re-publishing other people's verifications of your claims.
  709. // If we've repudiated any claims, you can add their IDs to the repudiated field in the verification set.
  710. }
  711. Moneychanger::~Moneychanger()
  712. {
  713. }
  714. //opentxs::OTRecordList & Moneychanger::GetRecordlist()
  715. //{
  716. // return m_list;
  717. //}
  718. //void Moneychanger::setupRecordList()
  719. //{
  720. // int nServerCount = ot_.Exec().GetServerCount();
  721. // int nAssetCount = ot_.Exec().GetAssetTypeCount();
  722. // int nNymCount = ot_.Exec().GetNymCount();
  723. // // ----------------------------------------------------
  724. // GetRecordlist().ClearServers();
  725. // GetRecordlist().ClearAssets();
  726. // GetRecordlist().ClearNyms();
  727. // GetRecordlist().ClearAccounts();
  728. // // ----------------------------------------------------
  729. // for (int ii = 0; ii < nServerCount; ++ii)
  730. // {
  731. // std::string NotaryID = ot_.Exec().GetServer_ID(ii);
  732. // GetRecordlist().AddNotaryID(NotaryID);
  733. // }
  734. // // ----------------------------------------------------
  735. // for (int ii = 0; ii < nAssetCount; ++ii)
  736. // {
  737. // std::string InstrumentDefinitionID = ot_.Exec().GetAssetType_ID(ii);
  738. // GetRecordlist().AddInstrumentDefinitionID(InstrumentDefinitionID);
  739. // }
  740. // // ----------------------------------------------------
  741. // for (int ii = 0; ii < nNymCount; ++ii)
  742. // {
  743. // std::string nymId = ot_.Exec().GetNym_ID(ii);
  744. // GetRecordlist().AddNymID(nymId);
  745. // }
  746. // // ----------------------------------------------------
  747. // for (const auto& [accountID, alias] : ot_.DB().AccountList())
  748. // {
  749. // GetRecordlist().AddAccountID(accountID);
  750. // }
  751. // // ----------------------------------------------------
  752. // GetRecordlist().AcceptChequesAutomatically (true);
  753. // GetRecordlist().AcceptReceiptsAutomatically (true);
  754. // GetRecordlist().AcceptTransfersAutomatically(false);
  755. // GetRecordlist().IgnoreMail(!expertMode());
  756. //}
  757. // Calls OTRecordList::Populate(), and then additionally adds records from Bitmessage, etc.
  758. //
  759. //void Moneychanger::populateRecords(bool bCurrentlyModifying/*=false*/)
  760. //{
  761. // GetRecordlist().Populate(); // Refreshes the OT data from local storage. < << <<==============***
  762. // ---------------------------------------------------------------------
  763. // QList<QString> listCheckOnlyOnce; // So we don't call checkMail more than once for the same connect string.
  764. // // ---------------------------------------------------------------------
  765. // // Let's see if, additionally, there are any Bitmessage records (etc)
  766. // // for the Nyms that we care about. (If we didn't add a Nym ID to GetRecordlist()'s
  767. // // list of Nyms, then we don't care about any Bitmessages for that Nym.)
  768. // //
  769. // bool bNeedsReSorting = false;
  770. // const opentxs::list_of_strings & the_nyms = GetRecordlist().GetNyms();
  771. // for (opentxs::list_of_strings::const_iterator it = the_nyms.begin(); it != the_nyms.end(); ++it)
  772. // {
  773. // const std::string str_nym_id = *it;
  774. // // -----------------------------
  775. // mapIDName mapMethods;
  776. // QString filterByNym = QString::fromStdString(str_nym_id);
  777. // bool bGotMethods = !filterByNym.isEmpty() ? MTContactHandler::getInstance()->GetMsgMethodsByNym(mapMethods, filterByNym, false, QString("")) : false;
  778. // if (bGotMethods)
  779. // {
  780. // // Loop through mapMethods and for each methodID, call GetAddressesByNym.
  781. // // Then for each address, grab the inbox and outbox from MTComms, and add
  782. // // the messages to GetRecordlist().
  783. // //
  784. // for (mapIDName::iterator ii = mapMethods.begin(); ii != mapMethods.end(); ++ii)
  785. // {
  786. // QString qstrID = ii.key();
  787. // int nFilterByMethodID = 0;
  788. // QStringList stringlist = qstrID.split("|");
  789. // if (stringlist.size() >= 2) // Should always be 2...
  790. // {
  791. //// QString qstrType = stringlist.at(0);
  792. // QString qstrMethodID = stringlist.at(1);
  793. // nFilterByMethodID = qstrMethodID.isEmpty() ? 0 : qstrMethodID.toInt();
  794. // // --------------------------------------
  795. // if (nFilterByMethodID > 0)
  796. // {
  797. // QString qstrMethodType = MTContactHandler::getInstance()->GetMethodType (nFilterByMethodID);
  798. // QString qstrTypeDisplay = MTContactHandler::getInstance()->GetMethodTypeDisplay(nFilterByMethodID);
  799. // QString qstrConnectStr = MTContactHandler::getInstance()->GetMethodConnectStr (nFilterByMethodID);
  800. // if (!qstrConnectStr.isEmpty())
  801. // {
  802. // NetworkModule * pModule = MTComms::find(qstrConnectStr.toStdString());
  803. // if ((nullptr == pModule) && MTComms::add(qstrMethodType.toStdString(), qstrConnectStr.toStdString()))
  804. // pModule = MTComms::find(qstrConnectStr.toStdString());
  805. // if (nullptr == pModule)
  806. // // todo probably need a messagebox here.
  807. // qDebug() << QString("PopulateRecords: Unable to add a %1 interface with connection string: %2").arg(qstrMethodType).arg(qstrConnectStr);
  808. // if ((nullptr != pModule) && pModule->accessible())
  809. // {
  810. // if ((-1) == listCheckOnlyOnce.indexOf(qstrConnectStr)) // Not on the list yet.
  811. // {
  812. // pModule->checkMail();
  813. // listCheckOnlyOnce.insert(0, qstrConnectStr);
  814. // }
  815. // // ------------------------------
  816. // mapIDName mapAddresses;
  817. // if (MTContactHandler::getInstance()->GetAddressesByNym(mapAddresses, filterByNym, nFilterByMethodID))
  818. // {
  819. // for (mapIDName::iterator jj = mapAddresses.begin(); jj != mapAddresses.end(); ++jj)
  820. // {
  821. // QString qstrAddress = jj.key();
  822. // if (!qstrAddress.isEmpty())
  823. // {
  824. // // --------------------------------------------------------------------------------------------
  825. // // INBOX
  826. // //
  827. // std::vector< _SharedPtr<NetworkMail> > theInbox = pModule->getInbox(qstrAddress.toStdString());
  828. // for (std::vector< _SharedPtr<NetworkMail> >::size_type nIndex = 0; nIndex < theInbox.size(); ++nIndex)
  829. // {
  830. // _SharedPtr<NetworkMail> & theMsg = theInbox[nIndex];
  831. // std::string strSubject = theMsg->getSubject();
  832. // std::string strContents = theMsg->getMessage();
  833. // // ----------------------------------------------------
  834. // QString qstrFinal;
  835. // if (!strSubject.empty())
  836. // qstrFinal = QString("%1: %2\n%3").
  837. // arg(tr("Subject")).
  838. // arg(QString::fromStdString(strSubject)).
  839. // arg(QString::fromStdString(strContents));
  840. // else
  841. // qstrFinal = QString::fromStdString(strContents);
  842. // // ----------------------------------------------------
  843. // bNeedsReSorting = true;
  844. // if (!theMsg->getMessageID().empty())
  845. // GetRecordlist().AddSpecialMsg(theMsg->getMessageID(),
  846. // false, //bIsOutgoing=false
  847. // static_cast<int32_t>(nFilterByMethodID),
  848. // qstrFinal.toStdString(),
  849. // theMsg->getTo(),
  850. // theMsg->getFrom(),
  851. // qstrMethodType.toStdString(),
  852. // qstrTypeDisplay.toStdString(),
  853. // str_nym_id,
  854. // static_cast<time64_t>(theMsg->getReceivedTime()));
  855. // } // for (inbox)
  856. // // --------------------------------------------------------------------------------------------
  857. // // OUTBOX
  858. // //
  859. // std::vector< _SharedPtr<NetworkMail> > theOutbox = pModule->getOutbox(qstrAddress.toStdString());
  860. // for (std::vector< _SharedPtr<NetworkMail> >::size_type nIndex = 0; nIndex < theOutbox.size(); ++nIndex)
  861. // {
  862. // _SharedPtr<NetworkMail> & theMsg = theOutbox[nIndex];
  863. // std::string strSubject = theMsg->getSubject();
  864. // std::string strContents = theMsg->getMessage();
  865. // // ----------------------------------------------------
  866. // QString qstrFinal;
  867. // if (!strSubject.empty())
  868. // qstrFinal = QString("%1: %2\n%3").
  869. // arg(tr("Subject")).
  870. // arg(QString::fromStdString(strSubject)).
  871. // arg(QString::fromStdString(strContents));
  872. // else
  873. // qstrFinal = QString::fromStdString(strContents);
  874. // // ----------------------------------------------------
  875. // bNeedsReSorting = true;
  876. //// qDebug() << QString("Adding OUTGOING theMsg->getMessageID(): %1 \n filterByNym: %2 \n qstrAddress: %3 \n nIndex: %4")
  877. //// .arg(QString::fromStdString(theMsg->getMessageID()))
  878. //// .arg(filterByNym)
  879. //// .arg(qstrAddress)
  880. //// .arg(nIndex)
  881. //// ;
  882. // if (!theMsg->getMessageID().empty())
  883. // GetRecordlist().AddSpecialMsg(theMsg->getMessageID(),
  884. // true, //bIsOutgoing=true
  885. // static_cast<int32_t>(nFilterByMethodID),
  886. // qstrFinal.toStdString(),
  887. // theMsg->getFrom(),
  888. // theMsg->getTo(),
  889. // qstrMethodType.toStdString(),
  890. // qstrTypeDisplay.toStdString(),
  891. // str_nym_id,
  892. // static_cast<time64_t>(theMsg->getSentTime()));
  893. // } // for (outbox)
  894. // } // if (!qstrAddress.isEmpty())
  895. // } // for (addresses)
  896. // } // if GetAddressesByNym
  897. // } // if ((nullptr != pModule) && pModule->accessible())
  898. // } // if (!qstrConnectStr.isEmpty())
  899. // } // if nFilterByMethodID > 0
  900. // } // if (stringlist.size() >= 2)
  901. // } // for (methods)
  902. // } // if bGotMethods
  903. // } // for (nyms)
  904. // // -----------------------------------------------------
  905. // if (bNeedsReSorting)
  906. // GetRecordlist().SortRecords();
  907. // // -----------------------------------------------------
  908. // // This takes things like market receipts out of the record list
  909. // // and moves to their own database table.
  910. // // Same thing for mail messages, etc.
  911. // //
  912. // if (!bCurrentlyModifying)
  913. // modifyRecords();
  914. //}
  915. // ---------------------------------------------------------------
  916. // Check and see if the Nym has exhausted his usage credits.
  917. //
  918. // Return value: -2 for error, -1 for "unlimited" (or "server isn't enforcing"),
  919. // 0 for "exhausted", and non-zero for the exact number of credits available.
  920. int64_t Moneychanger::HasUsageCredits(const std::string & notary_id,
  921. const std::string & NYM_ID)
  922. {
  923. // Usually when a message fails, Moneychanger calls HasUsageCredits because it assumes
  924. // the failure probably happened due to a lack of usage credits.
  925. // ...But what if there was a network failure? What if messages can't even get out?
  926. //
  927. if (!ot_.Exec().CheckConnection(notary_id))
  928. {
  929. QString qstrErrorMsg;
  930. qstrErrorMsg = tr("HasUsageCredits: Failed trying to contact the notary. Perhaps it is down, or there might be a network problem.");
  931. emit appendToLog(qstrErrorMsg);
  932. return -2;
  933. }
  934. // --------------------------------------------------------
  935. std::string strMessage;
  936. {
  937. MTSpinner theSpinner;
  938. const auto notaryID = opentxs::Identifier::Factory(notary_id);
  939. const auto nymID = opentxs::Identifier::Factory(NYM_ID);
  940. auto action = ot_.ServerAction().AdjustUsageCredits(nymID, notaryID, nymID, 0);
  941. strMessage = action->Run();
  942. }
  943. if (strMessage.empty())
  944. {
  945. // QString qstrErrorMsg;
  946. // qstrErrorMsg = tr("Moneychanger::HasUsageCredits: Error 'strMessage' is Empty!");
  947. // emit appendToLog(qstrErrorMsg);
  948. return -2;
  949. }
  950. // --------------------------------------------------------
  951. const int64_t lReturnValue = ot_.Exec().Message_GetUsageCredits(strMessage);
  952. // --------------------------------------------------------
  953. QString qstrErrorMsg;
  954. switch (lReturnValue)
  955. {
  956. case (-2): // error
  957. qstrErrorMsg = tr("Error checking usage credits. Perhaps the server is down or inaccessible?");
  958. break;
  959. // --------------------------------
  960. case (-1): // unlimited, or server isn't enforcing
  961. qstrErrorMsg = tr("Nym has unlimited usage credits (or the server isn't enforcing credits.')");
  962. break;
  963. // --------------------------------
  964. case (0): // Exhausted
  965. qstrErrorMsg = tr("Sorry, but the Nym attempting this action is all out of usage credits on the server. "
  966. "(You should contact the server operator and purchase more usage credits.)");
  967. break;
  968. // --------------------------------
  969. default: // Nym has X usage credits remaining.
  970. qstrErrorMsg = tr("The Nym still has usage credits remaining. Should be fine.");
  971. break;
  972. }
  973. // --------------------------------
  974. switch (lReturnValue)
  975. {
  976. case (-2): // Error
  977. case (0): // Exhausted
  978. emit appendToLog(qstrErrorMsg);
  979. // --------------------------------
  980. default: // Nym has X usage credits remaining, or server isn't enforcing credits.
  981. break;
  982. }
  983. // --------------------------------
  984. return lReturnValue;
  985. }
  986. int64_t Moneychanger::HasUsageCredits(QString notary_id,
  987. QString NYM_ID)
  988. {
  989. const std::string str_server(notary_id.toStdString());
  990. const std::string str_nym (NYM_ID .toStdString());
  991. return HasUsageCredits(str_server, str_nym);
  992. }
  993. // ---------------------------------------------------------------
  994. /**
  995. * Systray
  996. **/
  997. // Startup
  998. void Moneychanger::bootTray()
  999. {
  1000. connect(this, SIGNAL(appendToLog(QString)), this, SLOT(mc_showlog_slot(QString)));
  1001. connect(this, SIGNAL(expertModeUpdated(bool)), this, SLOT(onExpertModeUpdated(bool)));
  1002. connect(this, SIGNAL(needToCheckNym(QString,QString,QString)), this, SLOT(onNeedToCheckNym(QString,QString,QString)));
  1003. connect(this, SIGNAL(nymWasJustChecked(QString)), this, SLOT(onCheckNym(QString)));
  1004. connect(this, SIGNAL(serversChanged()), this, SLOT(onServersChanged()));
  1005. connect(this, SIGNAL(assetsChanged()), this, SLOT(onAssetsChanged()));
  1006. // connect(this, SIGNAL(needToPopulateRecordlist()), this, SLOT(onNeedToPopulateRecordlist()));
  1007. connect(this, SIGNAL(needToUpdateMenu()), this, SLOT(onNeedToUpdateMenu()));
  1008. // connect(this, SIGNAL(updateMenuAndPopulateRecords()), this, SLOT(onNeedToUpdateMenu()));
  1009. // connect(this, SIGNAL(updateMenuAndPopulateRecords()), this, SLOT(onNeedToPopulateRecordlist()));
  1010. connect(this, SIGNAL(newServerAdded(QString)), this, SLOT(onNewServerAdded(QString)));
  1011. connect(this, SIGNAL(newAssetAdded(QString)), this, SLOT(onNewAssetAdded(QString)));
  1012. // ----------------------------------------------------------------------------
  1013. connect(this, SIGNAL(serversChanged()), this, SIGNAL(updateMenuAndPopulateRecords()));
  1014. connect(this, SIGNAL(assetsChanged()), this, SIGNAL(updateMenuAndPopulateRecords()));
  1015. connect(this, SIGNAL(newServerAdded(QString)), this, SIGNAL(updateMenuAndPopulateRecords()));
  1016. connect(this, SIGNAL(newAssetAdded(QString)), this, SIGNAL(updateMenuAndPopulateRecords()));
  1017. // ----------------------------------------------------------------------------
  1018. connect(this, SIGNAL(newNymAdded(QString)), this, SLOT(onNewNymAdded(QString)));
  1019. // ----------------------------------------------------------------------------
  1020. //Show systray
  1021. mc_systrayIcon->show();
  1022. // ----------------------------------------------------------------------------
  1023. SetupMainMenu();
  1024. // ----------------------------------------------------------------------------
  1025. QString qstrMenuFileExists = QString(opentxs::OTPaths::AppDataFolder().Get()) + QString("/knotworkpigeons");
  1026. if (QFile::exists(qstrMenuFileExists))
  1027. mc_main_menu_dialog();
  1028. // ----------------------------------------------------------------------------
  1029. if (!hideNav())
  1030. mc_activity_dialog();
  1031. // ----------------------------------------------------------------------------
  1032. if (!hasNyms()) {
  1033. std::string strSource(""), strMyName("Me");
  1034. // --------------------------------------
  1035. MTGetStringDialog nameDlg(this, tr("Creating your Nym. "
  1036. "Enter your display name (that others will see)"));
  1037. bool bNameEmpty{true};
  1038. if (QDialog::Accepted == nameDlg.exec())
  1039. {
  1040. const QString qstrNewMyName = nameDlg.GetOutputString();
  1041. if (!qstrNewMyName.isEmpty()) {
  1042. bNameEmpty = false;
  1043. strMyName = qstrNewMyName.toStdString();
  1044. }
  1045. }
  1046. // --------------------------------------------------
  1047. if (bNameEmpty) {
  1048. QString name;
  1049. name = qgetenv("USER"); // get the user name in Linux
  1050. if (!name.isEmpty()) {
  1051. bNameEmpty = false;
  1052. strMyName = name.toStdString();
  1053. }
  1054. else {
  1055. name = qgetenv("USERNAME"); // get the name in Windows
  1056. }
  1057. if (!name.isEmpty()) {
  1058. bNameEmpty = false;
  1059. strMyName = name.toStdString();
  1060. }
  1061. }
  1062. // --------------------------------------------------
  1063. std::string str_id = ot_.Exec().CreateNymHD(
  1064. opentxs::proto::CITEMTYPE_INDIVIDUAL, strMyName, strSource, 0);
  1065. if (!str_id.empty())
  1066. {
  1067. setDefaultNym(QString::fromStdString(str_id), QString::fromStdString(strMyName));
  1068. //DBHandler::getInstance()->AddressBookUpdateDefaultNym(QString::fromStdString(newNymId));
  1069. // -----------------------------------------------------------------------------------
  1070. SetupMainMenu(); // Since we just created a new default nym since setting up the menu.
  1071. const QString qstrNymId = QString::fromStdString(str_id);
  1072. // mc_nymmanager_dialog(qstrNymId);
  1073. emit newNymAdded(qstrNymId);
  1074. }
  1075. }
  1076. // ----------------------------------------------------------------------------
  1077. // bool bEnoughForNow = false;
  1078. // if (ot_.Exec().GetAssetTypeCount() <= 0) {
  1079. // mc_assetmanager_dialog();
  1080. // bEnoughForNow = true;
  1081. // }
  1082. // else if (ot_.Exec().GetServerCount() <= 0) {
  1083. // mc_servermanager_dialog();
  1084. // bEnoughForNow = true;
  1085. // }
  1086. // // ----------------------------------------------------------------------------
  1087. // if (!bEnoughForNow) {
  1088. // if (ot_.Exec().GetAccountCount() <= 0)
  1089. // mc_accountmanager_dialog();
  1090. // else
  1091. // mc_payments_dialog();
  1092. // }
  1093. // ----------------------------------------------------------------------------
  1094. }
  1095. // Shutdown
  1096. void Moneychanger::mc_shutdown_slot()
  1097. {
  1098. //Disconnect all signals from callin class (probubly main) to this class
  1099. //Disconnect
  1100. QObject::disconnect(this);
  1101. qApp->quit();
  1102. }
  1103. // End Systray
  1104. // ---------------------------------------------------------------
  1105. void Moneychanger::SetupMainMenu()
  1106. {
  1107. if (!mc_overall_init)
  1108. return;
  1109. // --------------------------------------------------
  1110. if (asset_list_id)
  1111. {
  1112. delete asset_list_id;
  1113. asset_list_id = nullptr;
  1114. }
  1115. if (asset_list_name)
  1116. {
  1117. delete asset_list_name;
  1118. asset_list_name = nullptr;
  1119. }
  1120. // --------------------------------------------------
  1121. if (server_list_id)
  1122. {
  1123. delete server_list_id;
  1124. server_list_id = nullptr;
  1125. }
  1126. if (server_list_name)
  1127. {
  1128. delete server_list_name;
  1129. server_list_name = nullptr;
  1130. }
  1131. // --------------------------------------------------
  1132. if (nym_list_id)
  1133. {
  1134. delete nym_list_id;
  1135. nym_list_id = nullptr;
  1136. }
  1137. if (nym_list_name)
  1138. {
  1139. delete nym_list_name;
  1140. nym_list_name = nullptr;
  1141. }
  1142. // --------------------------------------------------
  1143. if (account_list_id)
  1144. {
  1145. delete account_list_id;
  1146. account_list_id = nullptr;
  1147. }
  1148. if (account_list_name)
  1149. {
  1150. delete account_list_name;
  1151. account_list_name = nullptr;
  1152. }
  1153. // --------------------------------------------------
  1154. // --------------------------------------------------------------
  1155. if (mc_systrayMenu)
  1156. {
  1157. mc_systrayMenu->setParent(nullptr);
  1158. mc_systrayMenu->disconnect();
  1159. mc_systrayMenu->deleteLater();
  1160. mc_systrayMenu = nullptr;
  1161. }
  1162. // --------------------------------------------------------------
  1163. //MC System tray menu
  1164. //
  1165. mc_systrayMenu = new QMenu(this);
  1166. //Init Skeleton of system tray menu
  1167. //App name
  1168. // mc_systrayMenu_headertext = new QAction(tr(MONEYCHANGER_APP_NAME), mc_systrayMenu);
  1169. // mc_systrayMenu_headertext->setDisabled(1);
  1170. // mc_systrayMenu->addAction(mc_systrayMenu_headertext);
  1171. // --------------------------------------------------------------
  1172. if (hasNyms() &&
  1173. ot_.Exec().GetServerCount() > 0 &&
  1174. ot_.Exec().GetAssetTypeCount() > 0)
  1175. SetupAccountMenu(mc_systrayMenu);
  1176. SetupNymMenu(mc_systrayMenu);
  1177. // --------------------------------------------------------------
  1178. mc_systrayMenu->addSeparator();
  1179. // --------------------------------------------------------------
  1180. // if (hasAccounts())
  1181. // SetupPaymentsMenu(mc_systrayMenu);
  1182. if (expertMode() && hasNyms())
  1183. SetupMessagingMenu(mc_systrayMenu);
  1184. // --------------------------------------------------------------
  1185. //mc_systrayMenu->addSeparator();
  1186. // --------------------------------------------------------------
  1187. //Passphrase Manager
  1188. if (expertMode())
  1189. {
  1190. mc_systrayMenu_passphrase_manager = new QAction(mc_systrayIcon_crypto, tr("Secrets"), mc_systrayMenu);
  1191. mc_systrayMenu->addAction(mc_systrayMenu_passphrase_manager);
  1192. connect(mc_systrayMenu_passphrase_manager, SIGNAL(triggered()), this, SLOT(mc_passphrase_manager_slot()));
  1193. // --------------------------------------------------------------
  1194. mc_systrayMenu->addSeparator();
  1195. }
  1196. // --------------------------------------------------------------
  1197. //Blank
  1198. // mc_systrayMenu_aboveBlank = new QAction(" ", 0);
  1199. // mc_systrayMenu_aboveBlank->setDisabled(1);
  1200. // mc_systrayMenu->addAction(mc_systrayMenu_aboveBlank);
  1201. // --------------------------------------------------------------
  1202. if (expertMode() && hasAccounts())
  1203. {
  1204. SetupExchangeMenu(mc_systrayMenu);
  1205. mc_systrayMenu->addSeparator();
  1206. }
  1207. // --------------------------------------------------------------
  1208. // if (expertMode())
  1209. {
  1210. SetupContractsMenu(mc_systrayMenu);
  1211. mc_systrayMenu->addSeparator();
  1212. }
  1213. // --------------------------------------------------------------
  1214. if (expertMode() && hasNyms())
  1215. {
  1216. SetupToolsMenu(mc_systrayMenu);
  1217. mc_systrayMenu->addSeparator();
  1218. }
  1219. // --------------------------------------------------------------
  1220. //Company
  1221. // mc_systrayMenu_company = new QMenu("Company", 0);
  1222. // mc_systrayMenu->addMenu(mc_systrayMenu_company);
  1223. // --------------------------------------------------------------
  1224. // :/icons/icons/lock.png
  1225. //
  1226. // QPointer<QAction> mc_systrayMenu_crypto_encrypt;
  1227. // QPointer<QAction> mc_systrayMenu_crypto_decrypt;
  1228. // QPointer<QAction> mc_systrayMenu_crypto_sign;
  1229. // QPointer<QAction> mc_systrayMenu_crypto_verify;
  1230. // --------------------------------------------------------------
  1231. // Settings
  1232. mc_systrayMenu_settings = new QAction(mc_systrayIcon_settings, tr("Settings"), mc_systrayMenu);
  1233. mc_systrayMenu_settings->setMenuRole(QAction::NoRole);
  1234. mc_systrayMenu->addAction(mc_systrayMenu_settings);
  1235. connect(mc_systrayMenu_settings, SIGNAL(triggered()), this, SLOT(mc_settings_slot()));
  1236. // --------------------------------------------------------------
  1237. mc_systrayMenu->addSeparator();
  1238. // --------------------------------------------------------------
  1239. //Advanced submenu
  1240. SetupAdvancedMenu(mc_systrayMenu);
  1241. // --------------------------------------------------------------
  1242. SetupExperimentalMenu(mc_systrayMenu);
  1243. // --------------------------------------------------------------
  1244. // TODO: If the default isn't set, then choose the first one and select it.
  1245. // TODO: If there isn't even ONE to select, then this menu item should say "Create Nym..." with no sub-menu.
  1246. // TODO: When booting up, if there is already a default server and asset id, but no nyms exist, create a default nym.
  1247. // TODO: When booting up, if there is already a default nym, but no accounts exist, create a default account.
  1248. // --------------------------------------------------------------
  1249. //Separator
  1250. mc_systrayMenu->addSeparator();
  1251. // --------------------------------------------------------------
  1252. //Shutdown Moneychanger
  1253. mc_systrayMenu_shutdown = new QAction(mc_systrayIcon_shutdown, tr("Quit"), mc_systrayMenu);
  1254. mc_systrayMenu_shutdown->setMenuRole(QAction::NoRole);
  1255. mc_systrayMenu_shutdown->setIcon(mc_systrayIcon_shutdown);
  1256. mc_systrayMenu->addAction(mc_systrayMenu_shutdown);
  1257. connect(mc_systrayMenu_shutdown, SIGNAL(triggered()), this, SLOT(mc_shutdown_slot()));
  1258. // --------------------------------------------------------------
  1259. //Blank
  1260. // mc_systrayMenu_bottomblank = new QAction(" ", 0);
  1261. // mc_systrayMenu_bottomblank->setDisabled(1);
  1262. // mc_systrayMenu->addAction(mc_systrayMenu_bottomblank);
  1263. // --------------------------------------------------------------
  1264. //Set Skeleton to systrayIcon object code
  1265. //
  1266. mc_systrayIcon->setContextMenu(mc_systrayMenu);
  1267. }
  1268. bool Moneychanger::hasAccounts() const
  1269. {
  1270. return (!default_account_id.isEmpty() ||
  1271. (ot_.Storage().AccountList().size() > 0));
  1272. }
  1273. bool Moneychanger::hasNyms() const
  1274. {
  1275. return (!default_nym_id.isEmpty() ||
  1276. (ot_.Exec().GetNymCount() > 0));
  1277. }
  1278. //bool Moneychanger::financeMode() const
  1279. //{
  1280. // // NOTE: We don't even bother to show financial stuff
  1281. // // on the menu, if you have zero Nyms.
  1282. // //
  1283. // return (!default_account_id.isEmpty() ||
  1284. // !default_nym_id .isEmpty() ||
  1285. // (ot_.Exec().GetNymCount() > 0));
  1286. //}
  1287. void Moneychanger::SetupAssetMenu(QPointer<QMenu> & parent_menu)
  1288. {
  1289. if (default_asset_id.isEmpty() && (ot_.Exec().GetAssetTypeCount() > 0))
  1290. {
  1291. default_asset_id = QString::fromStdString(ot_.Exec().GetAssetType_ID(0));
  1292. }
  1293. // -------------------------------------------------
  1294. if (ot_.Exec().GetAssetTypeCount() <= 0)
  1295. {
  1296. // if (mc_systrayMenu_asset)
  1297. // mc_systrayMenu_asset->disconnect();
  1298. // mc_systrayMenu_asset = nullptr;
  1299. QAction * manage_assets = new QAction(tr("Add asset contract..."), parent_menu);
  1300. parent_menu->addAction(manage_assets);
  1301. connect(manage_assets, SIGNAL(triggered()), this, SLOT(mc_defaultasset_slot()));
  1302. return;
  1303. }
  1304. // -------------------------------------------------
  1305. QPointer<QMenu> & current_menu = mc_systrayMenu_asset;
  1306. // -------------------------------------------------
  1307. current_menu = new QMenu(tr("Set default asset..."), parent_menu);
  1308. current_menu->setIcon(mc_systrayIcon_purse);
  1309. parent_menu->addMenu(current_menu);
  1310. // --------------------------------------------------
  1311. //Add a "Manage asset types" action button (and connection)
  1312. QAction * manage_assets = new QAction(tr("Manage asset contracts..."), current_menu);
  1313. manage_assets->setData(QVariant(QString("openmanager")));
  1314. current_menu->addAction(manage_assets);
  1315. connect(current_menu, SIGNAL(triggered(QAction*)), this, SLOT(mc_assetselection_triggered(QAction*)));
  1316. // -------------------------------------------------
  1317. current_menu->addSeparator();
  1318. // -------------------------------------------------
  1319. if (!default_asset_id.isEmpty())
  1320. {
  1321. default_asset_name = QString::fromStdString(ot_.Exec().GetAssetType_Name(default_asset_id.toStdString()));
  1322. }
  1323. // -------------------------------------------------
  1324. //Load "default" asset type
  1325. //Init asset submenu
  1326. asset_list_id = new QList<QVariant>;
  1327. asset_list_name = new QList<QVariant>;
  1328. // ------------------------------------------
  1329. int32_t asset_count = ot_.Exec().GetAssetTypeCount();
  1330. for (int aa = 0; aa < asset_count; aa++)
  1331. {
  1332. QString OT_asset_id = QString::fromStdString(ot_.Exec().GetAssetType_ID(aa));
  1333. QString OT_asset_name = QString::fromStdString(ot_.Exec().GetAssetType_Name(OT_asset_id.toStdString()));
  1334. asset_list_id ->append(QVariant(OT_asset_id));
  1335. asset_list_name->append(QVariant(OT_asset_name));
  1336. QAction * next_asset_action = new QAction(mc_systrayIcon_purse, OT_asset_name, current_menu);
  1337. next_asset_action->setData(QVariant(OT_asset_id));
  1338. next_asset_action->setCheckable(true);
  1339. if (0 == OT_asset_id.compare(default_asset_id)) {
  1340. next_asset_action->setChecked(true);
  1341. }
  1342. else {
  1343. next_asset_action->setChecked(false);
  1344. }
  1345. current_menu->addAction(next_asset_action);
  1346. }
  1347. setDefaultAsset(default_asset_id, default_asset_name);
  1348. }
  1349. void Moneychanger::SetupServerMenu(QPointer<QMenu> & parent_menu)
  1350. {
  1351. if (default_notary_id.isEmpty() && (ot_.Exec().GetServerCount() > 0))
  1352. {
  1353. default_notary_id = QString::fromStdString(ot_.Exec().GetServer_ID(0));
  1354. }
  1355. // -------------------------------------------------
  1356. if (ot_.Exec().GetServerCount() <= 0)
  1357. {
  1358. // if (mc_systrayMenu_server)
  1359. // mc_systrayMenu_server->disconnect();
  1360. // mc_systrayMenu_server = nullptr;
  1361. QAction * manage_servers = new QAction(tr("Add server contract..."), parent_menu);
  1362. parent_menu->addAction(manage_servers);
  1363. connect(manage_servers, SIGNAL(triggered()), this, SLOT(mc_defaultserver_slot()));
  1364. return;
  1365. }
  1366. // -------------------------------------------------
  1367. QPointer<QMenu> & current_menu = mc_systrayMenu_server;
  1368. // -------------------------------------------------
  1369. current_menu = new QMenu(tr("Set default server..."), parent_menu);
  1370. current_menu->setIcon(mc_systrayIcon_server);
  1371. parent_menu->addMenu(current_menu);
  1372. // --------------------------------------------------
  1373. //Add a "Manage Servers" action button (and connection)
  1374. QAction * manage_servers = new QAction(tr("Manage Server Contracts..."), current_menu);
  1375. manage_servers->setData(QVariant(QString("openmanager")));
  1376. current_menu->addAction(manage_servers);
  1377. connect(current_menu, SIGNAL(triggered(QAction*)), this, SLOT(mc_serverselection_triggered(QAction*)));
  1378. // -------------------------------------------------
  1379. current_menu->addSeparator();
  1380. // -------------------------------------------------
  1381. //Ask OT what the display name of this server is and store it for a quick retrieval later on(mostly for "Default Server" displaying purposes)
  1382. if (!default_notary_id.isEmpty())
  1383. {
  1384. default_server_name = QString::fromStdString(ot_.Exec().GetServer_Name(default_notary_id.toStdString()));
  1385. }
  1386. // -------------------------------------------------
  1387. //Load "default" server
  1388. //Init server submenu
  1389. server_list_id = new QList<QVariant>;
  1390. server_list_name = new QList<QVariant>;
  1391. // ------------------------------------------
  1392. int32_t server_count = ot_.Exec().GetServerCount();
  1393. for (int32_t aa = 0; aa < server_count; aa++)
  1394. {
  1395. QString OT_notary_id = QString::fromStdString(ot_.Exec().GetServer_ID(aa));
  1396. QString OT_server_name = QString::fromStdString(ot_.Exec().GetServer_Name(OT_notary_id.toStdString()));
  1397. server_list_id ->append(QVariant(OT_notary_id));
  1398. server_list_name->append(QVariant(OT_server_name));
  1399. //Append to submenu of server
  1400. QAction * next_server_action = new QAction(mc_systrayIcon_server, OT_server_name, current_menu);
  1401. next_server_action->setData(QVariant(OT_notary_id));
  1402. next_server_action->setCheckable(true);
  1403. if (0 == OT_notary_id.compare(default_notary_id)) {
  1404. next_server_action->setChecked(true);
  1405. }
  1406. else {
  1407. next_server_action->setChecked(false);
  1408. }
  1409. current_menu->addAction(next_server_action);
  1410. }
  1411. setDefaultServer(default_notary_id, default_server_name);
  1412. }
  1413. void Moneychanger::SetupNymMenu(QPointer<QMenu> & parent_menu)
  1414. {
  1415. // -------------------------------------------------
  1416. if (default_nym_id.isEmpty() && (ot_.Exec().GetNymCount() > 0))
  1417. {
  1418. default_nym_id = QString::fromStdString(ot_.Exec().GetNym_ID(0));
  1419. }
  1420. // -------------------------------------------------
  1421. if (!hasNyms())
  1422. {
  1423. // if (mc_systrayMenu_nym)
  1424. // mc_systrayMenu_nym->disconnect();
  1425. // mc_systrayMenu_nym = nullptr;
  1426. QAction * manage_nyms = new QAction(tr("Create my identity..."), parent_menu);
  1427. parent_menu->addAction(manage_nyms);
  1428. connect(manage_nyms, SIGNAL(triggered()), this, SLOT(mc_defaultnym_slot()));
  1429. return;
  1430. }
  1431. // -------------------------------------------------
  1432. QPointer<QMenu> & current_menu = mc_systrayMenu_nym;
  1433. // -------------------------------------------------
  1434. current_menu = new QMenu("Set default identity...", parent_menu);
  1435. current_menu->setIcon(mc_systrayIcon_nym);
  1436. parent_menu->addMenu(current_menu);
  1437. //Add a "Manage pseudonym" action button (and connection)
  1438. QAction * manage_nyms = new QAction(tr("My identities..."), current_menu);
  1439. manage_nyms->setData(QVariant(QString("openmanager")));
  1440. current_menu->addAction(manage_nyms);
  1441. connect(current_menu, SIGNAL(triggered(QAction*)), this, SLOT(mc_nymselection_triggered(QAction*)));
  1442. // -------------------------------------------------
  1443. current_menu->addSeparator();
  1444. // -------------------------------------------------
  1445. //Ask OT what the display name of this nym is and store it for quick retrieval later on(mostly for "Default Nym" displaying purposes)
  1446. if (!default_nym_id.isEmpty())
  1447. {
  1448. default_nym_name = QString::fromStdString(ot_.Exec().GetNym_Name(default_nym_id.toStdString()));
  1449. }
  1450. // -------------------------------------------------
  1451. //Init nym submenu
  1452. nym_list_id = new QList<QVariant>;
  1453. nym_list_name = new QList<QVariant>;
  1454. // --------------------------------------------------------
  1455. //Count nyms
  1456. int32_t nym_count = ot_.Exec().GetNymCount();
  1457. //Add/append to the id + name lists
  1458. for (int32_t a = 0; a < nym_count; a++)
  1459. {
  1460. QString OT_nym_id = QString::fromStdString(ot_.Exec().GetNym_ID(a));
  1461. QString OT_nym_name = QString::fromStdString(ot_.Exec().GetNym_Name(OT_nym_id.toStdString()));
  1462. nym_list_id ->append(QVariant(OT_nym_id));
  1463. nym_list_name->append(QVariant(OT_nym_name));
  1464. //Append to submenu of nym
  1465. QAction * next_nym_action = new QAction(mc_systrayIcon_nym, OT_nym_name, current_menu);
  1466. next_nym_action->setData(QVariant(OT_nym_id));
  1467. next_nym_action->setCheckable(true);
  1468. if (0 == OT_nym_id.compare(default_nym_id)) {
  1469. next_nym_action->setChecked(true);
  1470. }
  1471. else {
  1472. next_nym_action->setChecked(false);
  1473. }
  1474. current_menu->addAction(next_nym_action);
  1475. } // for
  1476. // -------------------------------------------------
  1477. setDefaultNym(default_nym_id, default_nym_name);
  1478. }
  1479. void Moneychanger::SetupPaymentsMenu(QPointer<QMenu> & parent_menu)
  1480. {
  1481. // -------------------------------------------------
  1482. QPointer<QMenu> & current_menu = mc_systrayMenu_payments;
  1483. // -------------------------------------------------
  1484. current_menu = new QMenu(tr("Payments"), parent_menu);
  1485. current_menu->setIcon(mc_systrayIcon_sendfunds);
  1486. parent_menu->addMenu(current_menu);
  1487. // --------------------------------------------------------------
  1488. //Send funds
  1489. mc_systrayMenu_sendfunds = new QAction(mc_systrayIcon_sendfunds, tr("Pay Funds..."), current_menu);
  1490. current_menu->addAction(mc_systrayMenu_sendfunds);
  1491. connect(mc_systrayMenu_sendfunds, SIGNAL(triggered()), this, SLOT(mc_sendfunds_slot()));
  1492. // -------------------------------------------------
  1493. current_menu->addSeparator();
  1494. // -------------------------------------------------
  1495. //Payment History
  1496. mc_systrayMenu_receipts = new QAction(mc_systrayIcon_overview, tr("Payment History"), current_menu);
  1497. current_menu->addAction(mc_systrayMenu_receipts);
  1498. connect(mc_systrayMenu_receipts, SIGNAL(triggered()), this, SLOT(mc_payments_slot()));
  1499. // --------------------------------------------------------------
  1500. //Pending Transactions
  1501. mc_systrayMenu_overview = new QAction(mc_systrayIcon_pending, tr("Pending Transactions"), current_menu);
  1502. current_menu->addAction(mc_systrayMenu_overview);
  1503. connect(mc_systrayMenu_overview, SIGNAL(triggered()), this, SLOT(mc_overview_slot()));
  1504. // --------------------------------------------------------------
  1505. //Live Agreements
  1506. if (bExpertMode_)
  1507. {
  1508. mc_systrayMenu_agreements = new QAction(mc_systrayIcon_active_agreements, tr("Active Agreements"), current_menu);
  1509. current_menu->addAction(mc_systrayMenu_agreements);
  1510. connect(mc_systrayMenu_agreements, SIGNAL(triggered()), this, SLOT(mc_agreements_slot()));
  1511. }
  1512. // -------------------------------------------------
  1513. current_menu->addSeparator();
  1514. // -------------------------------------------------
  1515. //Request payment
  1516. mc_systrayMenu_requestfunds = new QAction(mc_systrayIcon_requestfunds, tr("Request Payment..."), current_menu);
  1517. current_menu->addAction(mc_systrayMenu_requestfunds);
  1518. connect(mc_systrayMenu_requestfunds, SIGNAL(triggered()), this, SLOT(mc_requestfunds_slot()));
  1519. // --------------------------------------------------------------
  1520. if (bExpertMode_)
  1521. {
  1522. mc_systrayMenu_proposeplan = new QAction(mc_systrayIcon_proposeplan, tr("Recurring Payment..."), current_menu);
  1523. current_menu->addAction(mc_systrayMenu_proposeplan);
  1524. connect(mc_systrayMenu_proposeplan, SIGNAL(triggered()), this, SLOT(mc_proposeplan_slot()));
  1525. // -------------------------------------------------
  1526. mc_systrayMenu_import_cash = new QAction(mc_systrayIcon_advanced_import, tr("Import Cash..."), current_menu);
  1527. current_menu->addAction(mc_systrayMenu_import_cash);
  1528. connect(mc_systrayMenu_import_cash, SIGNAL(triggered()), this, SLOT(mc_import_slot()));
  1529. }
  1530. }
  1531. // --------------------------------------------------------------
  1532. void Moneychanger::SetupExchangeMenu(QPointer<QMenu> & parent_menu)
  1533. {
  1534. // -------------------------------------------------
  1535. QPointer<QMenu> & current_menu = mc_systrayMenu_exchange;
  1536. // -------------------------------------------------
  1537. current_menu = new QMenu(tr("Exchange"), parent_menu);
  1538. current_menu->setIcon(mc_systrayIcon_markets);
  1539. parent_menu->addMenu(current_menu);
  1540. // --------------------------------------------------------------
  1541. mc_systrayMenu_markets = new QAction(mc_systrayIcon_markets, tr("Live Offers"), current_menu);
  1542. current_menu->addAction(mc_systrayMenu_markets);
  1543. connect(mc_systrayMenu_markets, SIGNAL(triggered()), this, SLOT(mc_market_slot()));
  1544. // --------------------------------------------------------------
  1545. mc_systrayMenu_trade_archive = new QAction(mc_systrayIcon_trade_archive, tr("Historical Trades"), mc_systrayMenu_exchange);
  1546. mc_systrayMenu_exchange->addAction(mc_systrayMenu_trade_archive);
  1547. connect(mc_systrayMenu_trade_archive, SIGNAL(triggered()), this, SLOT(mc_trade_archive_slot()));
  1548. }
  1549. void Moneychanger::SetupContractsMenu(QPointer<QMenu> & parent_menu)
  1550. {
  1551. QPointer<QMenu> & current_menu = mc_systrayMenu_contracts;
  1552. // -------------------------------------------------
  1553. current_menu = new QMenu(tr("Contracts"), parent_menu);
  1554. current_menu->setIcon(mc_systrayIcon_active_agreements);
  1555. parent_menu->addMenu(current_menu);
  1556. // --------------------------------------------------------------
  1557. SetupAssetMenu(current_menu);
  1558. SetupServerMenu(current_menu);
  1559. // -------------------------------------------------
  1560. current_menu->addSeparator();
  1561. // -------------------------------------------------
  1562. if (bExpertMode_)
  1563. {
  1564. mc_systrayMenu_smart_contracts = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Smart Contract Editor"), current_menu);
  1565. current_menu->addAction(mc_systrayMenu_smart_contracts);
  1566. connect(mc_systrayMenu_smart_contracts, SIGNAL(triggered()), this, SLOT(mc_smartcontract_slot()));
  1567. }
  1568. }
  1569. void Moneychanger::SetupAdvancedMenu(QPointer<QMenu> & parent_menu)
  1570. {
  1571. if (bExpertMode_)
  1572. return;
  1573. // -------------------------------------------------
  1574. QPointer<QMenu> & current_menu = mc_systrayMenu_advanced;
  1575. // -------------------------------------------------
  1576. current_menu = new QMenu(tr("Advanced"), parent_menu);
  1577. current_menu->setIcon(mc_systrayIcon_active_agreements);
  1578. parent_menu->addMenu(current_menu);
  1579. // --------------------------------------------------------------
  1580. // SetupContractsMenu(current_menu);
  1581. // --------------------------------------------------------------
  1582. if (hasNyms())
  1583. {
  1584. SetupToolsMenu(current_menu);
  1585. }
  1586. // --------------------------------------------------------------
  1587. current_menu->addSeparator();
  1588. // --------------------------------------------------------------
  1589. if (bExpertMode_ && hasNyms())
  1590. {
  1591. mc_systrayMenu_smart_contracts = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Smart Contract Editor"), current_menu);
  1592. current_menu->addAction(mc_systrayMenu_smart_contracts);
  1593. connect(mc_systrayMenu_smart_contracts, SIGNAL(triggered()), this, SLOT(mc_smartcontract_slot()));
  1594. // --------------------------------------------------------------
  1595. current_menu->addSeparator();
  1596. }
  1597. // --------------------------------------------------------------
  1598. // Basic mode doesn't show the cash purse on the account details page.
  1599. // So what's the point of importing cash, when you then can't see it in the
  1600. // cash purse? It would just be confusing.
  1601. // Therefore, if you cannot see the cash purse, neither can you import cash.
  1602. // Put yourself in expert mode if you want to do that stuff.
  1603. //
  1604. // if (hasAccounts())
  1605. // {
  1606. // // --------------------------------------------------------------
  1607. // mc_systrayMenu_import_cash = new QAction(mc_systrayIcon_advanced_import, tr("Import Cash..."), current_menu);
  1608. // current_menu->addAction(mc_systrayMenu_import_cash);
  1609. // connect(mc_systrayMenu_import_cash, SIGNAL(triggered()), this, SLOT(mc_import_slot()));
  1610. // // --------------------------------------------------------------
  1611. // current_menu->addSeparator();
  1612. // }
  1613. // -------------------------------------------------
  1614. current_menu->addSeparator();
  1615. // -------------------------------------------------
  1616. mc_systrayMenu_pair_node = new QAction(mc_systrayIcon_advanced_corporations, tr("Pair Stash Node"), current_menu);
  1617. current_menu->addAction(mc_systrayMenu_pair_node);
  1618. connect(mc_systrayMenu_pair_node, SIGNAL(triggered()), this, SLOT(mc_pair_node_slot()));
  1619. // --------------------------------------------------------------
  1620. //Separator
  1621. current_menu->addSeparator();
  1622. // --------------------------------------------------------------
  1623. // Transport
  1624. if (bExpertMode_) {
  1625. mc_systrayMenu_p2p_transport = new QAction(mc_systrayIcon_advanced_transport, tr("P2P Transport"), current_menu);
  1626. current_menu->addAction(mc_systrayMenu_p2p_transport);
  1627. connect(mc_systrayMenu_p2p_transport, SIGNAL(triggered()), this, SLOT(mc_transport_slot()));
  1628. }
  1629. // --------------------------------------------------------------
  1630. // Error Log
  1631. mc_systrayMenu_error_log = new QAction(mc_systrayIcon_overview, tr("Error Log"), current_menu);
  1632. current_menu->addAction(mc_systrayMenu_error_log);
  1633. connect(mc_systrayMenu_error_log, SIGNAL(triggered()), this, SLOT(mc_log_slot()));
  1634. }
  1635. void Moneychanger::SetupExperimentalMenu(QPointer<QMenu> & parent_menu)
  1636. {
  1637. if (!bExpertMode_)
  1638. return;
  1639. // -------------------------------------------------
  1640. QPointer<QMenu> & current_menu = mc_systrayMenu_experimental;
  1641. // -------------------------------------------------
  1642. //Experimental
  1643. current_menu = new QMenu(tr("Experimental"), parent_menu);
  1644. current_menu->setIcon(mc_systrayIcon_advanced);
  1645. parent_menu->addMenu(current_menu);
  1646. // --------------------------------------------------------------
  1647. // Corporations
  1648. mc_systrayMenu_corporations = new QAction(mc_systrayIcon_advanced_corporations, tr("Corporations"), current_menu);
  1649. current_menu->addAction(mc_systrayMenu_corporations);
  1650. connect(mc_systrayMenu_corporations, SIGNAL(triggered()), this, SLOT(mc_corporation_slot()));
  1651. // -------------------------------------------------
  1652. current_menu->addSeparator();
  1653. // -------------------------------------------------
  1654. mc_systrayMenu_pair_node = new QAction(mc_systrayIcon_advanced_corporations, tr("Pair Stash Node"), current_menu);
  1655. current_menu->addAction(mc_systrayMenu_pair_node);
  1656. connect(mc_systrayMenu_pair_node, SIGNAL(triggered()), this, SLOT(mc_pair_node_slot()));
  1657. // --------------------------------------------------------------
  1658. //Separator
  1659. // current_menu->addSeparator();
  1660. // --------------------------------------------------------------
  1661. // Corporations submenu
  1662. // mc_systrayMenu_company_create = new QMenu(tr("Create"), 0);
  1663. // mc_systrayMenu_corporations->addMenu(mc_systrayMenu_company_create);
  1664. // // Create insurance company action on submenu
  1665. // mc_systrayMenu_company_create_insurance = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Insurance Company"), 0);
  1666. // mc_systrayMenu_company_create->addAction(mc_systrayMenu_company_create_insurance);
  1667. // connect(mc_systrayMenu_company_create_insurance, SIGNAL(triggered()), this, SLOT(mc_createinsurancecompany_slot()));
  1668. // --------------------------------------------------------------
  1669. // Bazaar
  1670. // mc_systrayMenu_bazaar = new QMenu(tr("Bazaar"), current_menu);
  1671. // current_menu->addMenu(mc_systrayMenu_bazaar);
  1672. //
  1673. // // Bazaar actions
  1674. // mc_systrayMenu_bazaar_search = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Search Listings"), mc_systrayMenu_bazaar);
  1675. // mc_systrayMenu_bazaar->addAction(mc_systrayMenu_bazaar_search);
  1676. //// connect(mc_systrayMenu_bazaar_search, SIGNAL(triggered()), this, SLOT(mc_bazaar_search_slot()));
  1677. //
  1678. // mc_systrayMenu_bazaar_post = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Post an Ad"), mc_systrayMenu_bazaar);
  1679. // mc_systrayMenu_bazaar->addAction(mc_systrayMenu_bazaar_post);
  1680. //// connect(mc_systrayMenu_bazaar_post, SIGNAL(triggered()), this, SLOT(mc_bazaar_search_slot()));
  1681. //
  1682. // mc_systrayMenu_bazaar_orders = new QAction(mc_systrayIcon_advanced_smartcontracts, tr("Orders"), mc_systrayMenu_bazaar);
  1683. // mc_systrayMenu_bazaar->addAction(mc_systrayMenu_bazaar_orders);
  1684. //// connect(mc_systrayMenu_bazaar_orders, SIGNAL(triggered()), this, SLOT(mc_bazaar_search_slot()));
  1685. // -------------------------------------------------
  1686. // current_menu->addSeparator();
  1687. // -------------------------------------------------
  1688. // Bitcoin
  1689. // mc_systrayMenu_bitcoin = new QMenu(tr("Bitcoin"), current_menu);
  1690. // mc_systrayMenu_bitcoin->setIcon(mc_systrayIcon_bitcoin);
  1691. //
  1692. // current_menu->addMenu(mc_systrayMenu_bitcoin);
  1693. //
  1694. // mc_systrayMenu_bitcoin_test = new QAction(tr("Test"), mc_systrayMenu_bitcoin);
  1695. // mc_systrayMenu_bitcoin_connect = new QAction(tr("Connect to wallet"), mc_systrayMenu_bitcoin);
  1696. // mc_systrayMenu_bitcoin_pools = new QAction(tr("Pools"), mc_systrayMenu_bitcoin);
  1697. // mc_systrayMenu_bitcoin_transactions = new QAction(tr("Transactions"), mc_systrayMenu_bitcoin);
  1698. // mc_systrayMenu_bitcoin_send = new QAction(tr("Send"), mc_systrayMenu_bitcoin);
  1699. // mc_systrayMenu_bitcoin_receive = new QAction(tr("Receive"), mc_systrayMenu_bitcoin);
  1700. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_connect);
  1701. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_send);
  1702. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_receive);
  1703. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_transactions);
  1704. // mc_systrayMenu_bitcoin->addSeparator();
  1705. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_test);
  1706. // mc_systrayMenu_bitcoin->addAction(mc_systrayMenu_bitcoin_pools);
  1707. // connect(mc_systrayMenu_bitcoin_test, SIGNAL(triggered()), this, SLOT(mc_bitcoin_slot()));
  1708. // connect(mc_systrayMenu_bitcoin_connect, SIGNAL(triggered()), this, SLOT(mc_bitcoin_connect_slot()));
  1709. // connect(mc_systrayMenu_bitcoin_pools, SIGNAL(triggered()), this, SLOT(mc_bitcoin_pools_slot()));
  1710. // connect(mc_systrayMenu_bitcoin_transactions, SIGNAL(triggered()), this, SLOT(mc_bitcoin_transactions_slot()));
  1711. // connect(mc_systrayMenu_bitcoin_send, SIGNAL(triggered()), this, SLOT(mc_bitcoin_send_slot()));
  1712. // connect(mc_systrayMenu_bitcoin_receive, SIGNAL(triggered()), this, SLOT(mc_bitcoin_receive_slot()));
  1713. // --------------------------------------------------------------
  1714. //Separator
  1715. // current_menu->addSeparator();
  1716. }
  1717. void Moneychanger::SetupToolsMenu(QPointer<QMenu> & parent_menu)
  1718. {
  1719. // -------------------------------------------------
  1720. QPointer<QMenu> & current_menu = mc_systrayMenu_tools;
  1721. // -------------------------------------------------
  1722. current_menu = new QMenu(tr("Crypto Tools"), parent_menu);
  1723. current_menu->setIcon(mc_systrayIcon_crypto_sign);
  1724. parent_menu->addMenu(current_menu);
  1725. // --------------------------------------------------------------
  1726. mc_systrayMenu_crypto_sign = new QAction(mc_systrayIcon_crypto_sign, tr("Sign"), current_menu);
  1727. current_menu->addAction(mc_systrayMenu_crypto_sign);
  1728. connect(mc_systrayMenu_crypto_sign, SIGNAL(triggered()), this, SLOT(mc_crypto_sign_slot()));
  1729. // --------------------------------------------------------------
  1730. mc_systrayMenu_crypto_encrypt = new QAction(mc_systrayIcon_crypto_encrypt, tr("Encrypt"), current_menu);
  1731. current_menu->addAction(mc_systrayMenu_crypto_encrypt);
  1732. connect(mc_systrayMenu_crypto_encrypt, SIGNAL(triggered()), this, SLOT(mc_crypto_encrypt_slot()));
  1733. // --------------------------------------------------------------
  1734. //Separator
  1735. current_menu->addSeparator();
  1736. // --------------------------------------------------------------
  1737. mc_systrayMenu_crypto_decrypt = new QAction(mc_systrayIcon_crypto_decrypt, tr("Decrypt / Verify"), current_menu);
  1738. current_menu->addAction(mc_systrayMenu_crypto_decrypt);
  1739. connect(mc_systrayMenu_crypto_decrypt, SIGNAL(triggered()), this, SLOT(mc_crypto_decrypt_slot()));
  1740. // --------------------------------------------------------------
  1741. }
  1742. void Moneychanger::SetupMessagingMenu(QPointer<QMenu> & parent_menu)
  1743. {
  1744. // -------------------------------------------------
  1745. QPointer<QMenu> & current_menu = mc_systrayMenu_messaging;
  1746. // -------------------------------------------------
  1747. current_menu = new QMenu(tr("Messages"), parent_menu);
  1748. current_menu->setIcon(mc_systrayIcon_composemessage);
  1749. parent_menu->addMenu(current_menu);
  1750. // -------------------------------------------------
  1751. //Compose Message
  1752. mc_systrayMenu_composemessage = new QAction(mc_systrayIcon_composemessage, tr("Compose Message"), current_menu);
  1753. current_menu->addAction(mc_systrayMenu_composemessage);
  1754. connect(mc_systrayMenu_composemessage, SIGNAL(triggered()), this, SLOT(mc_composemessage_slot()));
  1755. // --------------------------------------------------------------
  1756. current_menu->addSeparator();
  1757. // --------------------------------------------------------------
  1758. //Message History
  1759. mc_systrayMenu_messages = new QAction(mc_systrayIcon_overview, tr("Message History"), current_menu);
  1760. current_menu->addAction(mc_systrayMenu_messages);
  1761. connect(mc_systrayMenu_messages, SIGNAL(triggered()), this, SLOT(mc_messages_slot()));
  1762. // --------------------------------------------------------------
  1763. //Address Book
  1764. mc_systrayMenu_contacts = new QAction(mc_systrayIcon_contacts, tr("Address Book"), current_menu);
  1765. current_menu->addAction(mc_systrayMenu_contacts);
  1766. connect(mc_systrayMenu_contacts, SIGNAL(triggered()), this, SLOT(mc_addressbook_slot()));
  1767. // --------------------------------------------------------------
  1768. current_menu->addSeparator();
  1769. // --------------------------------------------------------------
  1770. // Transport
  1771. if (bExpertMode_)
  1772. {
  1773. mc_systrayMenu_p2p_transport = new QAction(mc_systrayIcon_advanced_transport, tr("P2P Transport"), current_menu);
  1774. current_menu->addAction(mc_systrayMenu_p2p_transport);
  1775. connect(mc_systrayMenu_p2p_transport, SIGNAL(triggered()), this, SLOT(mc_transport_slot()));
  1776. // --------------------------------------------------------------
  1777. // Error Log
  1778. mc_systrayMenu_error_log = new QAction(mc_systrayIcon_overview, tr("Error Log"), current_menu);
  1779. current_menu->addAction(mc_systrayMenu_error_log);
  1780. connect(mc_systrayMenu_error_log, SIGNAL(triggered()), this, SLOT(mc_log_slot()));
  1781. }
  1782. // --------------------------------------------------------------
  1783. }
  1784. void Moneychanger::SetupAccountMenu(QPointer<QMenu> & parent_menu)
  1785. {
  1786. const auto accounts = ot_.Storage().AccountList();
  1787. if (default_account_id.isEmpty() && (accounts.size() > 0))
  1788. {
  1789. default_account_id = QString::fromStdString(std::get<0>(accounts.front()));
  1790. }
  1791. // -------------------------------------------------
  1792. if (accounts.size() <= 0)
  1793. {
  1794. QAction * manage_accounts = new QAction(tr("Create an account..."), parent_menu);
  1795. parent_menu->addAction(manage_accounts);
  1796. connect(manage_accounts, SIGNAL(triggered()), this, SLOT(mc_defaultaccount_slot()));
  1797. return;
  1798. }
  1799. // -------------------------------------------------
  1800. QPointer<QMenu> & current_menu = mc_systrayMenu_account;
  1801. // -------------------------------------------------
  1802. current_menu = new QMenu(tr("Set default account..."), parent_menu);
  1803. current_menu->setIcon(mc_systrayIcon_goldaccount);
  1804. parent_menu->addMenu(current_menu);
  1805. //Add a "Manage accounts" action button (and connection)
  1806. QAction * manage_accounts = new QAction(tr("Manage Accounts..."), current_menu);
  1807. manage_accounts->setData(QVariant(QString("openmanager")));
  1808. current_menu->addAction(manage_accounts);
  1809. connect(current_menu, SIGNAL(triggered(QAction*)), this, SLOT(mc_accountselection_triggered(QAction*)));
  1810. // -------------------------------------------------
  1811. current_menu->addSeparator();
  1812. // -------------------------------------------------
  1813. //Ask OT what the display name of this account is and store it for a quick retrieval later on(mostly for "Default Account" displaying purposes)
  1814. if (!default_account_id.isEmpty())
  1815. {
  1816. default_account_name = QString::fromStdString(ot_.Exec().GetAccountWallet_Name(default_account_id.toStdString()));
  1817. }
  1818. // -------------------------------------------------
  1819. //Init account submenu
  1820. account_list_id = new QList<QVariant>;
  1821. account_list_name = new QList<QVariant>;
  1822. // ------------------------------------------
  1823. for (const auto& [accountID, alias] : ot_.Storage().AccountList())
  1824. {
  1825. QString OT_account_id = QString::fromStdString(accountID);
  1826. QString OT_account_name = QString::fromStdString(alias);
  1827. account_list_id ->append(QVariant(OT_account_id));
  1828. account_list_name->append(QVariant(OT_account_name));
  1829. QAction * next_account_action = new QAction(mc_systrayIcon_goldaccount, OT_account_name, current_menu);
  1830. next_account_action->setData(QVariant(OT_account_id));
  1831. next_account_action->setCheckable(true);
  1832. if (0 == OT_account_id.compare(default_account_id)) {
  1833. next_account_action->setChecked(true);
  1834. }
  1835. else {
  1836. next_account_action->setChecked(false);
  1837. }
  1838. current_menu->addAction(next_account_action);
  1839. }
  1840. // -------------------------------------------------
  1841. setDefaultAccount(default_account_id, default_account_name);
  1842. }
  1843. /****
  1844. *
  1845. * Menu Dialog Related Calls
  1846. *
  1847. * First you'll want to create a class for the dialog window you want to display.
  1848. * Then you'll want to follow one of the dialog examples below to see how the startup should happen.
  1849. *
  1850. ****
  1851. *
  1852. * Remember that you'll need to define a close public function here in Moneychanger, and the accompanying
  1853. * QEvent Handler for the class in question.
  1854. *
  1855. ****
  1856. *
  1857. * At a minimum, a Window needs three Functions to operate in the Systray:
  1858. *
  1859. * 1) Startup Slot to connect to Moneychanger Buttons (mc_classname_slot)
  1860. * 2) Dialog Function to launch the Window (mc_classname_dialog)
  1861. * 3) A Function to handled the Close Event Handlers (close_classname_dialog)
  1862. *
  1863. * If you're confused, take a look at the window functions defined below :-)
  1864. * (NOTE) : Some of these may not be fully complete yet, this is a work in progress.
  1865. *
  1866. * Try to keep everything you add for your windows organized and grouped below by Window Class.
  1867. *
  1868. ****/
  1869. /**
  1870. * CRYPTO FUNCTIONS
  1871. **/
  1872. void Moneychanger::mc_crypto_encrypt_slot()
  1873. {
  1874. mc_encrypt_show_dialog(true, true);
  1875. }
  1876. void Moneychanger::mc_crypto_sign_slot()
  1877. {
  1878. mc_encrypt_show_dialog(false, true);
  1879. }
  1880. void Moneychanger::mc_decrypt_show_dialog()
  1881. {
  1882. // --------------------------------------------------
  1883. DlgDecrypt * decrypt_window = new DlgDecrypt(nullptr);
  1884. decrypt_window->setAttribute(Qt::WA_DeleteOnClose);
  1885. // --------------------------------------------------
  1886. decrypt_window->dialog();
  1887. // --------------------------------------------------
  1888. }
  1889. void Moneychanger::mc_crypto_decrypt_slot()
  1890. {
  1891. mc_decrypt_show_dialog();
  1892. }
  1893. void Moneychanger::mc_crypto_verify_slot()
  1894. {
  1895. //nothing for now. prolly forever.
  1896. }
  1897. void Moneychanger::mc_encrypt_show_dialog(bool bEncrypt/*=true*/, bool bSign/*=true*/)
  1898. {
  1899. // --------------------------------------------------
  1900. DlgEncrypt * encrypt_window = new DlgEncrypt(nullptr);
  1901. encrypt_window->setAttribute(Qt::WA_DeleteOnClose);
  1902. // --------------------------------------------------
  1903. encrypt_window->SetEncrypt(bEncrypt);
  1904. encrypt_window->SetSign (bSign);
  1905. // ---------------------------------------
  1906. encrypt_window->dialog();
  1907. // --------------------------------------------------
  1908. }
  1909. void Moneychanger::mc_passphrase_manager_slot()
  1910. {
  1911. mc_passphrase_manager_show_dialog();
  1912. }
  1913. void Moneychanger::mc_passphrase_manager_show_dialog()
  1914. {
  1915. if (!passphrase_window)
  1916. passphrase_window = new DlgPassphraseManager(this);
  1917. // --------------------------------------------------
  1918. passphrase_window->dialog();
  1919. }
  1920. /**
  1921. * Address Book
  1922. **/
  1923. // text may contain a "pre-selected" Contact ID (an integer in string form.)
  1924. void Moneychanger::mc_addressbook_show(QString text/*=QString("")*/)
  1925. {
  1926. // The caller dosen't wish to have the address book paste to anything
  1927. // (they just want to see/manage the address book), just call blank.
  1928. //
  1929. if (!contactswindow)
  1930. contactswindow = new MTDetailEdit(this);
  1931. // -------------------------------------
  1932. contactswindow->m_map.clear();
  1933. // -------------------------------------
  1934. MTContactHandler::getInstance()->GetContacts(contactswindow->m_map);
  1935. // -------------------------------------
  1936. if (!text.isEmpty())
  1937. contactswindow->SetPreSelected(text);
  1938. // -------------------------------------
  1939. contactswindow->setWindowTitle(tr("Address Book"));
  1940. // -------------------------------------
  1941. contactswindow->dialog(MTDetailEdit::DetailEditTypeContact);
  1942. }
  1943. void Moneychanger::mc_addressbook_slot()
  1944. {
  1945. mc_addressbook_show();
  1946. }
  1947. void Moneychanger::mc_showcontact_slot(QString text)
  1948. {
  1949. mc_addressbook_show(text);
  1950. }
  1951. /**
  1952. * Opentxs Contacts
  1953. **/
  1954. // text may contain a "pre-selected" Contact ID
  1955. // (A new-style, string-based contact ID in opentxs)
  1956. void Moneychanger::mc_opentxs_contact_show(QString text/*=QString("")*/)
  1957. {
  1958. if (!opentxscontactswindow)
  1959. opentxscontactswindow = new MTDetailEdit(this);
  1960. // -------------------------------------
  1961. opentxscontactswindow->m_map.clear();
  1962. // -------------------------------------
  1963. MTContactHandler::getInstance()->GetOpentxsContacts(opentxscontactswindow->m_map);
  1964. // -------------------------------------
  1965. if (!text.isEmpty())
  1966. opentxscontactswindow->SetPreSelected(text);
  1967. // -------------------------------------
  1968. opentxscontactswindow->setWindowTitle(tr("Opentxs Contacts"));
  1969. // -------------------------------------
  1970. opentxscontactswindow->dialog(MTDetailEdit::DetailEditTypeOpentxsContact);
  1971. }
  1972. void Moneychanger::mc_opentxs_contacts_slot()
  1973. {
  1974. mc_opentxs_contact_show();
  1975. }
  1976. void Moneychanger::mc_show_opentxs_contact_slot(QString text)
  1977. {
  1978. mc_opentxs_contact_show(text);
  1979. }
  1980. /**
  1981. * Nym Manager
  1982. **/
  1983. //Nym manager "clicked"
  1984. void Moneychanger::mc_defaultnym_slot()
  1985. {
  1986. //The operator has requested to open the dialog to the "Nym Manager";
  1987. mc_nymmanager_dialog();
  1988. }
  1989. void Moneychanger::mc_show_nym_slot(QString text)
  1990. {
  1991. mc_nymmanager_dialog(text);
  1992. }
  1993. void Moneychanger::onHideNavUpdated(bool bHideNav)
  1994. {
  1995. bHideNav_ = bHideNav;
  1996. mc_main_menu_dialog(!bHideNav);
  1997. }
  1998. void Moneychanger::onExpertModeUpdated(bool bExpertMode)
  1999. {
  2000. bExpertMode_ = bExpertMode;
  2001. // --------------------------------
  2002. SetupMainMenu();
  2003. // --------------------------------
  2004. bool bActivityWindowVisible = false;
  2005. if (activity_window)
  2006. {
  2007. bActivityWindowVisible = activity_window->isVisible();
  2008. // -------------------------------------
  2009. activity_window->setParent(nullptr);
  2010. activity_window->disconnect();
  2011. activity_window->setAttribute(Qt::WA_DeleteOnClose, true);
  2012. activity_window->close();
  2013. }
  2014. activity_window = nullptr;
  2015. if (bActivityWindowVisible) {
  2016. mc_activity_slot();
  2017. }
  2018. // --------------------------------
  2019. bool bNymsWindowVisible = false;
  2020. QString nym_id("");
  2021. if (nymswindow)
  2022. {
  2023. nym_id = nymswindow->m_qstrCurrentID;
  2024. bNymsWindowVisible = nymswindow->isVisible();
  2025. // -------------------------------------
  2026. nymswindow->setParent(nullptr);
  2027. nymswindow->disconnect();
  2028. nymswindow->setAttribute(Qt::WA_DeleteOnClose, true);
  2029. nymswindow->close();
  2030. }
  2031. nymswindow = nullptr;
  2032. if (bNymsWindowVisible)
  2033. mc_nymmanager_dialog(nym_id);
  2034. // --------------------------------
  2035. bool bAccountWindowVisible = false;
  2036. QString acct_id("");
  2037. if (accountswindow)
  2038. {
  2039. acct_id = accountswindow->m_qstrCurrentID;
  2040. bAccountWindowVisible = accountswindow->isVisible();
  2041. // -------------------------------------
  2042. accountswindow->setParent(nullptr);
  2043. accountswindow->disconnect();
  2044. accountswindow->setAttribute(Qt::WA_DeleteOnClose, true);
  2045. accountswindow->close();
  2046. }
  2047. accountswindow = nullptr;
  2048. if (bAccountWindowVisible)
  2049. mc_show_account_slot(acct_id);
  2050. // --------------------------------
  2051. bool bContactWindowVisible = false;
  2052. QString contact_id("");
  2053. if (contactswindow)
  2054. {
  2055. contact_id = contactswindow->m_qstrCurrentID;
  2056. bContactWindowVisible = contactswindow->isVisible();
  2057. // -------------------------------------
  2058. contactswindow->setParent(nullptr);
  2059. contactswindow->disconnect();
  2060. contactswindow->setAttribute(Qt::WA_DeleteOnClose, true);
  2061. contactswindow->close();
  2062. }
  2063. contactswindow = nullptr;
  2064. if (bContactWindowVisible)
  2065. mc_showcontact_slot(contact_id);
  2066. // --------------------------------
  2067. // GetRecordlist().IgnoreMail(!bExpertMode);
  2068. }
  2069. void Moneychanger::mc_nymmanager_dialog(QString qstrPresetID/*=QString("")*/)
  2070. {
  2071. QString qstr_default_id = this->get_default_nym_id();
  2072. // -------------------------------------
  2073. if (qstrPresetID.isEmpty())
  2074. qstrPresetID = qstr_default_id;
  2075. // -------------------------------------
  2076. if (!nymswindow)
  2077. nymswindow = new MTDetailEdit(this);
  2078. // -------------------------------------
  2079. mapIDName & the_map = nymswindow->m_map;
  2080. // -------------------------------------
  2081. the_map.clear();
  2082. // -------------------------------------
  2083. int32_t nym_count = ot_.Exec().GetNymCount();
  2084. bool bFoundPreset = false;
  2085. for (int32_t ii = 0; ii < nym_count; ii++)
  2086. {
  2087. QString OT_id = QString::fromStdString(ot_.Exec().GetNym_ID(ii));
  2088. QString OT_name = QString::fromStdString(ot_.Exec().GetNym_Name(OT_id.toStdString()));
  2089. the_map.insert(OT_id, OT_name);
  2090. // ------------------------------
  2091. if (!qstrPresetID.isEmpty() && (0 == qstrPresetID.compare(OT_id)))
  2092. bFoundPreset = true;
  2093. // ------------------------------
  2094. } // for
  2095. // -------------------------------------
  2096. nymswindow->setWindowTitle(tr("My identities"));
  2097. // -------------------------------------
  2098. if (bFoundPreset)
  2099. nymswindow->SetPreSelected(qstrPresetID);
  2100. // -------------------------------------
  2101. nymswindow->dialog(MTDetailEdit::DetailEditTypeNym);
  2102. }
  2103. //Additional Nym Manager Functions
  2104. void Moneychanger::setDefaultNym(QString nym_id, QString nym_name)
  2105. {
  2106. //Set default nym internal memory
  2107. default_nym_id = nym_id;
  2108. default_nym_name = nym_name;
  2109. //SQL UPDATE default nym
  2110. DBHandler::getInstance()->AddressBookUpdateDefaultNym(nym_id);
  2111. //Rename "NYM:" if a nym is loaded
  2112. if (nym_id != "")
  2113. {
  2114. if (mc_systrayMenu_nym)
  2115. mc_systrayMenu_nym->setTitle(tr("Identity: ")+nym_name);
  2116. if (mc_overall_init)
  2117. {
  2118. // Loop through actions in mc_systrayMenu_nym.
  2119. // Ignore the "openmanager" action.
  2120. // For all others, compare the data to the default nym ID.
  2121. // If one matches, set the "checked" property to true, and for
  2122. // all others, set to false.
  2123. if (mc_systrayMenu_nym)
  2124. foreach (QAction* a, mc_systrayMenu_nym->actions())
  2125. {
  2126. QString qstrActionData = a->data().toString();
  2127. if (0 == qstrActionData.compare(default_nym_id)) {
  2128. a->setChecked(true);
  2129. }
  2130. else {
  2131. a->setChecked(false);
  2132. }
  2133. }
  2134. }
  2135. }
  2136. }
  2137. //Nym new default selected from systray
  2138. void Moneychanger::mc_nymselection_triggered(QAction*action_triggered)
  2139. {
  2140. //Check if the user wants to open the nym manager (or) select a different default nym
  2141. QString action_triggered_string = QVariant(action_triggered->data()).toString();
  2142. // qDebug() << "NYM TRIGGERED" << action_triggered_string;
  2143. if (action_triggered_string == "openmanager")
  2144. {
  2145. //Open nym manager
  2146. mc_defaultnym_slot();
  2147. }
  2148. else
  2149. {
  2150. //Set new nym default
  2151. QString action_triggered_string_nym_name = QVariant(action_triggered->text()).toString();
  2152. setDefaultNym(action_triggered_string, action_triggered_string_nym_name);
  2153. //Refresh the nym default selection in the nym manager (ONLY if it is open)
  2154. //Check if nym manager has ever been opened (then apply logic) [prevents crash if the dialog hasen't be opend before]
  2155. //
  2156. if (nymswindow && !nymswindow->isHidden())
  2157. {
  2158. mc_nymmanager_dialog();
  2159. }
  2160. }
  2161. }
  2162. // End Nym Manager
  2163. void Moneychanger::onNeedToDownloadMail()
  2164. {
  2165. QString qstrErrorMsg;
  2166. qstrErrorMsg = tr("Failed trying to contact the notary. Perhaps it is down, or there might be a network problem.");
  2167. // -----------------------------
  2168. int32_t nymCount = ot_.Exec().GetNymCount();
  2169. if (0 == nymCount)
  2170. {
  2171. std::string strSource(""), strMyName("Me");
  2172. // --------------------------------------
  2173. MTGetStringDialog nameDlg(this, tr("Creating your Nym. "
  2174. "Enter your display name (that others will see)"));
  2175. bool bNameEmpty{true};
  2176. if (QDialog::Accepted == nameDlg.exec())
  2177. {
  2178. const QString qstrNewMyName = nameDlg.GetOutputString();
  2179. if (!qstrNewMyName.isEmpty()) {
  2180. bNameEmpty = false;
  2181. strMyName = qstrNewMyName.toStdString();
  2182. }
  2183. }
  2184. // --------------------------------------------------
  2185. if (bNameEmpty) {
  2186. QString name;
  2187. name = qgetenv("USER"); // get the user name in Linux
  2188. if (!name.isEmpty()) {
  2189. bNameEmpty = false;
  2190. strMyName = name.toStdString();
  2191. }
  2192. else {
  2193. name = qgetenv("USERNAME"); // get the name in Windows
  2194. }
  2195. if (!name.isEmpty()) {
  2196. bNameEmpty = false;
  2197. strMyName = name.toStdString();
  2198. }
  2199. }
  2200. // --------------------------------------------------
  2201. std::string newNymId = ot_.Exec().CreateNymHD(
  2202. opentxs::proto::CITEMTYPE_INDIVIDUAL, strMyName, strSource, 0);
  2203. // --------------------------------------------------
  2204. if (!newNymId.empty())
  2205. {
  2206. DBHandler::getInstance()->AddressBookUpdateDefaultNym(QString::fromStdString(newNymId));
  2207. qDebug() << "Finished Making Nym";
  2208. }
  2209. nymCount = ot_.Exec().GetNymCount();
  2210. }
  2211. // ----------------------------------------------------------------
  2212. std::string defaultNymID(get_default_nym_id().toStdString());
  2213. // ----------------------------------------------------------------
  2214. // Some messages come from Bitmessage or other transport layers, and
  2215. // other messages from via OT. So let's download any latest Nym info
  2216. // from OT... (Messages are shipped via the nymbox.)
  2217. //
  2218. if ((get_server_list_id_size() > 0))
  2219. {
  2220. std::string defaultNotaryID(get_default_notary_id().toStdString());
  2221. // ----------------------------------------------------------------
  2222. if (defaultNotaryID.empty())
  2223. {
  2224. defaultNotaryID = get_notary_id_at(0).toStdString();
  2225. DBHandler::getInstance()->AddressBookUpdateDefaultServer(QString::fromStdString(defaultNotaryID));
  2226. }
  2227. // ----------------------------------------------------------------
  2228. if (!defaultNymID.empty() && !defaultNotaryID.empty())
  2229. {
  2230. bool isReg = ot_.Exec().IsNym_RegisteredAtServer(defaultNymID, defaultNotaryID);
  2231. if (!isReg)
  2232. {
  2233. std::string response;
  2234. {
  2235. MTSpinner theSpinner;
  2236. response = opentxs::String::Factory(ot_.Sync().RegisterNym(opentxs::Identifier::Factory(defaultNymID), opentxs::Identifier::Factory(defaultNotaryID), true))->Get();
  2237. if (!ot_.Exec().CheckConnection(defaultNotaryID))
  2238. {
  2239. emit appendToLog(qstrErrorMsg);
  2240. return;
  2241. }
  2242. }
  2243. if (!opentxs::VerifyMessageSuccess(ot_, response)) {
  2244. Moneychanger::It()->HasUsageCredits(defaultNotaryID, defaultNymID);
  2245. return;
  2246. }
  2247. else
  2248. MTContactHandler::getInstance()->NotifyOfNymServerPair(QString::fromStdString(defaultNymID),
  2249. QString::fromStdString(defaultNotaryID));
  2250. // qDebug() << QString("Creation Response: %1").arg(QString::fromStdString(response));
  2251. }
  2252. }
  2253. // ----------------------------------------------------------------
  2254. // Retrieve Nyms
  2255. //
  2256. int32_t serverCount = ot_.Exec().GetServerCount();
  2257. for (int32_t serverIndex = 0; serverIndex < serverCount; ++serverIndex)
  2258. {
  2259. std::string NotaryID = ot_.Exec().GetServer_ID(serverIndex);
  2260. for (int32_t nymIndex = 0; nymIndex < nymCount; ++nymIndex)
  2261. {
  2262. std::string nymId = ot_.Exec().GetNym_ID(nymIndex);
  2263. bool bRetrievalAttempted = false;
  2264. bool bRetrievalSucceeded = false;
  2265. if (ot_.Exec().IsNym_RegisteredAtServer(nymId, NotaryID))
  2266. {
  2267. MTSpinner theSpinner;
  2268. bRetrievalAttempted = true;
  2269. bRetrievalSucceeded = retrieve_nym(NotaryID, nymId);
  2270. if (!ot_.Exec().CheckConnection(NotaryID))
  2271. {
  2272. emit appendToLog(qstrErrorMsg);
  2273. return;
  2274. }
  2275. }
  2276. // ----------------------------------------------------------------
  2277. if (bRetrievalAttempted && !bRetrievalSucceeded) {
  2278. Moneychanger::It()->HasUsageCredits(NotaryID, nymId);
  2279. return;
  2280. }
  2281. }
  2282. }
  2283. // ----------------------------------------------------------------
  2284. // onNeedToPopulateRecordlist();
  2285. return;
  2286. }
  2287. else
  2288. {
  2289. qDebug() << QString("%1: There's not at least 1 server contract; doing nothing.").arg(__FUNCTION__);
  2290. }
  2291. }
  2292. //bool Moneychanger::AddFinalReceiptToTradeArchive(opentxs::OTRecord& recordmt)
  2293. //{
  2294. // QPointer<ModelTradeArchive> pModel = DBHandler::getInstance()->getTradeArchiveModel();
  2295. // if (pModel)
  2296. // {
  2297. // QPointer<FinalReceiptProxyModel> pFinalReceiptProxy = new FinalReceiptProxyModel;
  2298. // pFinalReceiptProxy->setSourceModel(pModel);
  2299. // pFinalReceiptProxy->setFilterOpentxsRecord(recordmt);
  2300. // bool bEditing = false;
  2301. // QString qstrReceipt;
  2302. // int nRowCount = pFinalReceiptProxy->rowCount();
  2303. // if (nRowCount > 0) // Matching rows are present.
  2304. // {
  2305. // for (int nIndex = 0; nIndex < nRowCount; ++nIndex)
  2306. // {
  2307. // if (!bEditing)
  2308. // {
  2309. // bEditing = true;
  2310. // pModel->database().transaction();
  2311. // qstrReceipt = QString::fromStdString(recordmt.GetContents());
  2312. // }
  2313. // QModelIndex proxyIndex = pFinalReceiptProxy->index(nIndex, 0);
  2314. // QModelIndex actualIndex = pFinalReceiptProxy->mapToSource(proxyIndex);
  2315. // QSqlRecord record = pModel->record(actualIndex.row());
  2316. // record.setValue("final_receipt", qstrReceipt);
  2317. // pModel->setRecord(actualIndex.row(), record);
  2318. // }
  2319. // }
  2320. // else if (recordmt.HasOriginType() && recordmt.IsOriginTypeMarketOffer())
  2321. // {
  2322. // bEditing = true;
  2323. // pModel->database().transaction();
  2324. // qstrReceipt = QString::fromStdString(recordmt.GetContents());
  2325. // QSqlRecord record = pModel->record();
  2326. //// const bool bIsBid = false; // I guess I have to derive this from the record's contents...
  2327. // const int64_t lReceiptID = recordmt.GetTransactionNum();
  2328. // const int64_t lOfferID = recordmt.GetTransNumForDisplay();
  2329. // const std::string & strMsgNotaryID = recordmt.GetMsgNotaryID();
  2330. // const std::string & strPmntNotaryID = recordmt.GetPmntNotaryID();
  2331. // const std::string & strNymID = recordmt.GetNymID();
  2332. // const time64_t tDate = static_cast<time64_t>(ot_.Exec().StringToLong(recordmt.GetDate()));
  2333. //// record.setValue("is_bid", bIsBid);
  2334. // record.setValue("receipt_id", QVariant::fromValue(lReceiptID));
  2335. // record.setValue("offer_id", QVariant::fromValue(lOfferID));
  2336. //// record.setValue("scale", QVariant::fromValue(lScale));
  2337. //// record.setValue("actual_price", QVariant::fromValue(lPrice));
  2338. //// record.setValue("actual_paid", QVariant::fromValue(lPayQuantity));
  2339. //// record.setValue("amount_purchased", QVariant::fromValue(lQuantity));
  2340. // record.setValue("timestamp", QVariant::fromValue(tDate));
  2341. // record.setValue("msg_notary_id", QString::fromStdString(strMsgNotaryID));
  2342. // record.setValue("pmnt_notary_id", QString::fromStdString(strPmntNotaryID));
  2343. // record.setValue("nym_id", QString::fromStdString(strNymID));
  2344. //// record.setValue("asset_id", QString::fromStdString(pTradeData->instrument_definition_id));
  2345. //// record.setValue("currency_id", QString::fromStdString(pTradeData->currency_id));
  2346. //// record.setValue("asset_acct_id", QString::fromStdString(pTradeData->asset_acct_id));
  2347. //// record.setValue("currency_acct_id", QString::fromStdString(pTradeData->currency_acct_id));
  2348. //// record.setValue("asset_receipt", QString::fromStdString(pTradeData->asset_receipt));
  2349. //// record.setValue("currency_receipt", QString::fromStdString(pTradeData->currency_receipt));
  2350. // record.setValue("final_receipt", qstrReceipt);
  2351. // qDebug() << "Kind of a weird situation -- a final receipt where there were "
  2352. // "never any marketReceipts. (The offer expired without ever trading.) "
  2353. // "Importing it here anyway to see if it causes any problems. "
  2354. // "UPDATE: Maybe there WERE marketReceipts, but we just filtered it wrong, "
  2355. // "or we got this finalReceipt first, possibly as a notice, and then get the others next.";
  2356. // qDebug() << QString("lOfferID for new insertion: %1").arg(lOfferID);
  2357. // pModel->insertRecord(0, record);
  2358. // }
  2359. // // ----------------------------
  2360. // if (bEditing)
  2361. // {
  2362. // if (pModel->submitAll())
  2363. // {
  2364. // if (pModel->database().commit())
  2365. // {
  2366. // // Success.
  2367. // return true;
  2368. // }
  2369. // }
  2370. // else
  2371. // {
  2372. // pModel->database().rollback();
  2373. // qDebug() << "Database Write Error" <<
  2374. // "The database reported an error: " <<
  2375. // pModel->lastError().text();
  2376. // }
  2377. // }
  2378. // }
  2379. // return false;
  2380. //}
  2381. ///// Returns true if it succeeds in creating the database record, including for the message body.
  2382. /////
  2383. //bool Moneychanger::low_level_AddMailToMsgArchive(
  2384. // opentxs::OTRecord& recordmt,
  2385. // MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  2386. // MapOfConversationsByNym & mapOfConversationsByNym)
  2387. //{
  2388. // // This function is low level because it assumes we already tried the lookup
  2389. // // table.
  2390. // // ------------------------------------------------------------------------------
  2391. // QPointer<ModelMessages> pModel = DBHandler::getInstance()->getMessageModel();
  2392. // bool bSuccessAddingMsg = false;
  2393. // QString qstrBody(""), threadItemId;
  2394. // if (pModel)
  2395. // {
  2396. // QString myNymID;
  2397. // if (!recordmt.GetNymID().empty())
  2398. // myNymID = QString::fromStdString(recordmt.GetNymID());
  2399. // // ---------------------------------
  2400. // QString myAddress;
  2401. // if (!recordmt.GetAddress().empty())
  2402. // myAddress = QString::fromStdString(recordmt.GetAddress());
  2403. //// myAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetAddress()));
  2404. // // ---------------------------------
  2405. // QString senderNymID, senderAddress,
  2406. // recipientNymID, recipientAddress;
  2407. // if (recordmt.IsOutgoing())
  2408. // {
  2409. // if (!recordmt.GetOtherNymID().empty())
  2410. // recipientNymID = QString::fromStdString(recordmt.GetOtherNymID());
  2411. // if (!recordmt.GetOtherAddress().empty())
  2412. // recipientAddress = QString::fromStdString(recordmt.GetOtherAddress());
  2413. //// recipientAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  2414. // }
  2415. // else
  2416. // {
  2417. // if (!recordmt.GetOtherNymID().empty())
  2418. // senderNymID = QString::fromStdString(recordmt.GetOtherNymID());
  2419. // if (!recordmt.GetOtherAddress().empty())
  2420. // senderAddress = QString::fromStdString(recordmt.GetOtherAddress());
  2421. //// senderAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  2422. // }
  2423. // // ---------------------------------
  2424. // QString msgNotaryID, pmntNotaryID, msgType, msgTypeDisplay;
  2425. // if (!recordmt.GetMsgNotaryID().empty())
  2426. // msgNotaryID = QString::fromStdString(recordmt.GetMsgNotaryID());
  2427. // if (!recordmt.GetPmntNotaryID().empty())
  2428. // pmntNotaryID = QString::fromStdString(recordmt.GetPmntNotaryID());
  2429. // if (!recordmt.GetMsgType().empty())
  2430. // msgType = QString::fromStdString(recordmt.GetMsgType());
  2431. //// msgType = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgType()));
  2432. // if (!recordmt.GetMsgTypeDisplay().empty())
  2433. // msgTypeDisplay = QString::fromStdString(recordmt.GetMsgTypeDisplay());
  2434. //// msgTypeDisplay = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgTypeDisplay()));
  2435. // if (!recordmt.GetThreadItemId().empty())
  2436. // threadItemId = QString::fromStdString(recordmt.GetThreadItemId());
  2437. // // ---------------------------------
  2438. // time64_t tDate = static_cast<time64_t>(ot_.Exec().StringToLong(recordmt.GetDate()));
  2439. // // ---------------------------------
  2440. // std::string str_mailDescription;
  2441. // recordmt.FormatMailSubject(str_mailDescription);
  2442. // QString mailDescription;
  2443. // if (!str_mailDescription.empty())
  2444. // mailDescription = MTContactHandler::Encode(QString::fromStdString(str_mailDescription));
  2445. // // ---------------------------------
  2446. // const int nFolder = recordmt.IsOutgoing() ? 0 : 1; // 0 for moneychanger's outbox, and 1 for inbox.
  2447. // // ---------------------------------
  2448. // pModel->database().transaction();
  2449. // // ---------------------------------
  2450. // // ADD THE RECORD HERE.
  2451. // //
  2452. // QSqlRecord record = pModel->record();
  2453. // record.setGenerated("message_id", true);
  2454. // if (!myNymID.isEmpty())
  2455. // record.setValue("my_nym_id", myNymID);
  2456. // if (!myAddress.isEmpty())
  2457. // record.setValue("my_address", myAddress);
  2458. // if (!senderNymID.isEmpty())
  2459. // record.setValue("sender_nym_id", senderNymID);
  2460. // if (!senderAddress.isEmpty())
  2461. // record.setValue("sender_address", senderAddress);
  2462. // if (!recipientNymID.isEmpty())
  2463. // record.setValue("recipient_nym_id", recipientNymID);
  2464. // if (!recipientAddress.isEmpty())
  2465. // record.setValue("recipient_address", recipientAddress);
  2466. // if (!msgType.isEmpty())
  2467. // record.setValue("method_type", msgType);
  2468. // if (!msgTypeDisplay.isEmpty())
  2469. // record.setValue("method_type_display", msgTypeDisplay);
  2470. // if (!msgNotaryID.isEmpty())
  2471. // record.setValue("msg_notary_id", msgNotaryID);
  2472. // if (!pmntNotaryID.isEmpty())
  2473. // record.setValue("pmnt_notary_id", pmntNotaryID);
  2474. // record.setValue("timestamp", QVariant::fromValue(tDate));
  2475. // record.setValue("have_read", recordmt.IsOutgoing() ? 1 : 0);
  2476. // record.setValue("have_replied", 0);
  2477. // record.setValue("have_forwarded", 0);
  2478. // // ------------------------------------------------
  2479. // qstrBody = QString::fromStdString(recordmt.GetContents());
  2480. // const QString qstrSubject{"subject:"};
  2481. // const bool bHasContents = !qstrBody.isEmpty();
  2482. // const bool bHasSubject = bHasContents && qstrBody.startsWith(qstrSubject, Qt::CaseInsensitive);
  2483. // const int nHasSubject = bHasSubject ? 1 : 0;
  2484. // record.setValue("has_subject", QVariant::fromValue(nHasSubject));
  2485. // if (!mailDescription.isEmpty())
  2486. // record.setValue("subject", mailDescription);
  2487. // // ------------------------------------------------
  2488. // record.setValue("folder", nFolder);
  2489. // if (!threadItemId.isEmpty())
  2490. // record.setValue("thread_item_id", threadItemId);
  2491. // // ------------------------------------------------
  2492. // record.setValue("archived", 0);
  2493. // pModel->insertRecord(0, record);
  2494. // // ---------------------------------
  2495. // if (pModel->submitAll())
  2496. // {
  2497. // if (pModel->database().commit())
  2498. // {
  2499. // // Success.
  2500. // bSuccessAddingMsg = true;
  2501. //// qstrBody = QString::fromStdString(recordmt.GetContents());
  2502. // }
  2503. // }
  2504. // else
  2505. // {
  2506. // pModel->database().rollback();
  2507. // qDebug() << "Database Write Error" <<
  2508. // "The database reported an error: " <<
  2509. // pModel->lastError().text();
  2510. // }
  2511. // }
  2512. // // ------------------------------------------------
  2513. // if (bSuccessAddingMsg)
  2514. // {
  2515. // if (!MTContactHandler::getInstance()->CreateMessageBody(qstrBody, threadItemId))
  2516. // {
  2517. // qDebug() << "AddMailToMsgArchive: Succeeded adding message record to database, but then failed writing message body.\n";
  2518. // return false;
  2519. // }
  2520. // // -------------------------------------------------------
  2521. // // Now that we've added it to our database, we need to delete it from Bitmessage.
  2522. // // (We don't need to delete normal mail messages because they are already deleted
  2523. // // in our calling function).
  2524. // bool bSuccessDeletingSpecial = true;
  2525. // if (recordmt.IsSpecialMail())
  2526. // {
  2527. // bSuccessDeletingSpecial = false;
  2528. // int32_t nMethodID = recordmt.GetMethodID();
  2529. // std::string strMsgID = recordmt.GetMsgID();
  2530. // std::string strMsgType = recordmt.GetMsgType();
  2531. // if ((nMethodID > 0) && !strMsgID.empty())
  2532. // {
  2533. // // Get the comm string for this message ID.
  2534. // QString qstrConnect = MTContactHandler::getInstance()->GetMethodConnectStr(static_cast<int>(nMethodID));
  2535. // // Then find the NetworkModule based on the comm string:
  2536. // //
  2537. // if (!qstrConnect.isEmpty())
  2538. // {
  2539. // NetworkModule * pModule = MTComms::find(qstrConnect.toStdString());
  2540. // // Use net module to delete msg ID
  2541. // //
  2542. // if (nullptr != pModule)
  2543. // {
  2544. // if (recordmt.IsOutgoing())
  2545. // {
  2546. // if (pModule->deleteOutMessage(strMsgID))
  2547. // bSuccessDeletingSpecial = true;
  2548. // }
  2549. // else // incoming
  2550. // {
  2551. // if (pModule->deleteMessage(strMsgID))
  2552. // bSuccessDeletingSpecial = true;
  2553. // }
  2554. // }
  2555. // }
  2556. // }
  2557. // if (!bSuccessDeletingSpecial)
  2558. // qDebug() << "AddMailToMsgArchive: FYI, FAILED while trying to delete special mail (probably bitmessage) from its native source.";
  2559. // else
  2560. // qDebug() << "AddMailToMsgArchive: FYI, SUCCESS deleting special mail (probably bitmessage) from its native source.";
  2561. // } // special mail
  2562. // // -----------------------------------
  2563. // }
  2564. // return bSuccessAddingMsg;
  2565. //}
  2566. //// Todo someday: Add a setting to the configuration so a user can choose whether or not to import Bitmessages.
  2567. //// In which case they might never be added to the database here, or deleting from Bitmessage here (as they are now in both cases), unless that setting was set to true.
  2568. ////
  2569. //// When this function returns "true" it means "delete the record" (The mail message).
  2570. ////
  2571. ////resume
  2572. //bool Moneychanger::AddMailToMsgArchive(
  2573. // opentxs::OTRecord& recordmt,
  2574. // MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  2575. // MapOfConversationsByNym & mapOfConversationsByNym,
  2576. // SetNymThreadAndItem & setNewlyAddedNymThreadAndItem)
  2577. //{
  2578. // // First let's make sure we're not re-importing a message we already imported before.
  2579. // //
  2580. // PtrSetOfStrings pAlreadyImportedIds; // For a given nymID and threadID. nullptr so far.
  2581. // std::string str_correct_thread_id_for_item;
  2582. // const std::string str_nym_id = recordmt.GetNymID();
  2583. // const std::string str_thread_item_id = recordmt.GetThreadItemId();
  2584. // if ((false == recordmt.IsSpecialMail()) // Only for normal opentxs mail, not special mail integrations.
  2585. // && !str_nym_id.empty() && !str_thread_item_id.empty())
  2586. // {
  2587. // // Here we need to loop through the conversation Ids for this Nym,
  2588. // // and then search setNewlyAddedNymThreadAndItem to see if the relevant
  2589. // // three IDs appear on the set.
  2590. // // If it's newly-added, we'll import the message body as well. Otherwise we can
  2591. // // assume that we already did, on some previous refresh, and thus can skip any
  2592. // // re-importing of the message body and message table in general.
  2593. // //
  2594. //// typedef std::set<std::string> SetOfStrings;
  2595. //// typedef std::shared_ptr<SetOfStrings> PtrSetOfStrings;
  2596. //// typedef std::pair<std::string, std::string> PairOfStrings;
  2597. //// typedef std::map<PairOfStrings, PtrSetOfStrings> MapOfPtrSetsOfStrings;
  2598. //// typedef std::map<std::string, PtrSetOfStrings> MapOfConversationsByNym;
  2599. ////
  2600. //// // NymID, (conversational) Thread Id, Thread Item Id.
  2601. //// typedef std::tuple<std::string, std::string, std::string> TupleNymThreadAndItem;
  2602. //// typedef std::shared_ptr<TupleNymThreadAndItem> PtrNymThreadAndItem;
  2603. //// typedef std::set<PtrNymThreadAndItem> SetNymThreadAndItem;
  2604. // MapOfConversationsByNym::iterator it_mapConversations = mapOfConversationsByNym.find(str_nym_id);
  2605. // if (mapOfConversationsByNym.end() != it_mapConversations)
  2606. // {
  2607. // PtrSetOfStrings & conversation_ids = it_mapConversations->second;
  2608. // if (conversation_ids)
  2609. // {
  2610. // for (auto& conversation_id : *conversation_ids)
  2611. // {
  2612. // // str_nym_id, conversation_id, str_thread_item_id;
  2613. // // setNewlyAddedNymThreadAndItem
  2614. // const TupleNymThreadAndItem tupleNymThreadAndItem{str_nym_id, conversation_id, str_thread_item_id};
  2615. // for (auto& ptrNymThreadAndItem : setNewlyAddedNymThreadAndItem)
  2616. // {
  2617. // // If the Nym Id, Thread Id, and Thread Item Id (as a tuple, for recordMT) were found on the
  2618. // // set of newly-imported thread items, then let's import the message body (etc) to Moneychanger's
  2619. // // internal DB.
  2620. // //
  2621. // if (tupleNymThreadAndItem == *ptrNymThreadAndItem)
  2622. // {
  2623. // qDebug() << "Importing conversation item...";
  2624. // const bool bReturn = low_level_AddMailToMsgArchive(
  2625. // recordmt,
  2626. // mapOfSetsOfAlreadyImportedMsgs,
  2627. // mapOfConversationsByNym);
  2628. // if (bReturn)
  2629. // {
  2630. // // once we've successfully imported it, can delete from this
  2631. // // set, since we had the set for the express purpose of seeing
  2632. // // which ones we need to import.
  2633. // //
  2634. // //setNewlyAddedNymThreadAndItem.erase(ptrNymThreadAndItem);
  2635. // // commenting out for now in case this might cause any iteration issues.
  2636. // }
  2637. // }
  2638. // }
  2639. // }
  2640. // }
  2641. // }
  2642. // }
  2643. // for (auto& it_preimportedMap : mapOfSetsOfAlreadyImportedMsgs)
  2644. // {
  2645. // PairOfStrings & pairNymIdAndThreadId = it_preimportedMap.first;
  2646. // PtrSetOfStrings & pSetThreadItemIds = it_preimportedMap.second;
  2647. // // ---------------------
  2648. // const std::string & str_current_nym_id = pairNymIdAndThreadId.first;
  2649. // const std::string & str_current_thread_id = pairNymIdAndThreadId.second;
  2650. // // ---------------------
  2651. // if (0 != str_current_nym_id.compare(str_nym_id)) {
  2652. // continue;
  2653. // }
  2654. // if (!pSetThreadItemIds) {
  2655. // continue;
  2656. // }
  2657. // // ---------------------
  2658. // // We've got a map with the key being a pair of strings, and the value
  2659. // // being a smart pointer to a set of strings.
  2660. // // The key is a NymId/ThreadId (and we're looking to find out a ThreadID FYI)
  2661. // // and the value is a pointer to a set of thread ITEM IDs for that Nym/Thread.
  2662. // //
  2663. // // By this point in the function, as we loop through the entire map, we grab
  2664. // // the key (the two strings) first. If the NymID doesn't match the one on the
  2665. // // record, we just skip it.
  2666. // // That leads us to where we are now. We know the NymID matches, but we don't
  2667. // // know yet if it's the right thread. The best thing we can do for now is to
  2668. // // then grab it_preimported.second, which is a shared_ptr to a set of strings
  2669. // // (thread Item IDs). We'll loop through those, and if the thread_item_id matches
  2670. // // any of those, then we can confidentally say that str_current_thread_id is
  2671. // // a valid thread id for this thread item. (We can also say with certainty, at
  2672. // // that point, that it's already been imported...)
  2673. // //
  2674. // // typedef std::set<std::string> SetOfStrings;
  2675. // // typedef std::shared_ptr<SetOfStrings> PtrSetOfStrings;
  2676. // // typedef std::pair<std::string, std::string> PairOfStrings;
  2677. // // typedef std::map<PairOfStrings, PtrSetOfStrings> MapOfPtrSetsOfStrings;
  2678. // // ---------------------
  2679. // bool bFoundThreadId = false;
  2680. // for (auto& str_current_thread_item_id : *pSetThreadItemIds)
  2681. // {
  2682. // if (0 == str_current_thread_item_id.compare(str_thread_item_id)) // Match!
  2683. // {
  2684. // bFoundThreadId = true;
  2685. // pAlreadyImportedIds = pSetThreadItemIds;
  2686. // str_correct_thread_id_for_item = str_current_thread_id;
  2687. // break;
  2688. // }
  2689. // } // for
  2690. // // ---------------------
  2691. // if (bFoundThreadId) // This means it's already been imported.
  2692. // {
  2693. // // Therefore no need to re-import it.
  2694. // }
  2695. // else // Otherwise it definitely HASN'T been yet imported
  2696. // {
  2697. // }
  2698. // // ---------------------
  2699. // } // for
  2700. // // ----------------------------------------------
  2701. // MapOfPtrSetsOfStrings::const_iterator it_map = mapOfSetsOfAlreadyImportedMsgs.find(PairOfStrings{str_nym_id, str_thread_id});
  2702. // }
  2703. // if (mapOfSetsOfAlreadyImportedMsgs.end() != it_map) // the set was already on the map
  2704. // {
  2705. // pAlreadyImportedIds = it_map->second();
  2706. // bHaveGrabbedTheAlreadyImportedIds = true;
  2707. // bHaveAlreadyImportedAnyIds = (pAlreadyImportedIds->size() > 0);
  2708. // }
  2709. // // ----------------------------------------------
  2710. // // LOOP THROUGH THE NEWLY IMPORTED ONES AND LOW LEVEL ADD THEM!
  2711. //// NymID, (conversational) Thread Id, Thread Item Id.
  2712. //// typedef std::tuple<std::string, std::string, std::string> TupleNymThreadAndItem;
  2713. // // ----------------------------------------------
  2714. // bool Moneychanger::low_level_AddMailToMsgArchive(
  2715. // opentxs::OTRecord& recordmt,
  2716. // MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  2717. // MapOfConversationsByNym & mapOfConversationsByNym)
  2718. // return false;
  2719. //}
  2720. // When OTRecord::AcceptIncomingInstrument is called, and the server reply is a success,
  2721. // it calls OTNameLookup::notifyOfSuccessfulNotarization so that the client GUI has the
  2722. // opportunity to make a database record that the transaction is complete. (That's what
  2723. // this function here is doing...)
  2724. //
  2725. // You see, if you deposit someone's incoming cheque, then HE is the one who gets the
  2726. // chequeReceipt (it's dropped into his inbox.) So you won't get any receipts in YOUR
  2727. // inbox. All YOU get is the server's success reply. (Directly.) If Moneychanger wasn't
  2728. // notified of that success reply, then it would have no way of knowing that the cheque
  2729. // had been deposited, and would still think it was "pending incoming."
  2730. //
  2731. // You might ask, "But wait a second, if the Moneychanger user did the cheque deposit,
  2732. // then Moneychanger should have seen it was a success." And that's true. But Moneychanger
  2733. // didn't do the cheque deposit. Rather, it asked OTRecord to do an AcceptIncomingInstrument.
  2734. // OTRecord did the actual deposit. That's why OTRecord has to notify Moneychanger of the success.
  2735. //
  2736. // You might also ask, "But we still have the pending incoming cheque, and if we know the
  2737. // deposit was a success, why not just move the incoming cheque to the record box, and then
  2738. // in the future we can think of it as a 'Deposited Cheque'?" The reason is, we only had the
  2739. // cheque when it was 'pending incoming'. But now that it's been deposited, we have the actual
  2740. // cheque deposit receipt that the server replied to us. So it's better to record that receipt
  2741. // since it PROVES the deposit, instead of merely inferring it based on the cheque being in
  2742. // Box B instead of Box A. Why not add the actual cheque DEPOSIT into the database, since we
  2743. // now have a copy of it? So that's what we do.
  2744. //
  2745. // One more thing: Since this function has "notification" in its name, you might think it's
  2746. // referring to a "notice" (a type of receipt that OT puts in the nymbox from time to time,
  2747. // to inform the user that something has happened.) But nope. That's not it. Here we use
  2748. // "Notification" because OTRecord has "notified" Moneychanger (by way of callback) that a
  2749. // transaction was successfully performed. The confusion is coincidental and unfortunate.
  2750. //
  2751. //void Moneychanger::AddPaymentBasedOnNotification(const std::string & str_acct_id,
  2752. // const std::string & p_nym_id,
  2753. // const std::string & p_msg_notary_id,
  2754. // const std::string & p_pmnt_notary_id,
  2755. // const std::string & p_txn_contents,
  2756. // int64_t & lTransactionNum,
  2757. // int64_t & lTransNumForDisplay)
  2758. //{
  2759. // QPointer<ModelPayments> pModel = DBHandler::getInstance()->getPaymentModel();
  2760. // bool bSuccessAddingPmnt = false;
  2761. // QString qstrBody(""), qstrPendingBody("");
  2762. // QMap<QString, QVariant> mapFinalValues;
  2763. // bool bRecordAlreadyExisted = false;
  2764. // int nPreExistingPaymentId = 0;
  2765. // if (pModel)
  2766. // {
  2767. // QString myNymID;
  2768. // if (!p_nym_id.empty())
  2769. // myNymID = QString::fromStdString(p_nym_id);
  2770. // // ---------------------------------
  2771. // QString myAcctID;
  2772. // if (!str_acct_id.empty())
  2773. // myAcctID = QString::fromStdString(str_acct_id);
  2774. // // ---------------------------------
  2775. // QString msgNotaryID, pmntNotaryID;
  2776. // if (!p_msg_notary_id.empty())
  2777. // msgNotaryID = QString::fromStdString(p_msg_notary_id);
  2778. // if (!p_pmnt_notary_id.empty())
  2779. // pmntNotaryID = QString::fromStdString(p_pmnt_notary_id);
  2780. // // ---------------------------------
  2781. // int64_t & transNum = lTransactionNum;
  2782. // int64_t & transNumDisplay = lTransNumForDisplay;
  2783. // int nPending = 1;
  2784. // int nCompleted = 1;
  2785. // // ---------------------------------
  2786. // const int nFolder = 1; // 0 for moneychanger's outbox, and 1 for inbox.
  2787. // // ---------------------------------
  2788. // // First let's see if a record already exists:
  2789. // //
  2790. // nPreExistingPaymentId = MTContactHandler::getInstance()->GetPaymentIdByTxnDisplayId(transNumDisplay, myNymID);
  2791. // bRecordAlreadyExisted = (nPreExistingPaymentId > 0);
  2792. // // ------------------------------------------
  2793. //// qDebug() << "Payment already existed: " << QString(bRecordAlreadyExisted ? "TRUE" : "FALSE");
  2794. //// qDebug() << "nPreExistingPaymentId: " << nPreExistingPaymentId;
  2795. // // We'll start by putting all the values into our map,
  2796. // // so we can then use that map when creating or updating
  2797. // // database records.
  2798. // //
  2799. // // if (bRecordAlreadyExisted) mapFinalValues.insert("payment_id", nPreExistingPaymentId);
  2800. // // Note: No need to insert this one.
  2801. // if (!myNymID.isEmpty()) mapFinalValues.insert("my_nym_id", myNymID);
  2802. // if (!myAcctID.isEmpty()) mapFinalValues.insert("my_acct_id", myAcctID);
  2803. // if (transNum > 0) mapFinalValues.insert("txn_id", QVariant::fromValue(transNum));
  2804. // if (transNumDisplay > 0) mapFinalValues.insert("txn_id_display", QVariant::fromValue(transNumDisplay));
  2805. // if (nPending > 0) mapFinalValues.insert("pending_found", QVariant::fromValue(nPending));
  2806. // if (nCompleted > 0) mapFinalValues.insert("completed_found", QVariant::fromValue(nCompleted));
  2807. // if (!msgNotaryID.isEmpty()) mapFinalValues.insert("msg_notary_id", msgNotaryID);
  2808. // if (!pmntNotaryID.isEmpty()) mapFinalValues.insert("pmnt_notary_id", pmntNotaryID);
  2809. //// qDebug() << "DEBUGGING AddPaymentBasedOnNotification. transNum: " << transNum << " transNumDisplay: " << transNumDisplay << "\n";
  2810. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_read", QVariant::fromValue(0));
  2811. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_replied", QVariant::fromValue(0));
  2812. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_forwarded", QVariant::fromValue(0));
  2813. // mapFinalValues.insert("folder", QVariant::fromValue(nFolder));
  2814. // // -------------------------------------------------
  2815. //// opentxs::OTPayment thePayment(p_txn_contents);
  2816. //// if (thePayment.IsValid() && thePayment.SetTempValues())
  2817. //// {
  2818. //// const std::string str_temp_type(thePayment.GetTypeString());
  2819. //// QString qstrType = QString::fromStdString(str_temp_type);
  2820. //// if (thePayment.IsNotice())
  2821. //// qstrPendingBody = QString::fromStdString(p_txn_contents);
  2822. //// else if ( thePayment.IsReceipt() )
  2823. //// qstrBody = QString::fromStdString(p_txn_contents);
  2824. //// else
  2825. //// qstrPendingBody = QString::fromStdString(p_txn_contents);
  2826. //// }
  2827. //// else
  2828. //// if (bRecordAlreadyExisted)
  2829. //// qstrBody = QString::fromStdString(p_txn_contents);
  2830. //// else
  2831. // qstrPendingBody = QString::fromStdString(p_txn_contents);
  2832. // // -------------------------------------------------
  2833. // if (bRecordAlreadyExisted)
  2834. // {
  2835. // // Success.
  2836. // if (MTContactHandler::getInstance()->UpdatePaymentRecord(nPreExistingPaymentId, mapFinalValues))
  2837. // {
  2838. // bSuccessAddingPmnt = true;
  2839. // pModel->select(); // Reset the model since we just inserted a new record.
  2840. // // AH WAIT!!! We don't want to do this for EVERY record inserted, do we?
  2841. // // Just the LAST ONE.
  2842. // // TODO!
  2843. // }
  2844. // }
  2845. // else // Record doesn't already exist in the database.
  2846. // { // In that case we can use some code we already had:
  2847. // pModel->database().transaction();
  2848. // // ---------------------------------
  2849. // QSqlRecord record = pModel->record();
  2850. // record.setGenerated("payment_id", true);
  2851. // // ---------------------------------
  2852. // for (QMap<QString, QVariant>::iterator it_map = mapFinalValues.begin();
  2853. // it_map != mapFinalValues.end(); ++it_map)
  2854. // {
  2855. // const QString & qstrKey = it_map.key();
  2856. // const QVariant & qValue = it_map.value();
  2857. // record.setValue(qstrKey, qValue);
  2858. // }
  2859. // pModel->insertRecord(0, record);
  2860. // // ---------------------------------
  2861. // if (pModel->submitAll())
  2862. // {
  2863. // // Success.
  2864. // if (pModel->database().commit())
  2865. // bSuccessAddingPmnt = true;
  2866. // }
  2867. // else
  2868. // {
  2869. // pModel->database().rollback();
  2870. // qDebug() << "Database Write Error" <<
  2871. // "The database reported an error: " <<
  2872. // pModel->lastError().text();
  2873. // }
  2874. // } // Record didn't already exist. (Adding new.)
  2875. // } // if pModel
  2876. // // ------------------------------------------------
  2877. // if (bSuccessAddingPmnt)
  2878. // {
  2879. // qDebug() << "AddPaymentBasedOnNotification: Succeeded adding payment record to database.\n";
  2880. // if (bRecordAlreadyExisted)
  2881. // {
  2882. // if (!MTContactHandler::getInstance()->UpdatePaymentBody(nPreExistingPaymentId, qstrBody, qstrPendingBody))
  2883. // {
  2884. // qDebug() << "AddPaymentBasedOnNotification: ...but then failed updating payment body and/or pending body.\n";
  2885. // }
  2886. // }
  2887. // // ------------------------
  2888. // else
  2889. // {
  2890. // if (!MTContactHandler::getInstance()->CreatePaymentBody(qstrBody, qstrPendingBody))
  2891. // {
  2892. // qDebug() << "AddPaymentBasedOnNotification: ...but then failed creating payment body and/or pending body.\n";
  2893. // }
  2894. // }
  2895. // }
  2896. //}
  2897. //bool Moneychanger::AddPaymentBasedOnNotice(opentxs::OTRecord& recordmt, const bool bCanDeleteRecord/*=true*/)
  2898. //{
  2899. // return AddPaymentToPmntArchive(recordmt, bCanDeleteRecord);
  2900. //}
  2901. //// Instead of the Payments UI, this is for the Agreements UI.
  2902. //// Pretty similar though. Just make sure, if you call this function, that you know you are
  2903. //// passing something related to a payment plan or smart contract. (Anything recurring except
  2904. //// for market trades.)
  2905. //// We'll start with paymentReceipts and finalReceipts and then go from there...
  2906. ////
  2907. //bool Moneychanger::AddAgreementRecord(opentxs::OTRecord& recordmt)
  2908. //{
  2909. // ModelPayments::PaymentFlags flags = ModelPayments::NoFlags;
  2910. // QPointer<ModelAgreements> pAgreementModel = DBHandler::getInstance()->getAgreementModel();
  2911. // QPointer<ModelAgreementReceipts> pModel = DBHandler::getInstance()->getAgreementReceiptModel();
  2912. // bool bSuccessAddingReceipt = false;
  2913. // bool bSuccessUpdatingReceipt = false;
  2914. // QString qstrReceiptBody(""), qstrMemo("");
  2915. // QMap<QString, QVariant> mapFinalValues;
  2916. // bool bRecordAlreadyExisted = false;
  2917. // int nAgreementId = 0;
  2918. // int nAgreementReceiptKey = 0;
  2919. // int nNewestKnownState = 0;
  2920. // int64_t receiptNum = 0;
  2921. // time64_t tDate = 0;
  2922. // if (pModel)
  2923. // {
  2924. // // ---------------------------------
  2925. // if (recordmt.IsSpecialMail()) flags |= ModelPayments::IsSpecialMail;
  2926. // if (recordmt.IsPending()) flags |= ModelPayments::IsPending;
  2927. // if (recordmt.IsOutgoing()) flags |= ModelPayments::IsOutgoing;
  2928. // if (recordmt.IsRecord()) flags |= ModelPayments::IsRecord;
  2929. // if (recordmt.IsReceipt()) flags |= ModelPayments::IsReceipt;
  2930. // if (recordmt.IsFinalReceipt()) flags |= ModelPayments::IsFinalReceipt;
  2931. // if (recordmt.IsMail()) flags |= ModelPayments::IsMail;
  2932. // if (recordmt.IsTransfer()) flags |= ModelPayments::IsTransfer;
  2933. // if (recordmt.IsCheque()) flags |= ModelPayments::IsCheque;
  2934. // if (recordmt.IsInvoice()) flags |= ModelPayments::IsInvoice;
  2935. // if (recordmt.IsVoucher()) flags |= ModelPayments::IsVoucher;
  2936. // if (recordmt.IsContract()) flags |= ModelPayments::IsContract;
  2937. // if (recordmt.IsPaymentPlan()) flags |= ModelPayments::IsPaymentPlan;
  2938. // if (recordmt.IsCash()) flags |= ModelPayments::IsCash;
  2939. // if (recordmt.IsNotice()) flags |= ModelPayments::IsNotice;
  2940. // if (recordmt.IsExpired()) flags |= ModelPayments::IsExpired;
  2941. // if (recordmt.IsCanceled()) flags |= ModelPayments::IsCanceled;
  2942. // if (recordmt.CanDeleteRecord()) flags |= ModelPayments::CanDelete;
  2943. // if (recordmt.CanAcceptIncoming()) flags |= ModelPayments::CanAcceptIncoming;
  2944. // if (recordmt.CanDiscardIncoming()) flags |= ModelPayments::CanDiscardIncoming;
  2945. // if (recordmt.CanCancelOutgoing()) flags |= ModelPayments::CanCancelOutgoing;
  2946. // if (recordmt.CanDiscardOutgoingCash()) flags |= ModelPayments::CanDiscardOutgoingCash;
  2947. // // ---------------------------------
  2948. // if (recordmt.HasOriginType()) {
  2949. // if (recordmt.IsOriginTypePaymentPlan()) flags |= ModelPayments::OriginTypePaymentPlan;
  2950. // if (recordmt.IsOriginTypeSmartContract()) flags |= ModelPayments::OriginTypeSmartContract;
  2951. // if (recordmt.IsOriginTypeMarketOffer()) {
  2952. // qDebug() << __FUNCTION__
  2953. // << ": Strange; Misguided attempt to import a market related receipt into the agreements table. (Failure.)";
  2954. // return false;
  2955. // }
  2956. // }
  2957. // // ---------------------------------
  2958. // QString myNymID;
  2959. // if (!recordmt.GetNymID().empty())
  2960. // myNymID = QString::fromStdString(recordmt.GetNymID());
  2961. // // ---------------------------------
  2962. // QString myAcctID;
  2963. // if (!recordmt.GetAccountID().empty())
  2964. // myAcctID = QString::fromStdString(recordmt.GetAccountID());
  2965. // // ---------------------------------
  2966. // QString instrumentType;
  2967. // if (!recordmt.GetInstrumentType().empty())
  2968. // instrumentType = QString::fromStdString(recordmt.GetInstrumentType());
  2969. // // ---------------------------------
  2970. // QString myAssetTypeID;
  2971. // if (!recordmt.GetUnitTypeID().empty())
  2972. // myAssetTypeID = QString::fromStdString(recordmt.GetUnitTypeID());
  2973. // // ---------------------------------
  2974. // QString myAddress;
  2975. // if (!recordmt.GetAddress().empty())
  2976. // myAddress = QString::fromStdString(recordmt.GetAddress());
  2977. //// myAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetAddress()));
  2978. // // ---------------------------------
  2979. // QString senderNymID, senderAccountID, senderAddress,
  2980. // recipientNymID, recipientAccountID, recipientAddress;
  2981. // if (recordmt.IsOutgoing())
  2982. // {
  2983. // if (!recordmt.GetOtherNymID().empty())
  2984. // recipientNymID = QString::fromStdString(recordmt.GetOtherNymID());
  2985. // if (!recordmt.GetOtherAccountID().empty())
  2986. // recipientAccountID = QString::fromStdString(recordmt.GetOtherAccountID());
  2987. // if (!recordmt.GetOtherAddress().empty())
  2988. // recipientAddress = QString::fromStdString(recordmt.GetOtherAddress());
  2989. //// recipientAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  2990. // }
  2991. // else
  2992. // {
  2993. // if (!recordmt.GetOtherNymID().empty())
  2994. // senderNymID = QString::fromStdString(recordmt.GetOtherNymID());
  2995. // if (!recordmt.GetOtherAccountID().empty())
  2996. // senderAccountID = QString::fromStdString(recordmt.GetOtherAccountID());
  2997. // if (!recordmt.GetOtherAddress().empty())
  2998. // senderAddress = QString::fromStdString(recordmt.GetOtherAddress());
  2999. //// senderAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  3000. // }
  3001. // // ---------------------------------
  3002. // QString msgNotaryID, pmntNotaryID, msgType, msgTypeDisplay;
  3003. // if (!recordmt.GetMsgNotaryID().empty())
  3004. // msgNotaryID = QString::fromStdString(recordmt.GetMsgNotaryID());
  3005. // if (!recordmt.GetPmntNotaryID().empty())
  3006. // pmntNotaryID = QString::fromStdString(recordmt.GetPmntNotaryID());
  3007. // if (!recordmt.GetMsgType().empty())
  3008. // msgType = QString::fromStdString(recordmt.GetMsgType());
  3009. //// msgType = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgType()));
  3010. // if (!recordmt.GetMsgTypeDisplay().empty())
  3011. // msgTypeDisplay = QString::fromStdString(recordmt.GetMsgTypeDisplay());
  3012. //// msgTypeDisplay = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgTypeDisplay()));
  3013. // // ---------------------------------
  3014. // tDate = static_cast<time64_t>(ot_.Exec().StringToLong(recordmt.GetDate()));
  3015. // // If it's a final Receipt, we want to get the closing number from it as the "receipt_id" which
  3016. // // is the Agreement table's version of the TransNum.
  3017. // // What's the difference? Well, they are basically identical, except for finalReceipts we have to use
  3018. // // the closing number instead of the "transaction number" since it's the only unique number on the
  3019. // // receipt. (A finalReceipt will have the same transaction number as other finalReceipts from the
  3020. // // same event.) So we're probably going to fix this soon by adding the "event_id" to OT.
  3021. // //
  3022. // int64_t transNum = recordmt.GetTransactionNum();
  3023. // int64_t transNumDisplay = recordmt.GetTransNumForDisplay();
  3024. // // ---------------------------------------------------------------
  3025. // receiptNum = transNum;
  3026. // if (recordmt.IsFinalReceipt())
  3027. // {
  3028. // int64_t temp = 0;
  3029. // if (recordmt.GetClosingNum(temp) && (temp > 0))
  3030. // receiptNum = temp;
  3031. // }
  3032. // // What's going on here is, we normally use the Transaction Number on a receipt to identify it.
  3033. // // (The "trans num for display" might be the same on many receipts, but the actual txn_id isn't.)
  3034. // // But a problem arose, because some finalReceipts have the same transaction number. (Those that
  3035. // // were created from the same event.) We didn't mind this in the past since each finalReceipt went
  3036. // // to a different account, and the txnId wasn't signed out to the user anyway, but was owned by
  3037. // // the server.
  3038. // // Well, the chickens have come home to roost. We DO need a unique receipt number, and so for now,
  3039. // // we're using the "closing number" on the final receipt -- which is unique, at least for a given
  3040. // // notary -- and we're using the normal TransNum for all other receipts. This is what forms the
  3041. // // "receipt_id" that's used in the Agreement table.
  3042. // //
  3043. // // At some point soon we're going to fix this by adding an event_id to transactions, so we can tell
  3044. // // which ones came from the same event, without having to put the same transaction number on each.
  3045. // // Probably make a "receipt number" as well, on the OT side.
  3046. // // Why's that? Imagine that Alice does a single transaction #900, to exchange out of a basket currency
  3047. // // that has 4 asset types. She receives a server reply to her basket exchange, and then also receives
  3048. // // 4 finalReceipts in her 4 asset accounts. So that's 5 receipts total!
  3049. // // The server reply should be Transaction #900. (Which WAS signed out to Alice, though it's closed now.)
  3050. // // It should also have a receipt ID owned by the server. Say, number 54.
  3051. // // It should also have an event ID owned by the server. Say, number 600.
  3052. // // The 4 receipts will each have a unique receipt number owned by the server. Say, 55, 56, 57, and 58.
  3053. // // They should NOT have a transaction number, but they should have #900 as the "number of origin."
  3054. // // They should also all have the same event ID 600.
  3055. // // You might ask, why not just use the Transaction# 900 as the event ID? It's already the same on
  3056. // // all those receipts. The answer is because it's possible to have multiple events from the same
  3057. // // transaction. For example, market offer #900 might have 5 trades that occur. Each of those spawns
  3058. // // 4 marketReceipts. (20 in total.) So that's 5 different events for the same #900. Those events
  3059. // // might be 600, 601, 602, and 603. And there will be 20 receipt IDs as well. We'll get there.
  3060. // //
  3061. // // So this is a little confusing, but we'll simplify it soon, and for now, this works.
  3062. // // ---------------------------------------------------------------
  3063. // if (0 >= receiptNum)
  3064. // {
  3065. // qDebug() << __FUNCTION__ << ": Strange -- receiptNum is 0 or less. Should never happen. Failure.";
  3066. // return false;
  3067. // }
  3068. // // ---------------------------------------------------------------
  3069. // int64_t lAmount = ot_.Exec().StringToLong(recordmt.GetAmount());
  3070. //// qDebug() << "DEBUGGING! recordmt.GetAmount(): " << QString::fromStdString(recordmt.GetAmount())
  3071. //// << " lAmount: " << lAmount << "\n";
  3072. // // ---------------------------------
  3073. // std::string str_Name = recordmt.GetName();
  3074. // QString qstrName;
  3075. // if (!str_Name.empty())
  3076. // qstrName = MTContactHandler::Encode(QString::fromStdString(str_Name));
  3077. // // ---------------------------------
  3078. // std::string str_Memo = recordmt.HasMemo() ? recordmt.GetMemo() : "";
  3079. // if (!str_Memo.empty())
  3080. // qstrMemo = MTContactHandler::Encode(QString::fromStdString(str_Memo));
  3081. // // ---------------------------------
  3082. // std::string str_mailDescription;
  3083. // recordmt.FormatDescription(str_mailDescription);
  3084. // QString mailDescription;
  3085. // if (!str_mailDescription.empty())
  3086. // mailDescription = MTContactHandler::Encode(QString::fromStdString(str_mailDescription));
  3087. // // ---------------------------------
  3088. // const int nFolder = recordmt.IsOutgoing() ? 0 : 1; // 0 for moneychanger's outbox, and 1 for inbox.
  3089. // // ---------------------------------
  3090. // if (pmntNotaryID.isEmpty())
  3091. // {
  3092. // qDebug() << __FUNCTION__ << ": Strange: pmntNotaryID was empty. (And I needed it. Returning false. Sigh.)";
  3093. // return false;
  3094. // }
  3095. // // ----------------------------------------------------------
  3096. // int nAgreementFolder = 0;
  3097. // if (recordmt.IsPaymentPlan()) nAgreementFolder = 0; // Recurring Payment Plan
  3098. // else if (recordmt.IsContract()) nAgreementFolder = 1; // Smart Contract
  3099. //// else if (recordmt.IsEntity()) nAgreementFolder = 2; // Someday. (For digital corporations.)
  3100. // // ----------------------------------------------------------------------------------------
  3101. // // NOTE: This may be a paymentReceipt for a smart contract.
  3102. // // In which case recordmt.IsContract() returns FALSE! (Though recordmt.IsReceipt() would return TRUE.)
  3103. // // In which case the above logic would set the folder wrong (It'd be set to the payment plan folder instead
  3104. // // of the smart contract folder.)
  3105. // // SO THEN, how does the below call to GetOrCreateLiveAgreementId work? Because it doesn't set the folder if
  3106. // // the record already exists.
  3107. // // It ONLY sets the folder when first creating the record. And it will get the folder correctly that time.
  3108. // // So I don't mind if the folder is wrong all the other times, because it's discarded in those cases anyway.
  3109. // // If it turns out later that this isn't good enough, I guess we can get more info from the record. But
  3110. // // this should work for now.
  3111. // // UPDATE: We now have the below flags which take the guesswork out of it.
  3112. // // ----------------------------------------------------------------------------------------
  3113. // else if (flags.testFlag(ModelPayments::OriginTypePaymentPlan)) nAgreementFolder = 0;
  3114. // else if (flags.testFlag(ModelPayments::OriginTypeSmartContract)) nAgreementFolder = 1;
  3115. // else {
  3116. // qDebug() << __FUNCTION__
  3117. // << ": Strange; Trying to import an agreement receipt, but can't figure out which folder to put it in. (Failure.)";
  3118. // return false;
  3119. // }
  3120. // // ----------------------------------------------------------------------------------------
  3121. // // Let's see if we already have a "live agreement" in the Moneychanger DB's agreement table.
  3122. // // The Notary and the TxnDisplay (which is the same for all Nyms) are used to look up the
  3123. // // agreement, and nAgreementId is the unique key returned.
  3124. // // (Can't use TxnDisplay for unique key since there are multiple notaries out there...)
  3125. // //
  3126. // int nLastKnownState = 0;
  3127. // nAgreementId = MTContactHandler::getInstance()->GetOrCreateLiveAgreementId(
  3128. // transNumDisplay, pmntNotaryID, qstrMemo, nAgreementFolder, nLastKnownState);
  3129. // if (nAgreementId <= 0)
  3130. // {
  3131. // qDebug() << __FUNCTION__ << ": Failed in call to GetOrCreateLiveAgreementId (strange.)";
  3132. // return false;
  3133. // }
  3134. // // ----------------------------------------------------------
  3135. // // Let's see if a record already exists for this receipt:
  3136. // // UPDATE: Normally we search for an agreement receipt based on the "receiptNum"
  3137. // // but there is one case where it will fail: a cancellation notice for a pending incoming agreement
  3138. // // will have a different receiptNum than the pending incoming agreement does. Normally this is fine,
  3139. // // as we just collect ALL receipts on the Active Agreements UI.
  3140. // // But in the case of cancellation, we want to do a replacement. And we'll fail in the above-described
  3141. // // scenario.
  3142. // // Therefore, ONLY in the case of cancellation/activation, we pass the transNumDisplay in addition to the receiptNum,
  3143. // // here into DoesAgreementReceiptAlreadyExist. ONLY if it fails in the normal way (using the receiptNum)
  3144. // // will it then try the alternate search method of the transNumDisplay, since you can only cancel a pending
  3145. // // transaction BEFORE it has been activated. Therefore there could not be any other records stored except
  3146. // // for the pending incoming itself. So it should theoretically be the only one found, when searching based
  3147. // // on the transNumDisplay. (When in all other cases in this UI, there could be a plethora of other receipts
  3148. // // for the same transNumDisplay. Like all the paymentReceipts for that payment plan, etc.)
  3149. // //
  3150. // nAgreementReceiptKey = MTContactHandler::getInstance()->DoesAgreementReceiptAlreadyExist(nAgreementId, receiptNum, myNymID,
  3151. // recordmt.IsNotice() ? transNumDisplay : 0);
  3152. // bRecordAlreadyExisted = (nAgreementReceiptKey > 0);
  3153. // if (bRecordAlreadyExisted)
  3154. // {
  3155. // // If the agreement receipt key already exists, AND the current record is a NOTICE,
  3156. // // that means the current record should REPLACE or UPDATE the pre-existing version.
  3157. // // But in ALL OTHER CASES, we simply want to add the receipt, or return if it's already there.
  3158. // // This is the only case where we want to update an existing record.
  3159. // QString qstrTemp = QString("nAgreementId: %1 nAgreementReceiptKey: %2 receiptNum: %3 transNum: %4 transNumDisplay: %5\n Description: %6")
  3160. // .arg(nAgreementId).arg(nAgreementReceiptKey).arg(receiptNum).arg(transNum).arg(transNumDisplay).arg(mailDescription);
  3161. // qDebug() << qstrTemp;
  3162. // QString tFinal = "false";
  3163. // QString tContract = "false";
  3164. // QString tPlan = "false";
  3165. // QString tNotice = "false";
  3166. // QString tExpired = "false";
  3167. // QString tCanceled = "false";
  3168. // QString tSuccess = "false";
  3169. // bool bIsSuccess = false;
  3170. // if (recordmt.IsFinalReceipt()) tFinal = "true";
  3171. // if (recordmt.IsContract()) tContract = "true";
  3172. // if (recordmt.IsPaymentPlan()) tPlan = "true";
  3173. // if (recordmt.IsNotice()) tNotice = "true";
  3174. // if (recordmt.IsExpired()) tExpired = "true";
  3175. // if (recordmt.IsCanceled()) tCanceled = "true";
  3176. // if (recordmt.HasSuccess(bIsSuccess)) tSuccess = bIsSuccess ? "true" : "false";
  3177. // qstrTemp = QString(" IsFinalReceipt: %1\n IsContract: %2 \n IsPaymentPlan: %3 \n IsNotice: %4 \n IsExpired: %5 \n IsCanceled: %6 \n IsSuccess: %7 ")
  3178. // .arg(tFinal).arg(tContract).arg(tPlan).arg(tNotice).arg(tExpired).arg(tCanceled).arg(tSuccess);
  3179. // qDebug() << qstrTemp;
  3180. // if (!recordmt.IsNotice())
  3181. // {
  3182. // qDebug() << __FUNCTION__ << ": Skipping this agreement receipt since it's apparently already in the database. (Returning true, however, so the recordlist will dump it.)";
  3183. // return true;
  3184. // }
  3185. // // else if it IS a notice, we let it fall through, and the below code is smart
  3186. // // enough now to know when to add a new record, and when to update an existing one.
  3187. // }
  3188. // // ----------------------------------------------------------
  3189. // // We'll start by putting all the values into our map, so we can then use
  3190. // // that map when creating the DB record.
  3191. // //
  3192. // // if (bRecordAlreadyExisted) mapFinalValues.insert("agreement_receipt_key", nAgreementReceiptKey);
  3193. // // Note: No need to insert this one. It's auto-number.
  3194. // mapFinalValues.insert("agreement_id", QVariant::fromValue(nAgreementId));
  3195. // mapFinalValues.insert("receipt_id", QVariant::fromValue(receiptNum));
  3196. // if (tDate > 0) mapFinalValues.insert("timestamp", QVariant::fromValue(tDate));
  3197. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_read", QVariant::fromValue(recordmt.IsOutgoing() ? 1 : 0));
  3198. // if (transNumDisplay > 0) mapFinalValues.insert("txn_id_display", QVariant::fromValue(transNumDisplay));
  3199. // // (Someday event_id will go here.)
  3200. // if (!qstrMemo.isEmpty()) mapFinalValues.insert("memo", qstrMemo);
  3201. // if (!myAssetTypeID.isEmpty()) mapFinalValues.insert("my_asset_type_id", myAssetTypeID);
  3202. // if (!myNymID.isEmpty()) mapFinalValues.insert("my_nym_id", myNymID);
  3203. // if (!myAcctID.isEmpty()) mapFinalValues.insert("my_acct_id", myAcctID);
  3204. // if (!myAddress.isEmpty()) mapFinalValues.insert("my_address", myAddress);
  3205. // if (!senderNymID.isEmpty()) mapFinalValues.insert("sender_nym_id", senderNymID);
  3206. // if (!senderAccountID.isEmpty()) mapFinalValues.insert("sender_acct_id", senderAccountID);
  3207. // if (!senderAddress.isEmpty()) mapFinalValues.insert("sender_address", senderAddress);
  3208. // if (!recipientNymID.isEmpty()) mapFinalValues.insert("recipient_nym_id", recipientNymID);
  3209. // if (!recipientAccountID.isEmpty()) mapFinalValues.insert("recipient_acct_id", recipientAccountID);
  3210. // if (!recipientAddress.isEmpty()) mapFinalValues.insert("recipient_address", recipientAddress);
  3211. // if (lAmount != 0) mapFinalValues.insert("amount", QVariant::fromValue(lAmount));
  3212. // mapFinalValues.insert("folder", QVariant::fromValue(nFolder));
  3213. // if (!msgType.isEmpty()) mapFinalValues.insert("method_type", msgType);
  3214. // if (!msgTypeDisplay.isEmpty()) mapFinalValues.insert("method_type_display", msgTypeDisplay);
  3215. // if (!msgNotaryID.isEmpty()) mapFinalValues.insert("msg_notary_id", msgNotaryID);
  3216. // if (!pmntNotaryID.isEmpty()) mapFinalValues.insert("pmnt_notary_id", pmntNotaryID);
  3217. // if (!mailDescription.isEmpty()) mapFinalValues.insert("description", mailDescription);
  3218. // if (!qstrName.isEmpty()) mapFinalValues.insert("record_name", qstrName);
  3219. // if (!instrumentType.isEmpty()) mapFinalValues.insert("instrument_type", instrumentType);
  3220. // qint64 storedFlags = (qint64)flags;
  3221. // mapFinalValues.insert("flags", QVariant::fromValue(storedFlags));
  3222. // // -------------------------------------------------
  3223. // // 0 Error, 1 Outgoing, 2 Incoming, 3 Activated, 4 Paid, 5 Payment Failed, 6 Failed Activating, 7 Canceled, 8 Expired, 9 Completed, 10 Killed
  3224. // const int nError = 0;
  3225. // const int nOutgoing = 1;
  3226. // const int nIncoming = 2;
  3227. // const int nActivated = 3;
  3228. // const int nPaid = 4;
  3229. // const int nPaymentFailed = 5; // Live agreement here and above this point.
  3230. // const int nFailedActivating = 6; // Dead agreement here and below this point.
  3231. // const int nCanceled = 7;
  3232. // const int nExpired = 8;
  3233. // const int nNoLongerActive = 9;
  3234. // const int nKilled = 10;
  3235. // if (recordmt.IsCanceled()) nNewestKnownState = nCanceled;
  3236. // else if (recordmt.IsExpired()) nNewestKnownState = nExpired;
  3237. // else if (recordmt.IsFinalReceipt())
  3238. // {
  3239. // nNewestKnownState = nNoLongerActive;
  3240. // // NOTE: I think it's possible to be both a finalReceipt AND a Notice.
  3241. // // How? Because the Nym is sent a finalReceipt notice when a cron item
  3242. // // stops running. (Market offer, payment plan, or smart contract.)
  3243. // // There are four finalReceipt RECEIPTS, in the case of market offer,
  3244. // // one for each of the four asset accounts involved, but there is also
  3245. // // a NOTICE finalReceipt that is sent to each of the two NYMs involved.
  3246. // //
  3247. // // ===> That's why it's so important that this "if final receipt" block
  3248. // // happens ABOVE the "else if notice" block you see just below here.
  3249. // // Because otherwise, the logic might take a "no longer active" notice
  3250. // // (finalReceipt+IsNotice) and mistakenly mark it as "Activated".
  3251. // //
  3252. // // Todo: Make sure this "finalreceipt + isnotice" contains the REASON
  3253. // // or CAUSE of the cron item to cease functioning, whether it expired,
  3254. // // or was killed by another Nym, etc. That way we can import that information
  3255. // // here and display it for the user. We do have expired. And we do have
  3256. // // canceled, but that only shows if I canceled it before he activated
  3257. // // it in the first place. It doesn't show if someone killed it while it
  3258. // // was already running.
  3259. // }
  3260. // else if (recordmt.IsNotice())
  3261. // {
  3262. // // IMPORTANT: Should ASSERT !isFinalReceipt() here, so the logic is preserved
  3263. // // that the above finalReceipt block comes just BEFORE this Notice block.
  3264. // bool bIsSuccess = false;
  3265. // if (recordmt.HasSuccess(bIsSuccess))
  3266. // {
  3267. // if (bIsSuccess) nNewestKnownState = nActivated;
  3268. // else nNewestKnownState = nFailedActivating;
  3269. // }
  3270. // }
  3271. // else if (recordmt.IsReceipt())
  3272. // {
  3273. // bool bIsSuccess = false;
  3274. // if (recordmt.HasSuccess(bIsSuccess))
  3275. // {
  3276. // if (bIsSuccess) nNewestKnownState = nPaid;
  3277. // else nNewestKnownState = nPaymentFailed;
  3278. // }
  3279. // }
  3280. // else if (recordmt.IsPending())
  3281. // {
  3282. // if (recordmt.IsOutgoing()) nNewestKnownState = nOutgoing;
  3283. // else nNewestKnownState = nIncoming;
  3284. // }
  3285. // // else if (blah blah blah) nNewestKnownState = 8; // Killed
  3286. // // TODO: What about if it's killed? Should be something on the finalReceipt that tells me whether it died naturally or was killed.
  3287. // // (There probably is, or there should be.)
  3288. // // ----------------------------------
  3289. // // If we already processed a finalReceipt previously, and now we're processing its related paymentReceipts,
  3290. // // (since they are coming from the recordBox and may not be in the order originally received...) then we know
  3291. // // the actual final state already. So we don't want to go backwards and set it back to "paid" again, in that case,
  3292. // // instead of keeping it at "finished." The below logic accomplishes this.
  3293. // //
  3294. // // 0 Error, 1 Outgoing, 2 Incoming, 3 Activated, 4 Paid, 5 Payment Failed, 6 Failed Activating, 7 Canceled, 8 Expired, 9 Completed, 10 Killed
  3295. // if (nNewestKnownState != nError)
  3296. // {
  3297. // if (nLastKnownState >= nFailedActivating)
  3298. // nNewestKnownState = nLastKnownState;
  3299. // else if (nLastKnownState >= nPaid && nNewestKnownState <= nActivated)
  3300. // nNewestKnownState = nLastKnownState;
  3301. // else if (nLastKnownState >= nActivated && nNewestKnownState < nActivated)
  3302. // nNewestKnownState = nLastKnownState;
  3303. // }
  3304. // // -------------------------------------------------
  3305. //// qDebug() << "DEBUGGING AddAgreementRecord. " << (recordmt.IsOutgoing() ? "OUT" : "IN") << ". receiptNum: " << receiptNum << " transNumDisplay: " << transNumDisplay << "\n";
  3306. // // -------------------------------------------------
  3307. // if (bRecordAlreadyExisted)
  3308. // {
  3309. // // With agreement receipts, in most cases, we either insert a new one
  3310. // // or just return since it's already there.
  3311. // // But there's this ONE case where we DO need to update an existing record.
  3312. // // It's when Payment Plan 757 comes in, and then later Notice 757 comes in
  3313. // // (like a cancellation notice.) So in THAT case, we need to update the "pending"
  3314. // // record to change it to "canceled."
  3315. // //
  3316. // if (MTContactHandler::getInstance()->UpdateAgreementReceiptRecord(nAgreementReceiptKey, mapFinalValues))
  3317. // {
  3318. // qstrReceiptBody = QString::fromStdString(recordmt.GetContents());
  3319. // bSuccessUpdatingReceipt = true;
  3320. // pModel->select(); // Reset the model since we just inserted a new record.
  3321. // // AH WAIT!!! We don't want to do this for EVERY record inserted, do we?
  3322. // // Just the LAST ONE.
  3323. // // TODO!
  3324. // }
  3325. // }
  3326. // else // Record didn't already exist in the DB, so we add it.
  3327. // { // AgreementReceipt table being updated here. Vs the Live Agreements, updated status below this block.
  3328. // pModel->database().transaction();
  3329. // // ---------------------------------
  3330. // QSqlRecord record = pModel->record();
  3331. // record.setGenerated("agreement_receipt_key", true);
  3332. // // ---------------------------------
  3333. // for (QMap<QString, QVariant>::iterator it_map = mapFinalValues.begin();
  3334. // it_map != mapFinalValues.end(); ++it_map)
  3335. // {
  3336. // const QString & qstrKey = it_map.key();
  3337. // const QVariant & qValue = it_map.value();
  3338. // record.setValue(qstrKey, qValue);
  3339. // }
  3340. // pModel->insertRecord(0, record);
  3341. // // ---------------------------------
  3342. // if (pModel->submitAll())
  3343. // {
  3344. // // Success.
  3345. // if (pModel->database().commit())
  3346. // {
  3347. // bSuccessAddingReceipt = true;
  3348. // nAgreementReceiptKey = DBHandler::getInstance()->queryInt("SELECT last_insert_rowid() from `agreement_receipt`", 0, 0);
  3349. // qstrReceiptBody = QString::fromStdString(recordmt.GetContents());
  3350. // }
  3351. // }
  3352. // else
  3353. // {
  3354. // pModel->database().rollback();
  3355. // qDebug() << "Database Write Error"
  3356. // << "The database reported an error: "
  3357. // << pModel->lastError().text();
  3358. // }
  3359. // }
  3360. // } // if pModel
  3361. // // ------------------------------------------------
  3362. // if (bSuccessAddingReceipt || bSuccessUpdatingReceipt)
  3363. // {
  3364. // if (nAgreementReceiptKey <= 0)
  3365. // {
  3366. // qDebug() << "AddAgreementRecord: Supposedly succeeded adding agreement receipt to database, but the resulting key is wrong! (Failure.)\n";
  3367. // return false;
  3368. // }
  3369. // else
  3370. // qDebug() << "AddAgreementRecord: Succeeded adding agreement receipt to database.\n";
  3371. // // -------------------------------------------
  3372. // if (!MTContactHandler::getInstance()->UpdateLiveAgreementRecord(nAgreementId, receiptNum, nNewestKnownState, tDate, qstrMemo))
  3373. // qDebug() << "AddAgreementRecord: Strange -- just failed trying to update a live agreement record.\n";
  3374. // else
  3375. // pAgreementModel->select();
  3376. // // -------------------------------------------
  3377. // if (bSuccessUpdatingReceipt &&
  3378. // !MTContactHandler::getInstance()->UpdateAgreementReceiptBody(nAgreementReceiptKey, qstrReceiptBody))
  3379. // {
  3380. // qDebug() << "AddAgreementRecord: Updated record, but then failed updating agreement receipt body.\n";
  3381. // return false;
  3382. // }
  3383. // else if (bSuccessAddingReceipt &&
  3384. // !MTContactHandler::getInstance()->CreateAgreementReceiptBody(nAgreementReceiptKey, qstrReceiptBody))
  3385. // {
  3386. // qDebug() << "AddAgreementRecord: ...but then failed creating agreement receipt body.\n";
  3387. // return false;
  3388. // }
  3389. // }
  3390. // // ------------------------------------------------
  3391. // return bSuccessAddingReceipt;
  3392. //}
  3393. //// ------------------------------
  3394. //// Adds or updates.
  3395. //// The payment archive stores up to multiple receipts per record.
  3396. //// The primary key is the "display txn ID"
  3397. ////
  3398. //bool Moneychanger::AddPaymentToPmntArchive(opentxs::OTRecord& recordmt, const bool bCanDeleteRecord/*=true*/)
  3399. //{
  3400. // ModelPayments::PaymentFlags flags = ModelPayments::NoFlags;
  3401. // QPointer<ModelPayments> pModel = DBHandler::getInstance()->getPaymentModel();
  3402. // bool bSuccessAddingPmnt = false;
  3403. // QString qstrBody(""), qstrPendingBody("");
  3404. // QMap<QString, QVariant> mapFinalValues;
  3405. // bool bRecordAlreadyExisted = false;
  3406. // int nPreExistingPaymentId = 0;
  3407. // if (pModel)
  3408. // {
  3409. // // ---------------------------------
  3410. // if (recordmt.IsSpecialMail()) flags |= ModelPayments::IsSpecialMail;
  3411. // if (recordmt.IsPending()) flags |= ModelPayments::IsPending;
  3412. // if (recordmt.IsOutgoing()) flags |= ModelPayments::IsOutgoing;
  3413. // if (recordmt.IsRecord()) flags |= ModelPayments::IsRecord;
  3414. // if (recordmt.IsReceipt()) flags |= ModelPayments::IsReceipt;
  3415. // if (recordmt.IsFinalReceipt()) flags |= ModelPayments::IsFinalReceipt;
  3416. // if (recordmt.IsMail()) flags |= ModelPayments::IsMail;
  3417. // if (recordmt.IsTransfer()) flags |= ModelPayments::IsTransfer;
  3418. // if (recordmt.IsCheque()) flags |= ModelPayments::IsCheque;
  3419. // if (recordmt.IsInvoice()) flags |= ModelPayments::IsInvoice;
  3420. // if (recordmt.IsVoucher()) flags |= ModelPayments::IsVoucher;
  3421. // if (recordmt.IsContract()) flags |= ModelPayments::IsContract;
  3422. // if (recordmt.IsPaymentPlan()) flags |= ModelPayments::IsPaymentPlan;
  3423. // if (recordmt.IsCash()) flags |= ModelPayments::IsCash;
  3424. // if (recordmt.IsNotice()) flags |= ModelPayments::IsNotice;
  3425. // if (recordmt.IsExpired()) flags |= ModelPayments::IsExpired;
  3426. // if (recordmt.IsCanceled()) flags |= ModelPayments::IsCanceled;
  3427. // if (recordmt.CanDeleteRecord()) flags |= ModelPayments::CanDelete;
  3428. // if (recordmt.CanAcceptIncoming()) flags |= ModelPayments::CanAcceptIncoming;
  3429. // if (recordmt.CanDiscardIncoming()) flags |= ModelPayments::CanDiscardIncoming;
  3430. // if (recordmt.CanCancelOutgoing()) flags |= ModelPayments::CanCancelOutgoing;
  3431. // if (recordmt.CanDiscardOutgoingCash()) flags |= ModelPayments::CanDiscardOutgoingCash;
  3432. // // ---------------------------------
  3433. // QString myNymID;
  3434. // if (!recordmt.GetNymID().empty())
  3435. // myNymID = QString::fromStdString(recordmt.GetNymID());
  3436. // // ---------------------------------
  3437. // QString myAcctID;
  3438. // if (!recordmt.GetAccountID().empty())
  3439. // myAcctID = QString::fromStdString(recordmt.GetAccountID());
  3440. // // ---------------------------------
  3441. // QString instrumentType;
  3442. // if (!recordmt.GetInstrumentType().empty())
  3443. // instrumentType = QString::fromStdString(recordmt.GetInstrumentType());
  3444. // // ---------------------------------
  3445. // QString myAssetTypeID;
  3446. // if (!recordmt.GetUnitTypeID().empty())
  3447. // myAssetTypeID = QString::fromStdString(recordmt.GetUnitTypeID());
  3448. // // ---------------------------------
  3449. // QString myAddress;
  3450. // if (!recordmt.GetAddress().empty())
  3451. // myAddress = QString::fromStdString(recordmt.GetAddress());
  3452. //// myAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetAddress()));
  3453. // // ---------------------------------
  3454. // QString senderNymID, senderAccountID, senderAddress,
  3455. // recipientNymID, recipientAccountID, recipientAddress;
  3456. // if (recordmt.IsOutgoing())
  3457. // {
  3458. // if (!recordmt.GetOtherNymID().empty())
  3459. // recipientNymID = QString::fromStdString(recordmt.GetOtherNymID());
  3460. // if (!recordmt.GetOtherAccountID().empty())
  3461. // recipientAccountID = QString::fromStdString(recordmt.GetOtherAccountID());
  3462. // if (!recordmt.GetOtherAddress().empty())
  3463. // recipientAddress = QString::fromStdString(recordmt.GetOtherAddress());
  3464. //// recipientAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  3465. // }
  3466. // else
  3467. // {
  3468. // if (!recordmt.GetOtherNymID().empty())
  3469. // senderNymID = QString::fromStdString(recordmt.GetOtherNymID());
  3470. // if (!recordmt.GetOtherAccountID().empty())
  3471. // senderAccountID = QString::fromStdString(recordmt.GetOtherAccountID());
  3472. // if (!recordmt.GetOtherAddress().empty())
  3473. // senderAddress = QString::fromStdString(recordmt.GetOtherAddress());
  3474. //// senderAddress = MTContactHandler::Encode(QString::fromStdString(recordmt.GetOtherAddress()));
  3475. // }
  3476. // // ---------------------------------
  3477. // QString msgNotaryID, pmntNotaryID, msgType, msgTypeDisplay;
  3478. // if (!recordmt.GetMsgNotaryID().empty())
  3479. // msgNotaryID = QString::fromStdString(recordmt.GetMsgNotaryID());
  3480. // if (!recordmt.GetPmntNotaryID().empty())
  3481. // pmntNotaryID = QString::fromStdString(recordmt.GetPmntNotaryID());
  3482. // if (!recordmt.GetMsgType().empty())
  3483. // msgType = QString::fromStdString(recordmt.GetMsgType());
  3484. //// msgType = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgType()));
  3485. // if (!recordmt.GetMsgTypeDisplay().empty())
  3486. // msgTypeDisplay = QString::fromStdString(recordmt.GetMsgTypeDisplay());
  3487. //// msgTypeDisplay = MTContactHandler::Encode(QString::fromStdString(recordmt.GetMsgTypeDisplay()));
  3488. // // ---------------------------------
  3489. // time64_t tDate = static_cast<time64_t>(ot_.Exec().StringToLong(recordmt.GetDate()));
  3490. // int64_t transNum = recordmt.GetTransactionNum();
  3491. // int64_t transNumDisplay = recordmt.GetTransNumForDisplay();
  3492. // int64_t lAmount = ot_.Exec().StringToLong(recordmt.GetAmount());
  3493. //// qDebug() << "DEBUGGING! recordmt.GetAmount(): " << QString::fromStdString(recordmt.GetAmount())
  3494. //// << " lAmount: " << lAmount << "\n";
  3495. // int nPending = recordmt.CanDeleteRecord() ? 0 : 1;
  3496. // int nCompleted = recordmt.CanDeleteRecord() ? 1 : 0;
  3497. // // ---------------------------------
  3498. // std::string str_Name = recordmt.GetName();
  3499. // QString qstrName;
  3500. // if (!str_Name.empty())
  3501. // qstrName = MTContactHandler::Encode(QString::fromStdString(str_Name));
  3502. // // ---------------------------------
  3503. // std::string str_Memo = recordmt.HasMemo() ? recordmt.GetMemo() : "";
  3504. // QString qstrMemo;
  3505. // if (!str_Memo.empty())
  3506. // qstrMemo = MTContactHandler::Encode(QString::fromStdString(str_Memo));
  3507. // // ---------------------------------
  3508. // std::string str_mailDescription;
  3509. // recordmt.FormatDescription(str_mailDescription);
  3510. // QString mailDescription;
  3511. // if (!str_mailDescription.empty())
  3512. // mailDescription = MTContactHandler::Encode(QString::fromStdString(str_mailDescription));
  3513. // // ---------------------------------
  3514. // const int nFolder = recordmt.IsOutgoing() ? 0 : 1; // 0 for moneychanger's outbox, and 1 for inbox.
  3515. // // ---------------------------------
  3516. // // First let's see if a record already exists:
  3517. // //
  3518. // nPreExistingPaymentId = MTContactHandler::getInstance()->GetPaymentIdByTxnDisplayId(transNumDisplay, myNymID);
  3519. // bRecordAlreadyExisted = (nPreExistingPaymentId > 0);
  3520. // // ------------------------------------------
  3521. // // We'll start by putting all the values into our map,
  3522. // // so we can then use that map when creating or updating
  3523. // // database records.
  3524. // //
  3525. // // if (bRecordAlreadyExisted) mapFinalValues.insert("payment_id", nPreExistingPaymentId);
  3526. // // Note: No need to insert this one.
  3527. // if (!myNymID.isEmpty()) mapFinalValues.insert("my_nym_id", myNymID);
  3528. // if (!myAcctID.isEmpty()) mapFinalValues.insert("my_acct_id", myAcctID);
  3529. // if (!myAssetTypeID.isEmpty()) mapFinalValues.insert("my_asset_type_id", myAssetTypeID);
  3530. // if (!myAddress.isEmpty()) mapFinalValues.insert("my_address", myAddress);
  3531. // if (!senderNymID.isEmpty()) mapFinalValues.insert("sender_nym_id", senderNymID);
  3532. // if (!senderAccountID.isEmpty()) mapFinalValues.insert("sender_acct_id", senderAccountID);
  3533. // if (!senderAddress.isEmpty()) mapFinalValues.insert("sender_address", senderAddress);
  3534. // if (!recipientNymID.isEmpty()) mapFinalValues.insert("recipient_nym_id", recipientNymID);
  3535. // if (!recipientAccountID.isEmpty()) mapFinalValues.insert("recipient_acct_id", recipientAccountID);
  3536. // if (!recipientAddress.isEmpty()) mapFinalValues.insert("recipient_address", recipientAddress);
  3537. // if (transNum > 0) mapFinalValues.insert("txn_id", QVariant::fromValue(transNum));
  3538. // if (transNumDisplay > 0) mapFinalValues.insert("txn_id_display", QVariant::fromValue(transNumDisplay));
  3539. //// qDebug() << "DEBUGGING AddPaymentToPmntArchive. " << (recordmt.IsOutgoing() ? "OUT" : "IN") << ". transNum: " << transNum << " transNumDisplay: " << transNumDisplay << "\n";
  3540. // // I receive a cheque. This is the incoming cheque I'm receiving.
  3541. // if (lAmount != 0) mapFinalValues.insert("amount", QVariant::fromValue(lAmount));
  3542. // if (tDate > 0) mapFinalValues.insert("timestamp", QVariant::fromValue(tDate));
  3543. // if (nPending > 0) mapFinalValues.insert("pending_found", QVariant::fromValue(nPending));
  3544. // if (nCompleted > 0) mapFinalValues.insert("completed_found", QVariant::fromValue(nCompleted));
  3545. // if (!msgType.isEmpty()) mapFinalValues.insert("method_type", msgType);
  3546. // if (!msgTypeDisplay.isEmpty()) mapFinalValues.insert("method_type_display", msgTypeDisplay);
  3547. // if (!msgNotaryID.isEmpty()) mapFinalValues.insert("msg_notary_id", msgNotaryID);
  3548. // if (!pmntNotaryID.isEmpty()) mapFinalValues.insert("pmnt_notary_id", pmntNotaryID);
  3549. // if (!qstrMemo.isEmpty()) mapFinalValues.insert("memo", qstrMemo);
  3550. // if (!mailDescription.isEmpty()) mapFinalValues.insert("description", mailDescription);
  3551. // if (!qstrName.isEmpty()) mapFinalValues.insert("record_name", qstrName);
  3552. // if (!instrumentType.isEmpty()) mapFinalValues.insert("instrument_type", instrumentType);
  3553. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_read", QVariant::fromValue(recordmt.IsOutgoing() ? 1 : 0));
  3554. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_replied", QVariant::fromValue(0));
  3555. // if (!bRecordAlreadyExisted) mapFinalValues.insert("have_forwarded", QVariant::fromValue(0));
  3556. // qint64 storedFlags = (qint64)flags;
  3557. // mapFinalValues.insert("folder", QVariant::fromValue(nFolder));
  3558. // mapFinalValues.insert("flags", QVariant::fromValue(storedFlags));
  3559. // // -------------------------------------------------
  3560. // bool bAddAsPending = false;
  3561. // if (!bCanDeleteRecord) bAddAsPending = true;
  3562. // else bAddAsPending = false;
  3563. // // -------------------------------------------------
  3564. // if ( (recordmt.IsNotice()) )
  3565. // {
  3566. // bAddAsPending = true;
  3567. // }
  3568. // // -------------------------------------------------
  3569. // if (
  3570. // (recordmt.IsReceipt())
  3571. // )
  3572. // {
  3573. // bAddAsPending = false;
  3574. // }
  3575. // // -------------------------------------------------
  3576. // if (bAddAsPending) qstrPendingBody = QString::fromStdString(recordmt.GetContents());
  3577. // else qstrBody = QString::fromStdString(recordmt.GetContents());
  3578. // // -------------------------------------------------
  3579. // if (bRecordAlreadyExisted)
  3580. // {
  3581. // // Success.
  3582. // if (MTContactHandler::getInstance()->UpdatePaymentRecord(nPreExistingPaymentId, mapFinalValues))
  3583. // {
  3584. // bSuccessAddingPmnt = true;
  3585. // pModel->select(); // Reset the model since we just inserted a new record.
  3586. // // AH WAIT!!! We don't want to do this for EVERY record inserted, do we?
  3587. // // Just the LAST ONE.
  3588. // // TODO!
  3589. // }
  3590. // }
  3591. // else // Record doesn't already exist in the database.
  3592. // { // In that case we can use some code we already had:
  3593. // pModel->database().transaction();
  3594. // // ---------------------------------
  3595. // QSqlRecord record = pModel->record();
  3596. // record.setGenerated("payment_id", true);
  3597. // // ---------------------------------
  3598. // for (QMap<QString, QVariant>::iterator it_map = mapFinalValues.begin();
  3599. // it_map != mapFinalValues.end(); ++it_map)
  3600. // {
  3601. // const QString & qstrKey = it_map.key();
  3602. // const QVariant & qValue = it_map.value();
  3603. // record.setValue(qstrKey, qValue);
  3604. // }
  3605. // pModel->insertRecord(0, record);
  3606. // // ---------------------------------
  3607. // if (pModel->submitAll())
  3608. // {
  3609. // // Success.
  3610. // if (pModel->database().commit())
  3611. // bSuccessAddingPmnt = true;
  3612. // }
  3613. // else
  3614. // {
  3615. // pModel->database().rollback();
  3616. // qDebug() << "Database Write Error" <<
  3617. // "The database reported an error: " <<
  3618. // pModel->lastError().text();
  3619. // }
  3620. // } // Record didn't already exist. (Adding new.)
  3621. // } // if pModel
  3622. // // ------------------------------------------------
  3623. // if (bSuccessAddingPmnt)
  3624. // {
  3625. // qDebug() << "AddPaymentToPmntArchive: Succeeded adding payment record to database.\n";
  3626. // if (bRecordAlreadyExisted)
  3627. // {
  3628. // if (!MTContactHandler::getInstance()->UpdatePaymentBody(nPreExistingPaymentId, qstrBody, qstrPendingBody))
  3629. // {
  3630. // qDebug() << "AddPaymentToPmntArchive: ...but then failed updating payment body and/or pending body.\n";
  3631. // return false;
  3632. // }
  3633. // }
  3634. // // ------------------------
  3635. // else
  3636. // {
  3637. // if (!MTContactHandler::getInstance()->CreatePaymentBody(qstrBody, qstrPendingBody))
  3638. // {
  3639. // qDebug() << "AddPaymentToPmntArchive: ...but then failed creating payment body and/or pending body.\n";
  3640. // return false;
  3641. // }
  3642. // }
  3643. // }
  3644. // // ------------------------------------------------
  3645. // return bSuccessAddingPmnt;
  3646. //}
  3647. // message StorageThreadItem {
  3648. // optional uint32 version = 1;
  3649. // optional string id = 2;
  3650. // optional uint64 index = 3;
  3651. // optional uint64 time = 4;
  3652. // optional uint32 box = 5;
  3653. // optional string account = 6;
  3654. // optional bool unread = 7;
  3655. // }
  3656. // enum class StorageBox : std::uint8_t {
  3657. // SENTPEERREQUEST = 0,
  3658. // INCOMINGPEERREQUEST = 1,
  3659. // SENTPEERREPLY = 2,
  3660. // INCOMINGPEERREPLY = 3,
  3661. // FINISHEDPEERREQUEST = 4,
  3662. // FINISHEDPEERREPLY = 5,
  3663. // PROCESSEDPEERREQUEST = 6,
  3664. // PROCESSEDPEERREPLY = 7,
  3665. // MAILINBOX = 8,
  3666. // MAILOUTBOX = 9
  3667. // };
  3668. // Loop through conversations owned by this Nym and import copies to
  3669. // local DB for the GUI to use. Re-import if necessary since they
  3670. // change over time.
  3671. //
  3672. void Moneychanger::ImportConversationsForNym(const std::string & str_nym_id,
  3673. MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  3674. SetNymThreadAndItem & setNewlyAddedNymThreadAndItem) // output
  3675. {
  3676. OT_ASSERT(!str_nym_id.empty());
  3677. // ----------------------------------------------
  3678. opentxs::ObjectList threadList = ot_.Activity().Threads(opentxs::Identifier::Factory(str_nym_id));
  3679. opentxs::ObjectList::const_iterator ci = threadList.begin();
  3680. while (threadList.end() != ci)
  3681. {
  3682. const std::pair<std::string, std::string> & threadInfo = *ci;
  3683. const std::string & str_thread_id = threadInfo.first;
  3684. const std::string & str_thread_name = threadInfo.second;
  3685. // ----------------------------------------------
  3686. std::shared_ptr<opentxs::proto::StorageThread> thread;
  3687. ot_.Storage().Load(str_nym_id, str_thread_id, thread);
  3688. // ----------------------------------------------
  3689. if (!thread) {
  3690. ++ci;
  3691. continue;
  3692. }
  3693. // ----------------------------------------------
  3694. if (false == ImportConversationForNym(str_nym_id, str_thread_id, str_thread_name, thread, mapOfSetsOfAlreadyImportedMsgs, setNewlyAddedNymThreadAndItem)) {
  3695. ++ci;
  3696. continue;
  3697. }
  3698. // ----------------------------------------------
  3699. // Anything else we might want to do can be put right here.
  3700. // Basically, for those times when you need to do something
  3701. // immediately after importing a conversation.
  3702. // ----------------------------------------------
  3703. ++ci;
  3704. }
  3705. }
  3706. bool Moneychanger::ImportConversationForNym(const std::string & str_nym_id,
  3707. const std::string & str_thread_id,
  3708. const std::string & str_thread_name,
  3709. std::shared_ptr<opentxs::proto::StorageThread> & thread,
  3710. MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  3711. SetNymThreadAndItem & setNewlyAddedNymThreadAndItem) // output
  3712. {
  3713. if (!thread)
  3714. return false;
  3715. // ----------------------------------------------
  3716. if (thread->participant_size() <= 0)
  3717. return false;
  3718. // ----------------------------------------------
  3719. OT_ASSERT(0 == str_thread_id.compare(thread->id()));
  3720. // Note: in a conversation with a single contact, str_thread_id itself
  3721. // is also that ContactId, so I don't have to grab the first participant
  3722. // for his ID.
  3723. // If it's a group conversation, I ALSOS don't need the participants' IDs
  3724. // (in this case) since we're here mainly to import the conversation ID
  3725. // itself, which again would be str_thread_id.
  3726. //
  3727. // I think the only time I care about a specific participant's ID is when
  3728. // I'm trying to message that guy 1-on-1, and I just want to see if there's
  3729. // a conversation already there between us (on the GUI) before I otherwise
  3730. // create one and add it to the tree. But it seems, again, I can just use
  3731. // the contact ID (which is also the thread id in that case) to lookup the
  3732. // conversation on the tree.
  3733. //
  3734. //const std::string str_participant_contact_id = thread->participant(0);
  3735. const QString qstrMyNymId = QString::fromStdString(str_nym_id);
  3736. const QString qstrThreadId = QString::fromStdString(str_thread_id);
  3737. QString qstrThreadName = QString::fromStdString(str_thread_name);
  3738. // ----------------------------------------------
  3739. if (qstrThreadName.isEmpty()) {
  3740. qstrThreadName = QString("(%1)").arg(tr("Conversation name was empty"));
  3741. }
  3742. // ----------------------------------------------
  3743. // qstrMyNymId, qstrThreadId, qstrThreadName;
  3744. // If some of this seems like I did it weird, it's for lazy evaluation / optimization
  3745. // purposes, since the import can be rather slow.
  3746. // ----------------------------------------------
  3747. // So we don't continually re-import thread items that we already imported before.
  3748. //
  3749. PtrSetOfStrings pAlreadyImportedIds; // nullptr so far.
  3750. bool bHaveAlreadyImportedAnyIds = false;
  3751. bool bHaveGrabbedTheAlreadyImportedIds = false;
  3752. // ----------------------------------------------
  3753. // Loop through messages in this conversation, create or update each conversation_msg
  3754. // record based on the thread item it's importing from. Assume we may re-import the
  3755. // same records, and we don't want duplicates.
  3756. //
  3757. bool bConversationExistsInDB = false; // so far. (We'll check in a lazy way).
  3758. for (const auto & item : thread->item()) //opentxs::proto::StorageThreadItem & item
  3759. {
  3760. // QString create_conversation_msg_table = "CREATE TABLE IF NOT EXISTS conversation_msg"
  3761. // "(conversation_id TEXT,"
  3762. // " my_nym_id TEXT,"
  3763. // " thread_item_id TEXT," // Note: this field is also in message_body table
  3764. // " timestamp INTEGER,"
  3765. // " box INTEGER,"
  3766. // " account TEXT,"
  3767. // " unread INTEGER,"
  3768. // " PRIMARY KEY (conversation_id, my_nym_id, thread_item_id)"
  3769. // ")";
  3770. // --------------------------------------------
  3771. const std::string thread_item_id = item.has_id() ? item.id() : "" ;
  3772. const std::string thread_item_account (item.has_account() ? item.account() : "");
  3773. if (thread_item_id.empty())
  3774. {
  3775. qDebug() << "Found a conversational thread item with a blank ID field. Strange, probably should not ever be happening. (Skipping it).";
  3776. continue;
  3777. }
  3778. // --------------------------------------------
  3779. // const QString qstrMyNymId = QString::fromStdString(str_nym_id);
  3780. // const QString qstrThreadId = QString::fromStdString(str_thread_id);
  3781. const QString qstrThreadItemId = QString::fromStdString(thread_item_id);
  3782. const QString qstrThreadItemAccountId = QString::fromStdString(thread_item_account);
  3783. // --------------------------------------------
  3784. const int thread_item_box = item.has_box() ? item.box() : 0;
  3785. const time64_t thread_item_timestamp = item.has_time() ? item.time() : 0;
  3786. const bool thread_item_unread = item.has_unread() ? item.unread() : false;
  3787. // --------------------------------------------
  3788. // By this point we know there's definitely an item, we need to either import it
  3789. // or ignore it (if we already imported it in the past).
  3790. // We'll also go ahead and grab the IDs from our local DB of the ones we've already imported.
  3791. // We avoided doing that up until now for optimization reasons.
  3792. //
  3793. if (!bHaveGrabbedTheAlreadyImportedIds)
  3794. {
  3795. // typedef std::set<std::string> SetOfStrings;
  3796. // typedef std::shared_ptr<SetOfStrings> PtrSetOfStrings;
  3797. // typedef std::pair<std::string, std::string> PairOfStrings;
  3798. // typedef std::map<PairOfStrings, PtrSetOfStrings> MapOfPtrSetsOfStrings;
  3799. MapOfPtrSetsOfStrings::iterator it_map = mapOfSetsOfAlreadyImportedMsgs.find(PairOfStrings{str_nym_id, str_thread_id}); // Find the conversation on our lookup table.
  3800. if (mapOfSetsOfAlreadyImportedMsgs.end() != it_map) // the set was already on the map (conversation already on map of conversations by nym/threadIDs.)
  3801. {
  3802. bHaveGrabbedTheAlreadyImportedIds = true;
  3803. pAlreadyImportedIds = it_map->second;
  3804. }
  3805. else // This is the real part. Above block is just the optimization.
  3806. {
  3807. SetOfStrings * pSet = MTContactHandler::getInstance()->selectThreadItemIdsForNymAndConversation(qstrMyNymId, qstrThreadId);
  3808. if (nullptr != pSet) // We have some thread items for the given pair<nym/thread_ID>, which are already imported into our local DB.
  3809. {
  3810. pAlreadyImportedIds.reset( pSet );
  3811. }
  3812. else // We had none already imported for this nymId and ThreadID, but we'll go ahead and instantiate the shared_ptr (with an empty set) so it's on the map and consistent with the others.
  3813. { // (After all, we're currently looping through the opentxs thread items for THIS nym/threadID, so we KNOW we're GOING to be adding an item to it THIS iteration).
  3814. // This also makes it easy for us to assume, for the duration of the loop, that pAlreadyImportedIds is VALID. (Should assert in fact) since it should have been
  3815. // either set on a previous iteration of this loop, or on THIS iteration. Either way, below this point in the loop, we can now assume that it's good.
  3816. //
  3817. pAlreadyImportedIds.reset( new SetOfStrings );
  3818. }
  3819. bHaveGrabbedTheAlreadyImportedIds = true;
  3820. // for optimization (lookup table)
  3821. PairOfStrings nymIdAndThreadId{str_nym_id, str_thread_id};
  3822. std::pair<PairOfStrings, PtrSetOfStrings> the_pair = std::make_pair(nymIdAndThreadId, pAlreadyImportedIds);
  3823. mapOfSetsOfAlreadyImportedMsgs.insert(the_pair);
  3824. }
  3825. // --------------------------------------------
  3826. // Since we can assume from here on out that pAlreadyImportedIds is always a good pointer, anywhere below this point
  3827. // in the entire loop (see above comment) I'll just assert.
  3828. //
  3829. OT_ASSERT_MSG(pAlreadyImportedIds, "Should never happen: pAlreadyImportedIds contained nullptr.");
  3830. bHaveAlreadyImportedAnyIds = (pAlreadyImportedIds->size() > 0);
  3831. // --------------------------------------------
  3832. }
  3833. // --------------------------------------------
  3834. // I do the same assert here, since the above block will not occur every iteration of this loop.
  3835. //
  3836. OT_ASSERT_MSG(pAlreadyImportedIds, "Should never happen: pAlreadyImportedIds contained nullptr.");
  3837. // --------------------------------------------
  3838. // Now let's SEE if we have already previously imported THIS thread item (for the loop iteration
  3839. // we're on currently).
  3840. //
  3841. bool bHaveAlreadyImportedThisId = false;
  3842. if (bHaveAlreadyImportedAnyIds) // we only bother looking if we've previously imported ANY items for the current thread.
  3843. {
  3844. const std::set<std::string>::iterator it = pAlreadyImportedIds->find(thread_item_id);
  3845. bHaveAlreadyImportedThisId = (pAlreadyImportedIds->end() != it); // If true, no need to re-import this thread item.
  3846. }
  3847. // --------------------------------------------
  3848. // Make sure we have the conversation itself, before adding the
  3849. // conversational item.
  3850. // Update conversation_name also.
  3851. if (!bHaveAlreadyImportedThisId && !bConversationExistsInDB)
  3852. {
  3853. bConversationExistsInDB = MTContactHandler::getInstance()->EnsureConversationExists(qstrMyNymId, qstrThreadId, qstrThreadName);
  3854. if (!bConversationExistsInDB) {
  3855. qDebug() << "Moneychanger::ImportConversationForNym: Somehow failed to get or create conversation in DB when trying to import a conversational thread item.";
  3856. return false;
  3857. }
  3858. // else
  3859. // {
  3860. // Since we just imported this conversation (NOT ANY ITEMS YET, NECESSARILY) to the DB,
  3861. // *AND* since it wasn't previously there, we'll go ahead and add it to our lookup table
  3862. // as well.
  3863. //
  3864. // UPDATE: No need, due to some code higher up in this function, we already know for a
  3865. // fact that pAlreadyImportedIds is a valid sharedPtr to a std::set<std::string>,
  3866. // and it's already pointing to an instantiated set, that's already on the map, for
  3867. // the appropriate nym/thread ids.
  3868. //
  3869. // Of course we still need to insert the thread ITEM to it, for this iteration, but that
  3870. // happens below.
  3871. // }
  3872. }
  3873. // bConversationExistsInDB is now definitely true, below this point.
  3874. // --------------------------------------------
  3875. //
  3876. bool bItemExistsInDB = false;
  3877. if (bHaveAlreadyImportedThisId) // If it's on the lookup table, no need to hit the DB.
  3878. {
  3879. bItemExistsInDB = true;
  3880. }
  3881. else // We need to import this thread item -- it's never been imported before.
  3882. {
  3883. bItemExistsInDB = MTContactHandler::getInstance()->EnsureConversationItemExists(qstrMyNymId, qstrThreadId, qstrThreadItemId,
  3884. qstrThreadItemAccountId, thread_item_box,
  3885. thread_item_timestamp, thread_item_unread);
  3886. }
  3887. // --------------------------------------------
  3888. if (bItemExistsInDB)
  3889. {
  3890. if (!bHaveAlreadyImportedThisId) // This means we JUST NOW imported it to DB
  3891. { // (It wasn't previously there until this current loop iteration).
  3892. // So let's add it to our lookup table.
  3893. // (Just as we did above when we searched for this item in the DB
  3894. // when it wasn't found in the lookup table. If found in the DB,
  3895. // we add to the looktable table then as well.)
  3896. // And remember, the lookup table might ALREADY have an element for the thread
  3897. // itself, so we need to add the item to the existing one if that's found.
  3898. //
  3899. // UPDATE: The lookup table now DEFINITELY already has an element for the relevant
  3900. // thread. And pAlreadyImportedIds is DEFINITELY a valid shared_ptr to a std::set<std::string>
  3901. // of the thread item IDs, and it's definitely already on the lookup table map for the correct
  3902. // nym/threadID.
  3903. // So we don't have to search mapOfSetsOfAlreadyImportedMsgs here anymore. The map is already
  3904. // set up, and pAlreadyImportedIds is already good, and we can insert the new thread item ID
  3905. // into it.
  3906. //
  3907. pAlreadyImportedIds->insert(thread_item_id); // adding to lookup table since it's a new thread item that was imported.
  3908. // // NymID, (conversational) Thread Id, Thread Item Id.
  3909. // typedef std::tuple<std::string, std::string, std::string> TupleNymThreadAndItem;
  3910. // typedef std::shared_ptr<TupleNymThreadAndItem> PtrNymThreadAndItem;
  3911. // typedef std::set<PtrNymThreadAndItem> SetNymThreadAndItem;
  3912. // Add the Nym / Thread item ID pair to an output parameter so the caller will know
  3913. // later on, which ones need the message body imported for the first timne, versus which ones
  3914. // we just "ensured" were already there.
  3915. // UPDATE: hell, let's add the thread id while we're at it.
  3916. //
  3917. setNewlyAddedNymThreadAndItem.insert(PtrNymThreadAndItem{new TupleNymThreadAndItem{str_nym_id, str_thread_id, thread_item_id} });
  3918. }
  3919. // --------------------
  3920. // By this point, we know the conversational item is in the DB, AND it's in the lookup table.
  3921. // Done with this iteration.
  3922. }
  3923. else {
  3924. qDebug() << "Moneychanger::ImportConversationForNym: Somehow failed to get or create conversation ITEM in DB.";
  3925. return false;
  3926. }
  3927. // ----------------------------------------------
  3928. } // for
  3929. return true;
  3930. }
  3931. //void Moneychanger::modifyRecords()
  3932. //{
  3933. // MapOfPtrSetsOfStrings mapOfSetsOfAlreadyImportedMsgs; // key is a std::pair composed of nym_id/thread_id; value is shared_ptr to std::set<std::string> of thread_item_ids.
  3934. // MapOfConversationsByNym mapOfConversationsByNym; // key is nym_id, value is shared_ptr to std::set<std::string> of thread_ids.
  3935. //// typedef std::tuple<std::string, std::string, std::string> TupleNymThreadAndItem;
  3936. //// typedef std::shared_ptr<TupleNymThreadAndItem> PtrNymThreadAndItem;
  3937. //// typedef std::set<PtrNymThreadAndItem> SetNymThreadAndItem;
  3938. // SetNymThreadAndItem setNewlyAddedNymThreadAndItem;
  3939. // // -------------------------------------------------------------------
  3940. // const int32_t nymCount = ot_.Exec().GetNymCount();
  3941. // for ( int32_t nymIndex = 0; nymIndex < nymCount; ++nymIndex)
  3942. // {
  3943. // const std::string nymId = ot_.Exec().GetNym_ID(nymIndex);
  3944. // const QString qstrMyNymId = QString::fromStdString(nymId);
  3945. // // typedef std::set<std::string> SetOfStrings;
  3946. // // typedef std::shared_ptr<SetOfStrings> PtrSetOfStrings;
  3947. // // typedef std::pair<std::string, std::string> PairOfStrings;
  3948. // // typedef std::map<PairOfStrings, PtrSetOfStrings> MapOfPtrSetsOfStrings;
  3949. // // typedef std::map<std::string, PtrSetOfStrings> MapOfConversationsByNym;
  3950. // // Before we import the RecordList, we have to iterate through
  3951. // // the conversations, and any messages therein, and continually re-import
  3952. // // them (since the lifecycle items may have updated since last time).
  3953. // //
  3954. // // We do NOT delete anything; we just import the conversations and messages
  3955. // // into the GUI DB for later.
  3956. // //
  3957. // // UPDATE: FOr now I'm adding lookup tables for thread-item-id to thread-id,
  3958. // // (that's conversational thread) so I can later find the thread id using the
  3959. // // thread-item-id.
  3960. // // First that allows me to determine if a Nymn has ever seen part of a given
  3961. // // conversation before at all. Second, it allows me to determine, without
  3962. // // a fresh database lookup each time, for each thread-item-id, whether or not
  3963. // // it has already been imported into my local database. (Thus sparing me from
  3964. // // having to re-import it, in that case).
  3965. // // That's why I ImportConversationsForNym and THEN import the record list.
  3966. // // Because the record list has the thread-item-id for each record, but NOT its
  3967. // // corresponding thread ID. But that's okay, since I already imported the
  3968. // // conversations AND put them into a lookup table,
  3969. // //
  3970. // // This call here checks the lookup table to see if a given msg has already
  3971. // // been imported. If it hasn't, then it checks the local database to see if
  3972. // // it's there. When it does that, it loads ALL the thread IDs for a given Nym
  3973. // // at the same time (into the lookup table) so it doesn't have to hit the DB
  3974. // // every single time for each thread-item-id in that thread. (Since it has
  3975. // // to loop through all of those).
  3976. // //
  3977. // ImportConversationsForNym(nymId, mapOfSetsOfAlreadyImportedMsgs,
  3978. // setNewlyAddedNymThreadAndItem); // output here, for newly-imported items.
  3979. // // ---------------------
  3980. // // Obviously this has to go under the above call.
  3981. // //
  3982. // PtrSetOfStrings pPreimportedConversationIdsForNym{
  3983. // MTContactHandler::getInstance()->selectPreimportedConversationIdsForNym(qstrMyNymId)};
  3984. // mapOfConversationsByNym.insert(std::pair<std::string,PtrSetOfStrings>(
  3985. // nymId,
  3986. // pPreimportedConversationIdsForNym)
  3987. // );
  3988. // }
  3989. // // By this point we've loaded up lookup tables for the nymId, threadId, and ThreadItemId.
  3990. // // We've also imported the messages that we hadn't previously imported
  3991. // // (and ONLY those -- with no re-importing).
  3992. // // That way below, when we call processImportRecord, we will be able to skip those
  3993. // // thread item IDs that have been previously imported already. (WithOUT having to
  3994. // // search our local DB for each one to see if it's already there.)
  3995. // // -------------------------------------------------------
  3996. //// const int listSize = GetRecordlist().size();
  3997. //// // -------------------------------------------------------
  3998. //// // Delete the market receipts (since they are already archived in other places)
  3999. //// // and find any finalReceipts that correspond to those, so we can add them
  4000. //// // to the trade archive table as well (and delete them as well.)
  4001. //// // Leave any other final receipts, since they may correspond to offers that
  4002. //// // completed without a trade, or to a smart contract, or to a recurring payment, etc.
  4003. //// //
  4004. //// for (int ii = 0; ii < listSize; ++ii)
  4005. //// {
  4006. //// const int nIndex = listSize - ii - 1; // We iterate through the list in reverse. (Since we'll be deleting stuff.)
  4007. //// opentxs::OTRecord record = GetRecordlist().GetRecord(nIndex);
  4008. //// {
  4009. //// opentxs::OTRecord& recordmt = record;
  4010. //// if (false == recordmt.IsFinalReceipt()) {
  4011. //// processImportRecord(recordmt, nIndex, mapOfSetsOfAlreadyImportedMsgs, mapOfConversationsByNym, setNewlyAddedNymThreadAndItem);
  4012. //// }
  4013. //// }
  4014. //// } // for (GetRecordlist() in reverse)
  4015. //// //
  4016. //// // Notice that this function now does the same thing twice.
  4017. //// // Only difference is, the first time around it does all NON-Final Receipts,
  4018. //// // but the second time around it does all FINAL receipts. (And final receipt notices).
  4019. //// // This is basically just to ensure that final receipts are always done LAST.
  4020. //// //
  4021. //// // -------------------------------------
  4022. //// // If the above process DID remove any records, then we have to repopulate them now,
  4023. //// // since every record contains its index, and so they will be wrong until re-populated.
  4024. //// //
  4025. //// if (listSize != GetRecordlist().size())
  4026. //// populateRecords(true); //bCurrentlyModifying=false by default.
  4027. //// // -------------------------------------
  4028. //// // -------------------------------------
  4029. //// const int newListSize = GetRecordlist().size();
  4030. //// for (int iii = 0; iii < newListSize; ++iii)
  4031. //// {
  4032. //// const int nIndex = newListSize - iii - 1; // We iterate through the list in reverse. (Since we'll be deleting stuff.)
  4033. //// opentxs::OTRecord record = GetRecordlist().GetRecord(nIndex);
  4034. //// {
  4035. //// opentxs::OTRecord& recordmt = record;
  4036. //// if (true == recordmt.IsFinalReceipt()) {
  4037. //// processImportRecord(recordmt, nIndex, mapOfSetsOfAlreadyImportedMsgs, mapOfConversationsByNym, setNewlyAddedNymThreadAndItem);
  4038. //// }
  4039. //// }
  4040. //// } // for (GetRecordlist() in reverse)
  4041. //// // -------------------------------------
  4042. //// // If the above process DID remove any records, then we have to repopulate them now,
  4043. //// // since every record contains its index, and so they will be wrong until re-populated.
  4044. //// //
  4045. //// if (listSize != GetRecordlist().size())
  4046. //// populateRecords(true); //bCurrentlyModifying=false by default.
  4047. // // -------------------------------------
  4048. //}
  4049. //void Moneychanger::processImportRecord(
  4050. // opentxs::OTRecord& recordmt,
  4051. // const int nIndex,
  4052. // MapOfPtrSetsOfStrings & mapOfSetsOfAlreadyImportedMsgs,
  4053. // MapOfConversationsByNym & mapOfConversationsByNym,
  4054. // SetNymThreadAndItem & setNewlyAddedNymThreadAndItem
  4055. // )
  4056. //{
  4057. //// if (!recordmt.CanDeleteRecord())
  4058. //// {
  4059. //// // In this case we aren't going to delete the record, but we can still
  4060. //// // save a copy of it in our local database, if it's not already there.
  4061. //// if (!recordmt.IsMail() &&
  4062. //// !recordmt.IsSpecialMail() &&
  4063. //// !recordmt.IsExpired() )
  4064. //// {
  4065. //// bool bShouldImportPayment = true; // To preserve original logic.
  4066. //// bool bShouldImportAgreement = false; // This part is new.
  4067. //// if (recordmt.IsPending()
  4068. //// && (recordmt.IsPaymentPlan() ||
  4069. //// recordmt.IsContract()) )
  4070. //// {
  4071. //// bShouldImportPayment = true;
  4072. //// bShouldImportAgreement = true;
  4073. //// }
  4074. //// if (bShouldImportPayment)
  4075. //// AddPaymentToPmntArchive(recordmt);
  4076. //// if (bShouldImportAgreement)
  4077. //// AddAgreementRecord(recordmt);
  4078. //// }
  4079. //// }
  4080. //// else // record can be deleted.
  4081. //// {
  4082. //// // If recordmt IsRecord() and IsReceipt() and is a "finalReceipt"
  4083. //// // then try to look it up in the Trade Archive table. For all entries
  4084. //// // from the same transaction, we set the final receipt text in those
  4085. //// // rows.
  4086. //// //
  4087. //// // Then we delete the finalReceipt from the OT Record Box.
  4088. //// //
  4089. //// // Meanwhile, for all marketReceipts, we just deleting them since they
  4090. //// // are ALREADY in the trade_archive table.
  4091. //// //
  4092. //// // -----------------------------------
  4093. //// bool bShouldDeleteRecord = false;
  4094. //// // -----------------------------------
  4095. //// if (recordmt.IsMail() || recordmt.IsSpecialMail())
  4096. //// {
  4097. //// if (expertMode() &&
  4098. //// AddMailToMsgArchive(recordmt, mapOfSetsOfAlreadyImportedMsgs, mapOfConversationsByNym, setNewlyAddedNymThreadAndItem))
  4099. //// {
  4100. //// //bShouldDeleteRecord = true; // Disabling this temporarily to see if it fixes any related startup/shutdown issues.
  4101. //// ;
  4102. //// }
  4103. //// }
  4104. //// // -----------------------------------
  4105. //// else if (recordmt.IsNotice())
  4106. //// {
  4107. //// bool bShouldImportPayment = false;
  4108. //// bool bShouldImportAgreement = false;
  4109. ////// bool bShouldImportFinalReceiptToTradeArchive = false; // experimental. See note just below.
  4110. //// if (recordmt.HasOriginType())
  4111. //// {
  4112. //// if (recordmt.IsOriginTypeMarketOffer()) {
  4113. //// qDebug() << __FUNCTION__ << ": This is where I almost just added a market notice to the payments table. I stopped myself.";
  4114. //// // There actually IS a finalReceipt NOTICE for market exchange. (Sent to the Nym.)
  4115. //// // (Versus the finalReceipt RECEIPTs, which are sent to 2 ACCOUNTS for each Nym.)
  4116. //// // Therefore, AddAgreementRecord needs to check for "IsNotice" in combination with "IsFinalReceipt"
  4117. //// // since in that case, it should know it hasn't received its official 4 ACCOUNT receipts yet,
  4118. //// // and more importantly, that this notice should NOT overwrite any of those, but it
  4119. //// // has still received _some_ useful information -- that the agreement itself _has_ been
  4120. //// // terminated.
  4121. //// //
  4122. //// //bShouldImportFinalReceiptToTradeArchive = true;
  4123. //// bShouldDeleteRecord = true;
  4124. //// }
  4125. //// else if (recordmt.IsOriginTypePaymentPlan()) {
  4126. //// bShouldImportPayment = true;
  4127. //// bShouldImportAgreement = true;
  4128. //// }
  4129. //// else if (recordmt.IsOriginTypeSmartContract()) {
  4130. //// bShouldImportPayment = true;
  4131. //// bShouldImportAgreement = true;
  4132. //// }
  4133. //// else {
  4134. //// qDebug() << __FUNCTION__ << ": Importing notices, found a record with an unknown origin type.";
  4135. //// }
  4136. //// }
  4137. //// else {
  4138. //// bShouldImportPayment = true;
  4139. //// // QString tFinal = "false";
  4140. //// // QString tContract = "false";
  4141. //// // QString tPlan = "false";
  4142. //// // QString tNotice = "false";
  4143. //// // QString tExpired = "false";
  4144. //// // QString tCanceled = "false";
  4145. //// // QString tSuccess = "false";
  4146. //// // bool bIsSuccess = false;
  4147. //// //
  4148. //// // if (recordmt.IsFinalReceipt()) tFinal = "true";
  4149. //// // if (recordmt.IsContract()) tContract = "true";
  4150. //// // if (recordmt.IsPaymentPlan()) tPlan = "true";
  4151. //// // if (recordmt.IsNotice()) tNotice = "true";
  4152. //// // if (recordmt.IsExpired()) tExpired = "true";
  4153. //// // if (recordmt.IsCanceled()) tCanceled = "true";
  4154. //// // if (recordmt.HasSuccess(bIsSuccess)) tSuccess = bIsSuccess ? "true" : "false";
  4155. //// //
  4156. //// // qstrTemp = QString(" IsFinalReceipt: %1\n IsContract: %2 \n IsPaymentPlan: %3 \n IsNotice: %4 \n IsExpired: %5 \n IsCanceled: %6 \n IsSuccess: %7 ")
  4157. //// // .arg(tFinal).arg(tContract).arg(tPlan).arg(tNotice).arg(tExpired).arg(tCanceled).arg(tSuccess);
  4158. //// //
  4159. //// // qDebug() << qstrTemp;
  4160. //// }
  4161. //// // -------------------------------------
  4162. //// if (bShouldImportPayment && AddPaymentBasedOnNotice(recordmt))
  4163. //// bShouldDeleteRecord = true;
  4164. //// if (bShouldImportAgreement && AddAgreementRecord(recordmt))
  4165. //// bShouldDeleteRecord = true;
  4166. //// // if (bShouldImportFinalReceiptToTradeArchive && AddFinalReceiptToTradeArchive(recordmt))
  4167. //// // bShouldDeleteRecord = true;
  4168. //// }
  4169. //// // -----------------------------------
  4170. //// else if (recordmt.IsRecord() && !recordmt.IsExpired())
  4171. //// {
  4172. //// if (recordmt.IsReceipt())
  4173. //// {
  4174. //// if (0 == recordmt.GetInstrumentType().compare("marketReceipt"))
  4175. //// {
  4176. //// // We don't have to add these to the trade archive table because they
  4177. //// // are already there. OTClient directly adds them into the TradeDataNym object,
  4178. //// // and then Moneychanger reads that object and imports it into the trade_achive
  4179. //// // table already. So basically here all we need to do is delete the market
  4180. //// // receipt records so the user doesn't have the hassle of deleting them himself.
  4181. //// // Now they are safe in his archive and he can do whatever he wants with them.
  4182. //// bShouldDeleteRecord = true;
  4183. //// } // marketReceipt
  4184. //// // -----------------------------------
  4185. //// // NOTE: PayDividend is possibly having its receipts go in here.
  4186. //// // Todo: Fix pay dividend in UI.
  4187. //// //
  4188. //// else if (0 == recordmt.GetInstrumentType().compare("paymentReceipt"))
  4189. //// {
  4190. //// if (recordmt.HasOriginType()
  4191. //// && (recordmt.IsOriginTypePaymentPlan() ||
  4192. //// recordmt.IsOriginTypeSmartContract())
  4193. //// && AddAgreementRecord(recordmt)) // <====== IMPORTS HERE.
  4194. //// {
  4195. //// bShouldDeleteRecord = true;
  4196. //// }
  4197. //// // else
  4198. //// // qDebug() << __FUNCTION__ << ": Failed trying to add a receipt to the agreement archive.";
  4199. //// // Commenting this out for now.
  4200. //// // It might have been added just to hide the pay dividend problems.
  4201. //// // Now I want to see whatever pops up here.
  4202. //// //bShouldDeleteRecord = true;
  4203. //// } // paymentReceipt
  4204. //// // -----------------------------------
  4205. //// else if (recordmt.IsFinalReceipt())
  4206. //// {
  4207. //// // Notice here we only delete the record if we successfully
  4208. //// // added the final receipt to the trade archive table.
  4209. //// // Why? Because the trade archive table contains receipts
  4210. //// // of COMPLETED TRADES. So if we fail to find any of those
  4211. //// // to add the final receipt to, we don't just want to DELETE
  4212. //// // the final receipt -- the user's sole remaining copy!
  4213. //// // - So for trades that occurred, the final receipt will be stored
  4214. //// // with those archives next to the corresponding market receipts.
  4215. //// // - And for trades that did NOT occur, the final receipt will
  4216. //// // remain in the record box, so the user himself can delete those
  4217. //// // whenever he sees fit. They will be his only notice that an
  4218. //// // offer completed on the market without any trades occurring.
  4219. //// // We might even change the GUI label now for final receipt records,
  4220. //// // (in the Pending Transactions window) to explicitly say,
  4221. //// // "offer completed on market without any trades."
  4222. //// //
  4223. //// // P.S. There's another reason not to just delete a finalReceipt
  4224. //// // if we can't find any trades associated with it: because it might
  4225. //// // not be a finalReceipt for a market offer! It might correspond to
  4226. //// // a smart contract or a recurring payment plan.
  4227. //// //
  4228. //// // UPDATE: We now CAN tell for finalReceipts and paymentReceipts, whether
  4229. //// // they are for market offers, payment plans, or smart contracts. So the
  4230. //// // logic is updated now to not even TRY to import into the trade archive
  4231. //// // unless it's specifically a finalReceipt for a market offer.
  4232. //// //
  4233. //// const bool has_origin_type = recordmt.HasOriginType();
  4234. //// const bool origin_market_offer = has_origin_type && recordmt.IsOriginTypeMarketOffer();
  4235. //// const bool added_trade_archive = origin_market_offer && AddFinalReceiptToTradeArchive(recordmt);
  4236. //// if ( has_origin_type
  4237. //// && origin_market_offer
  4238. //// && added_trade_archive) // <==== IMPORTS HERE.
  4239. //// bShouldDeleteRecord = true;
  4240. //// else if (AddAgreementRecord(recordmt)) // Okay, it's for a smart contract or recurring payment plan.
  4241. //// {
  4242. //// bShouldDeleteRecord = true;
  4243. //// // For now I'm doing this one here as well, so the normal payments screen
  4244. //// // is able to realize that the agreement has finished.
  4245. //// //
  4246. //// // UPDATE: We no longer do this. If someone activates a payment plan, and it
  4247. //// // says "activated" in the payments screen. (Or "canceled" or "expired" or whatever)
  4248. //// // then that was its state when that action occurred, and it's now historical.
  4249. //// // It "was activated." Since then, is it STILL active? If you want to know that,
  4250. //// // you have to look at the "active agreements" window where you can see its current
  4251. //// // status and its finalReceipts and paymentReceipts.
  4252. //// //
  4253. //// // UPDATE: uncommenting this for now, to see how it goes. I'm thinking that
  4254. //// // both the payments screen AND the active agreements screen should show the
  4255. //// // most recent status of the agreement.
  4256. //// //
  4257. //// // UPDATE: commented it out again. In the payments GUI, we had a sent
  4258. //// // activated, and a received activated, and you had to go to the live
  4259. //// // agreements GUI to see what happened beyond that. It's better to keep
  4260. //// // it that way, since when I uncomment this, those get replaced in the
  4261. //// // payments UI with both final receipts in the received. It's appropriate
  4262. //// // to see those appear in the live agreements, but it's confusing to have
  4263. //// // them appear in the payments UI, so I commented this out again.
  4264. //// //
  4265. //// //AddPaymentToPmntArchive(recordmt);
  4266. //// }
  4267. //// else
  4268. //// qDebug() << QString(" --- Tried to import final receipt, but it failed! has_origin_type: %1 origin_market_offer: %2 added_trade_archive: %3").arg(has_origin_type).arg(origin_market_offer).arg(added_trade_archive);
  4269. //// } // finalReceipt
  4270. //// else // All other closed (deletable) receipts.
  4271. //// {
  4272. //// qDebug() << __FUNCTION__ << ": FYI, IMPORTING A RECEIPT OF CLOSED 'ALL OTHER' TYPE.";
  4273. //// if (AddPaymentToPmntArchive(recordmt))
  4274. //// {
  4275. //// bShouldDeleteRecord = true;
  4276. //// }
  4277. //// // else
  4278. //// // qDebug() << __FUNCTION__ << ": Failed trying to add a receipt to the payment archive.";
  4279. //// }
  4280. //// }
  4281. //// // -----------------------------------
  4282. //// else // All other delete-able, non-expired records.
  4283. //// {
  4284. //// qDebug() << __FUNCTION__ << ": FYI, IMPORTING A NON-RECEIPT OF DELETABLE, NON-EXPIRED TYPE.";
  4285. //// // For example, an incoming cheque becomes a received cheque after depositing it.
  4286. //// // At that point, OT moves incoming cheque from the payments inbox, to the record box. So
  4287. //// // it's not a cheque receipt (the payer gets that; you're the recipient) but it's the deletable
  4288. //// // record of the incoming cheque itself, for a cheque you've since already deposited, and thus
  4289. //// // are now moving to your payment receipts table.
  4290. //// // There IS another relevant receipt, however -- the cheque DEPOSIT. When you deposited the cheque,
  4291. //// // YOU got a deposit receipt. This is currently not recorded here but it really should be. That
  4292. //// // way you can see the cheque itself, as well as your receipt from depositing that cheque. It'd just
  4293. //// // be two different receipts on the same payment record, similar to what we do in the trade archive
  4294. //// // table, which has potentially up to 3 different receipts for the same trade record. (Market receipt
  4295. //// // for asset and currency accounts, plus final receipt.)
  4296. //// //
  4297. //// if ((recordmt.IsPaymentPlan() || recordmt.IsContract()) // They could be here maybe because they expired without ever being activated.
  4298. //// && AddAgreementRecord(recordmt))
  4299. //// {
  4300. //// bShouldDeleteRecord = true;
  4301. //// }
  4302. //// if (AddPaymentToPmntArchive(recordmt))
  4303. //// {
  4304. //// bShouldDeleteRecord = true;
  4305. //// }
  4306. //// }
  4307. //// } // else if (recordmt.IsRecord() && !recordmt.IsExpired())
  4308. //// // -----------------------------------
  4309. //// if (bShouldDeleteRecord)
  4310. //// {
  4311. //// if (recordmt.DeleteRecord())
  4312. //// {
  4313. //// bool bRemoved = GetRecordlist().RemoveRecord(nIndex);
  4314. //// if (!bRemoved)
  4315. //// qDebug() << "Moneychanger::modifyRecords: weird issue trying to remove deleted record from GetRecordlist() (record list.)\n";
  4316. //// }
  4317. //// }
  4318. //// } // Record can be deleted.
  4319. //}
  4320. // This function is used sometimes, but it's NOT called by the function below it, that
  4321. // does this stuff in a loop. Why not? Because we don't want to download the same Nym
  4322. // for EACH account he owns, when we could just download the Nym once and then download
  4323. // all his accounts once. So this function is only used for more targeted cases where you
  4324. // really prefer the faster loading time. Also, notice the "emit populatedRecordList()"
  4325. // that you see at the bottom? We don't want to have to emit that 10 times in a row, so
  4326. // again, you would only use this function in the case where that Acct and Nym really are
  4327. // the ONLY two entities being refreshed.
  4328. //
  4329. void Moneychanger::onNeedToDownloadSingleAcct(QString qstrAcctID, QString qstrOptionalAcctID)
  4330. {
  4331. if (qstrAcctID.isEmpty())
  4332. return;
  4333. QString qstrErrorMsg;
  4334. qstrErrorMsg = tr("Failed trying to contact the notary. Perhaps it is down, or there might be a network problem.");
  4335. // ------------------------------
  4336. std::string accountId = qstrAcctID.toStdString();
  4337. std::string acctNymID = ot_.Exec().GetAccountWallet_NymID (accountId);
  4338. std::string acctSvrID = ot_.Exec().GetAccountWallet_NotaryID(accountId);
  4339. // ------------------------------
  4340. std::string accountIdOptional = qstrOptionalAcctID.isEmpty() ? "" : qstrOptionalAcctID.toStdString();
  4341. std::string acctNymIDOptional = qstrOptionalAcctID.isEmpty() ? "" : ot_.Exec().GetAccountWallet_NymID (accountIdOptional);
  4342. std::string acctSvrIDOptional = qstrOptionalAcctID.isEmpty() ? "" : ot_.Exec().GetAccountWallet_NotaryID(accountIdOptional);
  4343. // ------------------------------
  4344. bool bRetrievalAttemptedNym = false;
  4345. bool bRetrievalSucceededNym = false;
  4346. bool bRetrievalAttemptedAcct = false;
  4347. bool bRetrievalSucceededAcct = false;
  4348. // ------------------------------
  4349. if (!acctNymID.empty() && !acctSvrID.empty())
  4350. {
  4351. MTSpinner theSpinner;
  4352. bRetrievalAttemptedNym = true;
  4353. bRetrievalSucceededNym = retrieve_nym(acctSvrID, acctNymID);
  4354. if (!ot_.Exec().CheckConnection(acctSvrID))
  4355. {
  4356. emit appendToLog(qstrErrorMsg);
  4357. return;
  4358. }
  4359. // Let's download the Nym for the optional account too, but ONLY if it's not the same Nym!!
  4360. //
  4361. if (bRetrievalSucceededNym && !qstrOptionalAcctID.isEmpty() && (acctNymIDOptional != acctNymID))
  4362. {
  4363. bRetrievalSucceededNym = retrieve_nym(acctSvrIDOptional, acctNymIDOptional);
  4364. if (!ot_.Exec().CheckConnection(acctSvrIDOptional))
  4365. {
  4366. emit appendToLog(qstrErrorMsg);
  4367. return;
  4368. }
  4369. }
  4370. }
  4371. if (bRetrievalSucceededNym)
  4372. {
  4373. MTSpinner theSpinner;
  4374. bRetrievalAttemptedAcct = true;
  4375. const auto notaryID = opentxs::Identifier::Factory(acctSvrID);
  4376. const auto nymID = opentxs::Identifier::Factory(acctNymID);
  4377. const auto accountID = opentxs::Identifier::Factory(accountId);
  4378. bRetrievalSucceededAcct = ot_.ServerAction().DownloadAccount(nymID, notaryID, accountID, true);
  4379. if (bRetrievalSucceededAcct && !qstrOptionalAcctID.isEmpty())
  4380. {
  4381. const auto notaryIDOptional = opentxs::Identifier::Factory(acctSvrIDOptional);
  4382. const auto nymIDOptional = opentxs::Identifier::Factory(acctNymIDOptional);
  4383. const auto accountIDOptional = opentxs::Identifier::Factory(accountIdOptional);
  4384. bRetrievalSucceededAcct = ot_.ServerAction().DownloadAccount(
  4385. nymIDOptional, notaryIDOptional, accountIDOptional, true);
  4386. }
  4387. if (!ot_.Exec().CheckConnection(acctSvrIDOptional))
  4388. {
  4389. emit appendToLog(qstrErrorMsg);
  4390. return;
  4391. }
  4392. }
  4393. // ----------------------------------------------------------------
  4394. const bool bRetrievalAttempted = (bRetrievalAttemptedNym && bRetrievalAttemptedAcct);
  4395. const bool bRetrievalSucceeded = (bRetrievalSucceededNym && bRetrievalSucceededAcct);
  4396. // ----------------------------------------------------------------
  4397. if (bRetrievalAttempted)
  4398. {
  4399. if (!bRetrievalSucceeded) {
  4400. Moneychanger::It()->HasUsageCredits(acctSvrID, acctNymID);
  4401. return;
  4402. }
  4403. else
  4404. {
  4405. // ----------------------------------------------------------------
  4406. // This refreshes any new Nym Trade Data (the receipts we just downloaded
  4407. // may include Market Receipts, so we need to import those into the Historical Trade Archive.)
  4408. //
  4409. QPointer<ModelTradeArchive> pModel = DBHandler::getInstance()->getTradeArchiveModel();
  4410. if (pModel)
  4411. {
  4412. pModel->updateDBFromOT();
  4413. }
  4414. // ----------------------------------------------------------------
  4415. // onNeedToPopulateRecordlist();
  4416. return;
  4417. }
  4418. }
  4419. }
  4420. // ----------------------------------------------------------------
  4421. void Moneychanger::onNeedToPopulateRecordlist()
  4422. {
  4423. // setupRecordList();
  4424. // populateRecords(); // This updates the record list. (It assumes a download has recently occurred.)
  4425. // // ----------------------------------------------------------------
  4426. // emit populatedRecordlist();
  4427. }
  4428. // ----------------------------------------------------------------
  4429. void Moneychanger::onNeedToDownloadAccountData()
  4430. {
  4431. // const auto nymCount = ot_.Exec().GetNymCount();
  4432. // if (0 == nymCount) {
  4433. // const std::string id =
  4434. // opentxs::SwigWrap::CreateIndividualNym("Me", "", 0);
  4435. // if (!id.empty()) {
  4436. // DBHandler::getInstance()->AddressBookUpdateDefaultNym(
  4437. // QString::fromStdString(id));
  4438. // }
  4439. // }
  4440. // const auto defaultNotaryID = get_default_notary_id().toStdString();
  4441. // if (defaultNotaryID.empty()) {
  4442. // DBHandler::getInstance()->
  4443. // AddressBookUpdateDefaultServer(get_notary_id_at(0));
  4444. // }
  4445. // const auto defaultUnitDefinitionID (get_default_asset_id().toStdString());
  4446. // if (defaultUnitDefinitionID.empty()) {
  4447. // DBHandler::getInstance()->
  4448. // AddressBookUpdateDefaultAsset(get_asset_id_at(0));
  4449. // }
  4450. ot_.Sync().Refresh();
  4451. return;
  4452. }
  4453. /**
  4454. * Asset Manager
  4455. **/
  4456. //Asset manager "clicked"
  4457. void Moneychanger::mc_defaultasset_slot()
  4458. {
  4459. //The operator has requested to open the dialog to the "Asset Manager";
  4460. mc_assetmanager_dialog();
  4461. }
  4462. void Moneychanger::mc_assetmanager_dialog(QString qstrPresetID/*=QString("")*/)
  4463. {
  4464. QString qstr_default_id = this->get_default_asset_id();
  4465. // -------------------------------------
  4466. if (qstrPresetID.isEmpty())
  4467. qstrPresetID = qstr_default_id;
  4468. // -------------------------------------
  4469. if (!assetswindow)
  4470. assetswindow = new MTDetailEdit(this);
  4471. // -------------------------------------
  4472. mapIDName & the_map = assetswindow->m_map;
  4473. // -------------------------------------
  4474. the_map.clear();
  4475. // -------------------------------------
  4476. int32_t asset_count = ot_.Exec().GetAssetTypeCount();
  4477. bool bFoundPreset = false;
  4478. for (int32_t ii = 0; ii < asset_count; ii++)
  4479. {
  4480. QString OT_id = QString::fromStdString(ot_.Exec().GetAssetType_ID(ii));
  4481. QString OT_name = QString::fromStdString(ot_.Exec().GetAssetType_Name(OT_id.toStdString()));
  4482. the_map.insert(OT_id, OT_name);
  4483. // ------------------------------
  4484. if (!qstrPresetID.isEmpty() && (0 == qstrPresetID.compare(OT_id)))
  4485. bFoundPreset = true;
  4486. // ------------------------------
  4487. } // for
  4488. // -------------------------------------
  4489. assetswindow->setWindowTitle(tr("Asset Types"));
  4490. // -------------------------------------
  4491. if (bFoundPreset)
  4492. assetswindow->SetPreSelected(qstrPresetID);
  4493. // -------------------------------------
  4494. assetswindow->dialog(MTDetailEdit::DetailEditTypeAsset);
  4495. }
  4496. //Additional Asset slots
  4497. //This was mistakenly named asset_load_asset, should be set default asset
  4498. //Set Default asset
  4499. void Moneychanger::setDefaultAsset(QString asset_id, QString asset_name)
  4500. {
  4501. //Set default asset internal memory
  4502. default_asset_id = asset_id;
  4503. default_asset_name = asset_name;
  4504. //SQL UPDATE default asset
  4505. DBHandler::getInstance()->AddressBookUpdateDefaultAsset(asset_id);
  4506. //Rename "ASSET:" if a asset is loaded
  4507. if (asset_id != "")
  4508. {
  4509. mc_systrayMenu_asset->setTitle(tr("Asset contract: ")+asset_name);
  4510. if (mc_overall_init)
  4511. {
  4512. // Loop through actions in mc_systrayMenu_asset.
  4513. // Ignore the "openmanager" action.
  4514. // For all others, compare the data to the default asset ID.
  4515. // If one matches, set the "checked" property to true, and for
  4516. // all others, set to false.
  4517. foreach (QAction* a, mc_systrayMenu_asset->actions())
  4518. {
  4519. QString qstrActionData = a->data().toString();
  4520. if (0 == qstrActionData.compare(default_asset_id)) {
  4521. a->setChecked(true);
  4522. }
  4523. else {
  4524. a->setChecked(false);
  4525. }
  4526. }
  4527. }
  4528. }
  4529. }
  4530. //Asset new default selected from systray
  4531. void Moneychanger::mc_assetselection_triggered(QAction*action_triggered)
  4532. {
  4533. //Check if the user wants to open the asset manager (or) select a different default asset
  4534. QString action_triggered_string = QVariant(action_triggered->data()).toString();
  4535. qDebug() << "asset TRIGGERED" << action_triggered_string;
  4536. if(action_triggered_string == "openmanager"){
  4537. //Open asset manager
  4538. mc_defaultasset_slot();
  4539. }else{
  4540. //Set new asset default
  4541. QString action_triggered_string_asset_name = QVariant(action_triggered->text()).toString();
  4542. setDefaultAsset(action_triggered_string, action_triggered_string_asset_name);
  4543. //Refresh if the asset manager is currently open
  4544. if (assetswindow && !assetswindow->isHidden())
  4545. {
  4546. mc_assetmanager_dialog();
  4547. }
  4548. }
  4549. }
  4550. // End Asset Manager
  4551. void Moneychanger::onBalancesChanged()
  4552. {
  4553. SetupMainMenu();
  4554. emit balancesChanged();
  4555. }
  4556. void Moneychanger::onNeedToUpdateMenu()
  4557. {
  4558. SetupMainMenu();
  4559. }
  4560. /**
  4561. * Account Manager
  4562. **/
  4563. //Account manager "clicked"
  4564. void Moneychanger::mc_defaultaccount_slot()
  4565. {
  4566. //The operator has requested to open the dialog to the "account Manager";
  4567. mc_accountmanager_dialog();
  4568. }
  4569. void Moneychanger::mc_show_account_slot(QString text)
  4570. {
  4571. mc_accountmanager_dialog(text);
  4572. }
  4573. void Moneychanger::mc_show_account_manager_slot()
  4574. {
  4575. mc_accountmanager_dialog();
  4576. }
  4577. void Moneychanger::mc_accountmanager_dialog(QString qstrAcctID/*=QString("")*/)
  4578. {
  4579. QString qstr_default_acct_id = this->get_default_account_id();
  4580. // -------------------------------------
  4581. if (qstrAcctID.isEmpty())
  4582. qstrAcctID = qstr_default_acct_id;
  4583. // -------------------------------------
  4584. if (!accountswindow)
  4585. {
  4586. accountswindow = new MTDetailEdit(this);
  4587. // When the accountswindow signal "balancesChanged" is triggered,
  4588. // it will call Moneychanger's "onBalancesChanged" function.
  4589. // (Which will trigger Moneychanger's "balancesChanged" signal.)
  4590. //
  4591. connect(accountswindow, SIGNAL(balancesChanged()),
  4592. this, SLOT(onBalancesChanged()));
  4593. // When Moneychanger's signal "balancesChanged" is triggered,
  4594. // it will call accountswindow's "onBalancesChangedFromAbove" function.
  4595. //
  4596. connect(this, SIGNAL(balancesChanged()),
  4597. accountswindow, SLOT(onBalancesChangedFromAbove()));
  4598. qDebug() << "Account Manager Opened";
  4599. }
  4600. // -------------------------------------
  4601. mapIDName & the_map = accountswindow->m_map;
  4602. // -------------------------------------
  4603. the_map.clear();
  4604. // -------------------------------------
  4605. bool bFoundDefault = false;
  4606. for (const auto& [accountID, alias] : ot_.Storage().AccountList())
  4607. {
  4608. QString OT_id = QString::fromStdString(accountID);
  4609. QString OT_name = QString::fromStdString(alias);
  4610. the_map.insert(OT_id, OT_name);
  4611. // ------------------------------
  4612. if (!qstrAcctID.isEmpty() && (0 == qstrAcctID.compare(OT_id)))
  4613. bFoundDefault = true;
  4614. // ------------------------------
  4615. } // for
  4616. // -------------------------------------
  4617. accountswindow->setWindowTitle(tr("Manage Accounts"));
  4618. // -------------------------------------
  4619. if (bFoundDefault)
  4620. accountswindow->SetPreSelected(qstrAcctID);
  4621. // -------------------------------------
  4622. accountswindow->dialog(MTDetailEdit::DetailEditTypeAccount);
  4623. }
  4624. //Account Manager Additional Functions
  4625. //Account new default selected from systray
  4626. void Moneychanger::mc_accountselection_triggered(QAction*action_triggered)
  4627. {
  4628. //Check if the user wants to open the account manager (or) select a different default account
  4629. QString action_triggered_string = QVariant(action_triggered->data()).toString();
  4630. // qDebug() << "account TRIGGERED" << action_triggered_string;
  4631. if (action_triggered_string == "openmanager")
  4632. {
  4633. //Open account manager
  4634. mc_defaultaccount_slot();
  4635. }
  4636. else
  4637. {
  4638. //Set new account default
  4639. QString action_triggered_string_account_name = QVariant(action_triggered->text()).toString();
  4640. setDefaultAccount(action_triggered_string, action_triggered_string_account_name);
  4641. // ------------------------------
  4642. //Refresh the account default selection in the account manager (ONLY if it is open)
  4643. //Check if account manager has ever been opened (then apply logic) [prevents crash if the dialog hasen't be opened before]
  4644. //
  4645. if (accountswindow && !accountswindow->isHidden())
  4646. {
  4647. mc_accountmanager_dialog();
  4648. }
  4649. // ------------------------------
  4650. // NOTE: I just commented this out because it's already done in setDefaultAccount (above.)
  4651. // emit populatedRecordlist();
  4652. // ------------------------------
  4653. }
  4654. }
  4655. //Set Default account
  4656. void Moneychanger::setDefaultAccount(QString account_id, QString account_name)
  4657. {
  4658. //Set default account internal memory
  4659. default_account_id = account_id;
  4660. default_account_name = account_name;
  4661. //SQL UPDATE default account
  4662. DBHandler::getInstance()->AddressBookUpdateDefaultAccount(account_id);
  4663. //Rename "ACCOUNT:" if a account is loaded
  4664. if (account_id != "")
  4665. {
  4666. QString result = account_name;
  4667. // QString result = tr("Account: ") + account_name;
  4668. int64_t lBalance = ot_.Exec().GetAccountWallet_Balance (account_id.toStdString());
  4669. std::string strAsset = ot_.Exec().GetAccountWallet_InstrumentDefinitionID(account_id.toStdString());
  4670. // ----------------------------------------------------------
  4671. std::string str_amount;
  4672. if (!strAsset.empty())
  4673. {
  4674. str_amount = ot_.Exec().FormatAmount(strAsset, lBalance);
  4675. result += " ("+ QString::fromStdString(str_amount) +")";
  4676. }
  4677. mc_systrayMenu_account->setTitle(result);
  4678. // -----------------------------------------------------------
  4679. std::string strNym = ot_.Exec().GetAccountWallet_NymID (account_id.toStdString());
  4680. std::string strServer = ot_.Exec().GetAccountWallet_NotaryID(account_id.toStdString());
  4681. if (!strAsset.empty())
  4682. DBHandler::getInstance()->AddressBookUpdateDefaultAsset (QString::fromStdString(strAsset));
  4683. if (!strNym.empty())
  4684. DBHandler::getInstance()->AddressBookUpdateDefaultNym (QString::fromStdString(strNym));
  4685. if (!strServer.empty())
  4686. DBHandler::getInstance()->AddressBookUpdateDefaultServer(QString::fromStdString(strServer));
  4687. if (mc_overall_init)
  4688. {
  4689. // -----------------------------------------------------------
  4690. if (!strAsset.empty())
  4691. {
  4692. QString qstrAssetName = QString::fromStdString(ot_.Exec().GetAssetType_Name(strAsset));
  4693. if (!qstrAssetName.isEmpty() && (mc_systrayMenu_asset))
  4694. setDefaultAsset(QString::fromStdString(strAsset),
  4695. qstrAssetName);
  4696. }
  4697. // -----------------------------------------------------------
  4698. if (!strNym.empty())
  4699. {
  4700. QString qstrNymName = QString::fromStdString(ot_.Exec().GetNym_Name(strNym));
  4701. if (!qstrNymName.isEmpty() && (mc_systrayMenu_nym))
  4702. setDefaultNym(QString::fromStdString(strNym),
  4703. qstrNymName);
  4704. }
  4705. // -----------------------------------------------------------
  4706. if (!strServer.empty())
  4707. {
  4708. QString qstrServerName = QString::fromStdString(ot_.Exec().GetServer_Name(strServer));
  4709. if (!qstrServerName.isEmpty() && (mc_systrayMenu_server))
  4710. setDefaultServer(QString::fromStdString(strServer),
  4711. qstrServerName);
  4712. }
  4713. // -----------------------------------------------------------
  4714. // Loop through actions in mc_systrayMenu_account.
  4715. // Ignore the "openmanager" action.
  4716. // For all others, compare the data to the default account ID.
  4717. // If one matches, set the "checked" property to true, and for
  4718. // all others, set to false.
  4719. foreach (QAction* a, mc_systrayMenu_account->actions())
  4720. {
  4721. QString qstrActionData = a->data().toString();
  4722. if (0 == qstrActionData.compare(default_account_id)) {
  4723. a->setChecked(true);
  4724. }
  4725. else {
  4726. a->setChecked(false);
  4727. }
  4728. }
  4729. // ----------------------------------------------------------------
  4730. // onNeedToPopulateRecordlist();
  4731. }
  4732. }
  4733. }
  4734. void Moneychanger::mc_show_asset_slot(QString text)
  4735. {
  4736. mc_assetmanager_dialog(text);
  4737. }
  4738. void Moneychanger::mc_show_server_slot(QString text)
  4739. {
  4740. mc_servermanager_dialog(text);
  4741. }
  4742. /**
  4743. * Server Manager
  4744. **/
  4745. void Moneychanger::mc_defaultserver_slot()
  4746. {
  4747. mc_servermanager_dialog();
  4748. }
  4749. void Moneychanger::mc_servermanager_dialog(QString qstrPresetID/*=QString("")*/)
  4750. {
  4751. QString qstr_default_id = this->get_default_notary_id();
  4752. // -------------------------------------
  4753. if (qstrPresetID.isEmpty())
  4754. qstrPresetID = qstr_default_id;
  4755. // -------------------------------------
  4756. if (!serverswindow)
  4757. serverswindow = new MTDetailEdit(this);
  4758. // -------------------------------------
  4759. mapIDName & the_map = serverswindow->m_map;
  4760. // -------------------------------------
  4761. the_map.clear();
  4762. // -------------------------------------
  4763. int32_t server_count = ot_.Exec().GetServerCount();
  4764. bool bFoundPreset = false;
  4765. for (int32_t ii = 0; ii < server_count; ii++)
  4766. {
  4767. QString OT_id = QString::fromStdString(ot_.Exec().GetServer_ID(ii));
  4768. QString OT_name = QString::fromStdString(ot_.Exec().GetServer_Name(OT_id.toStdString()));
  4769. the_map.insert(OT_id, OT_name);
  4770. // ------------------------------
  4771. if (!qstrPresetID.isEmpty() && (0 == qstrPresetID.compare(OT_id)))
  4772. bFoundPreset = true;
  4773. // ------------------------------
  4774. } // for
  4775. // -------------------------------------
  4776. serverswindow->setWindowTitle(tr("Server Contracts"));
  4777. // -------------------------------------
  4778. if (bFoundPreset)
  4779. serverswindow->SetPreSelected(qstrPresetID);
  4780. // -------------------------------------
  4781. serverswindow->dialog(MTDetailEdit::DetailEditTypeServer);
  4782. }
  4783. void Moneychanger::setDefaultServer(QString notary_id, QString server_name)
  4784. {
  4785. //Set default server internal memory
  4786. default_notary_id = notary_id;
  4787. default_server_name = server_name;
  4788. // qDebug() << default_notary_id;
  4789. // qDebug() << default_server_name;
  4790. //SQL UPDATE default server
  4791. DBHandler::getInstance()->AddressBookUpdateDefaultServer(default_notary_id);
  4792. //Update visuals
  4793. QString new_server_title = default_server_name;
  4794. if (mc_overall_init)
  4795. {
  4796. if (new_server_title.isEmpty())
  4797. mc_systrayMenu_server->setTitle(tr("Set default server..."));
  4798. else
  4799. mc_systrayMenu_server->setTitle(tr("Server contract: ")+new_server_title);
  4800. // Loop through actions in mc_systrayMenu_server.
  4801. // Ignore the "openmanager" action.
  4802. // For all others, compare the data to the default server ID.
  4803. // If one matches, set the "checked" property to true, and for
  4804. // all others, set to false.
  4805. foreach (QAction* a, mc_systrayMenu_server->actions())
  4806. {
  4807. QString qstrActionData = a->data().toString();
  4808. if (0 == qstrActionData.compare(default_notary_id)) {
  4809. a->setChecked(true);
  4810. }
  4811. else {
  4812. a->setChecked(false);
  4813. }
  4814. }
  4815. }
  4816. }
  4817. //Server Slots
  4818. void Moneychanger::mc_serverselection_triggered(QAction * action_triggered)
  4819. {
  4820. //Check if the user wants to open the nym manager (or) select a different default nym
  4821. QString action_triggered_string = QVariant(action_triggered->data()).toString();
  4822. // qDebug() << "SERVER TRIGGERED" << action_triggered_string;
  4823. if(action_triggered_string == "openmanager"){
  4824. //Open server-list manager
  4825. mc_defaultserver_slot();
  4826. }
  4827. else
  4828. {
  4829. //Set new server default
  4830. QString action_triggered_string_server_name = QVariant(action_triggered->text()).toString();
  4831. setDefaultServer(action_triggered_string, action_triggered_string_server_name);
  4832. //Refresh if the server manager is currently open
  4833. if (serverswindow && !serverswindow->isHidden())
  4834. {
  4835. mc_servermanager_dialog();
  4836. }
  4837. }
  4838. }
  4839. // End Server Manager
  4840. #include <QSerialPort>
  4841. #include <QSerialPortInfo>
  4842. #include <QLabel>
  4843. #include <QScrollArea>
  4844. /**
  4845. * Pair Stash Node
  4846. **/
  4847. void Moneychanger::mc_pair_node_slot()
  4848. {
  4849. if (QMessageBox::Cancel == QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Make sure the pairing cable is attached, then click OK."),
  4850. QMessageBox::Ok | QMessageBox::Cancel))
  4851. return;
  4852. // ----------------------------------------
  4853. const auto infos = QSerialPortInfo::availablePorts();
  4854. for (const QSerialPortInfo &info : infos) {
  4855. auto baudrates = info.standardBaudRates();
  4856. QString qstrBaudrates;
  4857. QList<qint32>::const_iterator i;
  4858. for (i = baudrates.begin(); i != baudrates.end(); ++i) {
  4859. if (i != baudrates.begin())
  4860. qstrBaudrates += QString(", ");
  4861. qstrBaudrates += QString::number(*i);
  4862. }
  4863. QString s = QObject::tr("Port: ") + info.portName() + "\n"
  4864. + QObject::tr("Location: ") + info.systemLocation() + "\n"
  4865. + QObject::tr("Description: ") + info.description() + "\n"
  4866. + QObject::tr("Manufacturer: ") + info.manufacturer() + "\n"
  4867. + QObject::tr("Serial number: ") + info.serialNumber() + "\n"
  4868. + QObject::tr("Vendor Identifier: ") + (info.hasVendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + "\n"
  4869. + QObject::tr("Product Identifier: ") + (info.hasProductIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()) + "\n"
  4870. + QObject::tr("StandardBaudRates: ") + qstrBaudrates + "\n"
  4871. + QObject::tr("Busy: ") + (info.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) + "\n";
  4872. qDebug() << s;
  4873. }
  4874. // ----------------------------------------
  4875. // DlgPairNode dlgPair;
  4876. // if (QDialog::Accepted != dlgPair.exec())
  4877. // return;
  4878. // ----------------------------------------
  4879. QString serialPortName = QString(infos.first().systemLocation());
  4880. QSerialPort serialPort;
  4881. serialPort.setPortName(serialPortName);
  4882. int serialPortBaudRate = QSerialPort::Baud38400;
  4883. serialPort.setBaudRate(serialPortBaudRate);
  4884. if (!serialPort.open(QIODevice::ReadOnly)) {
  4885. qDebug() << QObject::tr("Failed to open port %1, error: %2").arg(serialPortName).arg(serialPort.error()) << endl;
  4886. }
  4887. else
  4888. {
  4889. serialPort.setBaudRate(QSerialPort::Baud38400);
  4890. serialPort.setDataBits(QSerialPort::Data8);
  4891. serialPort.setStopBits(QSerialPort::OneStop);
  4892. serialPort.setParity(QSerialPort::NoParity);
  4893. serialPort.setFlowControl(QSerialPort::NoFlowControl);
  4894. /**
  4895. * Current flow control Options:
  4896. * UsbSerialInterface.FLOW_CONTROL_OFF
  4897. * UsbSerialInterface.FLOW_CONTROL_RTS_CTS only for CP2102 and FT232
  4898. * UsbSerialInterface.FLOW_CONTROL_DSR_DTR only for CP2102 and FT232
  4899. */
  4900. // ------------------
  4901. int nCounter{0};
  4902. QByteArray readData;
  4903. while (nCounter++ < 30 && serialPort.waitForReadyRead(10000)) {
  4904. readData.append(serialPort.readAll());
  4905. }
  4906. auto the_error = serialPort.error();
  4907. if (the_error == QSerialPort::ReadError) {
  4908. qDebug() << QObject::tr("Failed to read from port %1, error: %2").arg(serialPortName).arg(serialPort.errorString());
  4909. } else if ((serialPort.error() == QSerialPort::TimeoutError) && readData.isEmpty()) {
  4910. qDebug() << QObject::tr("No data was currently available for reading from port: %1").arg(serialPortName);
  4911. }
  4912. else {
  4913. QString qstrData = QString::fromUtf8(readData, readData.length());
  4914. qDebug() << QObject::tr("Data successfully received from port %1.").arg(serialPortName);
  4915. //qDebug() << qstrData << endl;
  4916. //qDebug() << readData << endl;
  4917. QStringList strPairs = qstrData.split("\n");
  4918. if (strPairs.length() >= 3) {
  4919. QString strPair = strPairs[1]; // This way there's at least 3 pairs and we're grabbing the middle of the three.
  4920. QStringList listData = strPair.split(",");
  4921. if (2 == listData.length())
  4922. {
  4923. const QString qstrBridgeNymID = listData[0];
  4924. const QString qstrAdminPassword = listData[1];
  4925. QString qstrUserNymID = Moneychanger::It()->get_default_nym_id();
  4926. QString errorMessage{""};
  4927. if (qstrBridgeNymID.isEmpty()) {
  4928. errorMessage = tr("SNP Bridge Nym Id not available from pairing cable.");
  4929. }
  4930. if (qstrUserNymID.isEmpty()) {
  4931. errorMessage = tr("Default User NymId not available from local Opentxs wallet.");
  4932. }
  4933. if (qstrAdminPassword.isEmpty()) {
  4934. errorMessage = tr("SNP admin password not available from pairing cable.");
  4935. }
  4936. // -----------------------------------
  4937. const std::string str_introduction_notary_id{opentxs::String::Factory(ot_.Sync().IntroductionServer())->Get()};
  4938. if (str_introduction_notary_id.empty()) {
  4939. errorMessage = tr("Introduction Notary Id not available.");
  4940. }
  4941. // -----------------------------------
  4942. if (!errorMessage.isEmpty()) {
  4943. qDebug() << errorMessage << endl;
  4944. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), errorMessage);
  4945. return;
  4946. }
  4947. // -----------------------------------
  4948. // By this point we at least know that the pre-requisites are there,
  4949. // so we can go ahead and start pairing. (Or see how much is already done,
  4950. // if it's already been started.)
  4951. //
  4952. /*
  4953. namespace opentxs
  4954. {
  4955. class Identifier;
  4956. namespace api
  4957. {
  4958. namespace client
  4959. {
  4960. class Pair
  4961. {
  4962. public:
  4963. virtual bool AddIssuer(
  4964. const Identifier& localNymID,
  4965. const Identifier& issuerNymID,
  4966. const std::string& pairingCode) const = 0;
  4967. virtual std::string IssuerDetails(
  4968. const Identifier& localNymID,
  4969. const Identifier& issuerNymID) const = 0;
  4970. virtual std::set<Identifier> IssuerList(
  4971. const Identifier& localNymID,
  4972. const bool onlyTrusted) const = 0;
  4973. */
  4974. const auto localNymID = opentxs::Identifier::Factory(qstrUserNymID.toStdString());
  4975. const auto issuerNymID = opentxs::Identifier::Factory(qstrBridgeNymID.toStdString());
  4976. const std::string pairingCode{qstrAdminPassword.toStdString()};
  4977. // NEW JUSTUS API
  4978. const bool bPairNode = ot_.Pair().AddIssuer(localNymID, issuerNymID, pairingCode);
  4979. //const bool bPairNode = ot_.OTME_TOO().PairNode(qstrUserNymID.toStdString(), qstrBridgeNymID.toStdString(), qstrAdminPassword.toStdString());
  4980. if (!bPairNode) {
  4981. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), tr("Pairing failed."));
  4982. return;
  4983. }
  4984. // ---------------------------------------------------
  4985. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Pairing successfully initiated in the background. You may now unplug your device."));
  4986. }
  4987. }
  4988. else
  4989. {
  4990. qDebug() << QString("Didn't have enough pairs from the serial port. Fix the code.") << endl;
  4991. }
  4992. }
  4993. }
  4994. }
  4995. /**
  4996. * Import Cash
  4997. **/
  4998. // TODO: Make this able to handle multiple instrument types
  4999. void Moneychanger::mc_import_slot()
  5000. {
  5001. DlgImport dlgImport;
  5002. if (QDialog::Accepted != dlgImport.exec())
  5003. return;
  5004. // ----------------------------------------
  5005. QString qstrInstrument;
  5006. // ----------------------------------------
  5007. if (dlgImport.IsPasted()) // Pasted contents (not filename)
  5008. qstrInstrument = dlgImport.GetPasted(); // Dialog prohibits empty contents, so no need to check here.
  5009. // --------------------------------
  5010. else // Filename
  5011. {
  5012. QString fileName = dlgImport.GetFilename(); // Dialog prohibits empty filename, so no need to check here.
  5013. // -----------------------------------------------
  5014. QFile plainFile(fileName);
  5015. if (plainFile.open(QIODevice::ReadOnly))//| QIODevice::Text)) // Text flag translates /n/r to /n
  5016. {
  5017. QTextStream in(&plainFile); // Todo security: check filesize here and place a maximum size.
  5018. qstrInstrument = in.readAll();
  5019. plainFile.close();
  5020. // ----------------------------
  5021. if (qstrInstrument.isEmpty())
  5022. {
  5023. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5024. QString("%1: %2").arg(tr("File was apparently empty")).arg(fileName));
  5025. return;
  5026. }
  5027. // ----------------------------
  5028. }
  5029. else
  5030. {
  5031. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5032. QString("%1: %2").arg(tr("Failed trying to read file")).arg(fileName));
  5033. return;
  5034. }
  5035. }
  5036. // --------------------------------
  5037. // By this point, we have the contents of the instrument,
  5038. // and we know they aren't empty.
  5039. //
  5040. std::string strInstrument{qstrInstrument.trimmed().toStdString()};
  5041. auto otstrInstrument = opentxs::String::Factory(strInstrument);
  5042. qstrInstrument = QString::fromStdString(strInstrument);
  5043. // -----------------------------------------------
  5044. // This is for cases where the entire input is base64 (without bookends).
  5045. //
  5046. if (Moneychanger::is_base64(qstrInstrument))
  5047. {
  5048. auto ascInstrument = opentxs::Armored::Factory(strInstrument.c_str());
  5049. ascInstrument->GetString(otstrInstrument);
  5050. strInstrument = otstrInstrument->Get();
  5051. qstrInstrument = QString::fromStdString(strInstrument);
  5052. }
  5053. // -----------------------------------------------
  5054. // This handles "BEGIN SIGNED CHEQUE"
  5055. // as well as "BEGIN OT ARMORED CHEQUE"
  5056. //
  5057. std::shared_ptr<opentxs::OTPayment> payment{ot_.Factory().Payment(otstrInstrument).release()};
  5058. if (false == bool(payment)) {
  5059. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5060. tr("Failed instantiation. (Should never happen)."));
  5061. return;
  5062. }
  5063. else if (!payment->IsValid()) {
  5064. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5065. tr("Failure: Unable to load financial instrument from text."));
  5066. return;
  5067. }
  5068. // -----------------------------------------------
  5069. bool bExpired{false};
  5070. bool bWithinValidDateRange{false};
  5071. time64_t validFrom{}, validTo{};
  5072. QString qstrDateFrom, qstrDateTo;
  5073. QDateTime qdate_from, qdate_to;
  5074. QDateTime currentDateTime = QDateTime::currentDateTime();
  5075. QString qstrExpiration;
  5076. if (payment->GetValidFrom(validFrom))
  5077. {
  5078. // ---------------------------------------------------------------------
  5079. qdate_from = QDateTime::fromTime_t(validFrom);
  5080. qstrDateFrom = qdate_from.toString(QString("MMM d yyyy hh:mm:ss"));
  5081. // ---------------------------------------------------------------------
  5082. if (currentDateTime < qdate_from)
  5083. {
  5084. qstrExpiration = QString("%1: %2")
  5085. .arg(tr("Failed to import: This instrument is not valid yet, until"))
  5086. .arg(qstrDateFrom);
  5087. }
  5088. }
  5089. if (payment->GetValidTo(validTo))
  5090. {
  5091. qdate_to = QDateTime::fromTime_t(validTo);
  5092. qstrDateTo = qdate_to.toString(QString("MMM d yyyy hh:mm:ss"));
  5093. }
  5094. // If we were able to retrieve expiration info
  5095. // AND that info shows expired=true...
  5096. if (payment->IsExpired(bExpired) && bExpired)
  5097. {
  5098. qstrExpiration = QString("%1: %2: %3")
  5099. .arg(tr("Failed to import"))
  5100. .arg(tr("This instrument expired on"))
  5101. .arg(qstrDateTo);
  5102. }
  5103. // If we were able to retrieve date range info
  5104. // AND that info shows we're NOT within the valid date range...
  5105. if (payment->VerifyCurrentDate(bWithinValidDateRange) && !bWithinValidDateRange)
  5106. {
  5107. if (qstrExpiration.isEmpty())
  5108. qstrExpiration = QString("%1: %2: %3 %4 %5")
  5109. .arg(tr("Failed to import"))
  5110. .arg(tr("This instrument is outside its valid date range of"))
  5111. .arg(qstrDateFrom)
  5112. .arg(tr("to"))
  5113. .arg(qstrDateTo);
  5114. }
  5115. // -------------
  5116. if (!qstrExpiration.isEmpty())
  5117. {
  5118. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), qstrExpiration);
  5119. return;
  5120. }
  5121. // -----------------------------------------------
  5122. QString qstrErrorMsg;
  5123. switch (payment->GetType()) {
  5124. case opentxs::OTPayment::PAYMENT_PLAN: {
  5125. qstrErrorMsg = tr("Sorry, we don't yet allow importing payment plans.");
  5126. break;
  5127. }
  5128. case opentxs::OTPayment::SMART_CONTRACT: {
  5129. qstrErrorMsg = tr("Sorry, we don't yet allow importing smart contracts.");
  5130. break;
  5131. }
  5132. case opentxs::OTPayment::NOTICE: {
  5133. qstrErrorMsg = tr("Sorry, we don't yet allow importing notices.");
  5134. break;
  5135. }
  5136. case opentxs::OTPayment::CHEQUE: {
  5137. break; // Instrument is allowed.
  5138. }
  5139. case opentxs::OTPayment::VOUCHER: {
  5140. break; // Instrument is allowed.
  5141. }
  5142. case opentxs::OTPayment::INVOICE: {
  5143. qstrErrorMsg = tr("Sorry, we don't yet allow importing invoices.");
  5144. break;
  5145. }
  5146. case opentxs::OTPayment::PURSE: {
  5147. break; // Instrument is allowed.
  5148. }
  5149. default: {
  5150. const std::string instrument_type{payment->GetTypeString()};
  5151. const QString qstrInstrumentType = QString::fromStdString(instrument_type);
  5152. qstrErrorMsg = QString("%1: %2")
  5153. .arg("Failed to import; unexpected financial instrument type")
  5154. .arg(qstrInstrumentType);
  5155. break;
  5156. }
  5157. }
  5158. if (!qstrErrorMsg.isEmpty()) {
  5159. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), qstrErrorMsg);
  5160. return;
  5161. }
  5162. // -----------------------------------------------
  5163. auto recipient_nym_id = opentxs::Identifier::Factory(),
  5164. sender_nym_id = opentxs::Identifier::Factory(),
  5165. remitter_nym_id = opentxs::Identifier::Factory(),
  5166. notary_id = opentxs::Identifier::Factory();
  5167. const bool has_recipient_nym = payment->GetRecipientNymID(recipient_nym_id);
  5168. const bool has_sender_nym = payment->GetSenderNymID(sender_nym_id);
  5169. const bool has_remitter_nym = payment->IsVoucher() && payment->GetRemitterNymID(remitter_nym_id);
  5170. const bool has_notary_id = payment->GetNotaryID(notary_id);
  5171. auto myNyms = ot_.OTAPI().LocalNymList();
  5172. const bool recipientNymIsMine = has_recipient_nym && (1 == myNyms.count(recipient_nym_id));
  5173. const bool senderNymIsMine = has_sender_nym && (1 == myNyms.count(sender_nym_id));
  5174. const bool remitterNymIsMine = has_remitter_nym && (1 == myNyms.count(remitter_nym_id));
  5175. const bool bISentThisThing = (senderNymIsMine || remitterNymIsMine);
  5176. if (bISentThisThing && has_recipient_nym && !recipientNymIsMine)
  5177. {
  5178. // Todo: We might allow this in the future, in the case where you want
  5179. // to CANCEL a cheque that you wrote. In this spot, the UI might pop up
  5180. // and ask if you want to cancel the cheque.
  5181. //
  5182. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5183. tr("Failed: Cannot import an instrument that you yourself created, "
  5184. "unless you are also a valid recipient on that instrument (which you are not, in this case). "
  5185. "Anyway, it should already be in your sent box!"));
  5186. return;
  5187. }
  5188. // -----------------------------------------------
  5189. std::string str_notary_id;
  5190. if (has_notary_id) {
  5191. auto strNotaryId = opentxs::String::Factory(notary_id);
  5192. str_notary_id = strNotaryId->Get();
  5193. }
  5194. // -----------------------------------------------
  5195. // bool bPaymentSenderIsNym {false};
  5196. // bool bFromAcctIsAvailable{false};
  5197. //
  5198. // Identifier theSenderNymID, theSenderAcctID;
  5199. //
  5200. // if (thePayment.IsVoucher()) {
  5201. // bPaymentSenderIsNym =
  5202. // (thePayment.GetRemitterNymID(theSenderNymID) &&
  5203. // nymfile->CompareID(theSenderNymID));
  5204. //
  5205. // bFromAcctIsAvailable =
  5206. // thePayment.GetRemitterAcctID(theSenderAcctID);
  5207. // } else {
  5208. // bPaymentSenderIsNym =
  5209. // (thePayment.GetSenderNymID(theSenderNymID) &&
  5210. // nymfile->CompareID(theSenderNymID));
  5211. // bFromAcctIsAvailable =
  5212. // thePayment.GetSenderAcctID(theSenderAcctID);
  5213. // }
  5214. // This is for all financial instruments EXCEPT a cash purse.
  5215. //
  5216. // if (false == payment->IsPurse())
  5217. if (payment->IsCheque() || payment->IsVoucher())
  5218. {
  5219. if (has_recipient_nym)
  5220. {
  5221. if (recipientNymIsMine)
  5222. {
  5223. // Not ready to turn this on yet, since I need to be able to
  5224. // run it both ways in order to test the difference in how
  5225. // the receipts show up in the inbox. (Which was a problem
  5226. // last time I tested it).
  5227. // Once I can verify the receipts are showing up correctly,
  5228. // I will uncomment this and remove the other code.
  5229. //
  5230. // COMING SOON:
  5231. //
  5232. // const opentxs::Identifier taskId = ot_.Sync().
  5233. // DepositPayment(recipient_nym_id, payment);
  5234. // const opentxs::String strTaskId(taskId);
  5235. // const std::string str_task_id{strTaskId.Get()};
  5236. // const QString qstrTaskId{QString::fromStdString(str_task_id)};
  5237. //
  5238. // const QString qstrMsg = QString("%1. "
  5239. // "%2: %3"
  5240. // )
  5241. // .arg(tr("Successfully initiated deposit"))
  5242. // .arg(tr("Make sure you write down your Task ID"))
  5243. // .arg(qstrTaskId);
  5244. //
  5245. // QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), qstrMsg);
  5246. // return;
  5247. const auto otstr_recip = opentxs::String::Factory(recipient_nym_id);
  5248. const std::string str_recipient_nym_id(otstr_recip->Get());
  5249. auto unit_type_id = opentxs::Identifier::Factory();
  5250. payment->GetInstrumentDefinitionID(unit_type_id);
  5251. const auto otstr_unit = opentxs::String::Factory(unit_type_id);
  5252. const std::string str_unit_type_id(otstr_unit->Get());
  5253. // Maybe we ALREADY have an account of the correct type, that we
  5254. // can deposit this cheque into. Let's try and look it up.
  5255. //
  5256. DlgChooser theChooser(this);
  5257. theChooser.SetIsAccounts();
  5258. // -----------------------------------------------
  5259. mapIDName & the_map = theChooser.m_map;
  5260. bool bFoundDefault = false;
  5261. // -----------------------------------------------
  5262. const auto& db = ot_.Storage();
  5263. for (const auto& [id, alias] : db.AccountList())
  5264. {
  5265. const auto accountID = opentxs::Identifier::Factory(id);
  5266. const auto nymID = db.AccountOwner(accountID);
  5267. const auto serverID = db.AccountServer(accountID);
  5268. const auto unitID = db.AccountContract(accountID);
  5269. const auto otstrAccountId = opentxs::String::Factory(accountID.get());
  5270. const auto otstrNymId = opentxs::String::Factory(nymID.get());
  5271. const auto otstrServerId = opentxs::String::Factory(serverID.get());
  5272. const auto otstrUnitId = opentxs::String::Factory(unitID.get());
  5273. const std::string str_account_id{otstrAccountId->Get()};
  5274. QString OT_acct_id = QString::fromStdString(str_account_id);
  5275. QString OT_acct_name("");
  5276. const std::string str_acct_nym_id = otstrNymId->Get();
  5277. const std::string str_acct_asset_id = otstrUnitId->Get();
  5278. const std::string str_acct_notary_id = otstrServerId->Get();
  5279. if (!str_recipient_nym_id.empty() && (0 != str_recipient_nym_id.compare(str_acct_nym_id)))
  5280. continue;
  5281. if (0 != str_unit_type_id.compare(str_acct_asset_id))
  5282. continue;
  5283. if (0 != str_notary_id.compare(str_acct_notary_id))
  5284. continue;
  5285. // -----------------------------------------------
  5286. if (!default_account_id.isEmpty() && (OT_acct_id == default_account_id))
  5287. bFoundDefault = true;
  5288. // -----------------------------------------------
  5289. OT_acct_name = QString::fromStdString(ot_.Exec().GetAccountWallet_Name(OT_acct_id.toStdString()));
  5290. // -----------------------------------------------
  5291. the_map.insert(OT_acct_id, OT_acct_name);
  5292. }
  5293. // -----------------------------------------------
  5294. if (the_map.size() < 1)
  5295. {
  5296. // QMessageBox::warning(this, tr("No Matching Accounts"),
  5297. // tr("The Nym doesn't have any accounts of the appropriate asset type, "
  5298. // "on the appropriate server. Please create one and then try again."));
  5299. // This is where we can just call Justus' function.
  5300. // (There's no matching account, so the new API stuff can just
  5301. // create that account for us).
  5302. //
  5303. // This way for now, I can test the new code (by trying it
  5304. // with zero accounts, which Justus should create) AND I
  5305. // can compare it to the behavior of the old code (by trying
  5306. // it when I already have accounts created). That way I can
  5307. // compare behavior in terms of what receipts show up in the
  5308. // UI, and make sure that's behaving properly in the new code.
  5309. //
  5310. const auto taskId = ot_.Sync().
  5311. DepositPayment(recipient_nym_id, payment);
  5312. const auto strTaskId = opentxs::String::Factory(taskId);
  5313. const std::string str_task_id{strTaskId->Get()};
  5314. const QString qstrTaskId{QString::fromStdString(str_task_id)};
  5315. const QString qstrMsg = QString("%1. "
  5316. "%2: %3"
  5317. )
  5318. .arg(tr("Successfully initiated deposit"))
  5319. .arg(tr("Make sure you write down your Task ID"))
  5320. .arg(qstrTaskId);
  5321. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), qstrMsg);
  5322. return;
  5323. }
  5324. // -----------------------------------------------
  5325. // There's exactly one matching account in existence already.
  5326. // (With the right Nym, Server, and Unit type to deposit this
  5327. // cheque).
  5328. //
  5329. else if (1 == the_map.size())
  5330. {
  5331. const std::string str_deposit_acct_id(the_map.firstKey().toStdString());
  5332. int32_t nDepositCheque = 0;
  5333. {
  5334. MTSpinner theSpinner;
  5335. auto deposit_acct_id = opentxs::Identifier::Factory(str_deposit_acct_id);
  5336. auto cheque{ot_.Factory().Cheque()};
  5337. OT_ASSERT(false != bool(cheque));
  5338. cheque->LoadContractFromString(opentxs::String::Factory(strInstrument.c_str()));
  5339. auto action = ot_.ServerAction().DepositCheque(recipient_nym_id,
  5340. notary_id,
  5341. deposit_acct_id,
  5342. cheque);
  5343. std::string response = action->Run();
  5344. nDepositCheque = opentxs::InterpretTransactionMsgReply(ot_, str_notary_id, str_recipient_nym_id, str_deposit_acct_id, "import_cash_or_cheque", response);
  5345. }
  5346. // --------------------------------------------
  5347. if (1 == nDepositCheque)
  5348. {
  5349. QMessageBox::information(this, tr("Success"), tr("Success depositing cheque or voucher."));
  5350. emit balancesChanged();
  5351. }
  5352. else
  5353. {
  5354. const int64_t lUsageCredits = Moneychanger::It()->HasUsageCredits(str_notary_id, str_recipient_nym_id);
  5355. // In the case of -2 and 0, the problem has to do with the usage credits,
  5356. // and it already pops up an error box. Otherwise, the user had enough usage
  5357. // credits, so there must have been some other problem, so we pop up an error box.
  5358. //
  5359. if ((lUsageCredits != (-2)) && (lUsageCredits != 0)) {
  5360. QMessageBox::information(this, tr("Import Failure"), tr("Failed trying to deposit cheque or voucher."));
  5361. }
  5362. }
  5363. return;
  5364. }
  5365. // -----------------------------------------------
  5366. // const opentxs::Identifier taskId = ot_.Sync().
  5367. // DepositPayment(recipient_nym_id, payment);
  5368. // const opentxs::String strTaskId(taskId);
  5369. // const std::string str_task_id{strTaskId.Get()};
  5370. // const QString qstrTaskId{QString::fromStdString(str_task_id)};
  5371. //
  5372. // const QString qstrMsg = QString("%1. "
  5373. // "%2: %3"
  5374. // )
  5375. // .arg(tr("Successfully initiated deposit via Sync().DepositPayment"))
  5376. // .arg(tr("Make sure you write down your Task ID"))
  5377. // .arg(qstrTaskId);
  5378. //
  5379. // QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), qstrMsg);
  5380. // return;
  5381. // NOTE: The above commented-out code is what we should actually
  5382. // be using.
  5383. if (bFoundDefault && !default_account_id.isEmpty())
  5384. theChooser.SetPreSelected(default_account_id);
  5385. // -----------------------------------------------
  5386. theChooser.setWindowTitle(tr("Deposit Cheque to Which Account?"));
  5387. // -----------------------------------------------
  5388. if (theChooser.exec() == QDialog::Accepted)
  5389. {
  5390. if (!theChooser.m_qstrCurrentID.isEmpty())
  5391. {
  5392. const std::string str_deposit_acct_id(theChooser.m_qstrCurrentID.toStdString());
  5393. int32_t nDepositCheque = 0;
  5394. {
  5395. MTSpinner theSpinner;
  5396. auto deposit_acct_id = opentxs::Identifier::Factory(str_deposit_acct_id);
  5397. auto cheque{ot_.Factory().Cheque()};
  5398. OT_ASSERT(false != bool(cheque));
  5399. cheque->LoadContractFromString(opentxs::String::Factory(strInstrument.c_str()));
  5400. auto action = ot_.ServerAction().DepositCheque(recipient_nym_id,
  5401. notary_id,
  5402. deposit_acct_id,
  5403. cheque);
  5404. std::string response = action->Run();
  5405. nDepositCheque = opentxs::InterpretTransactionMsgReply(ot_, str_notary_id, str_recipient_nym_id, str_deposit_acct_id, "import_cash_or_cheque", response);
  5406. }
  5407. // --------------------------------------------
  5408. if (1 == nDepositCheque)
  5409. {
  5410. QMessageBox::information(this, tr("Success"), tr("Success depositing cheque."));
  5411. emit balancesChanged();
  5412. }
  5413. else
  5414. {
  5415. const int64_t lUsageCredits = Moneychanger::It()->HasUsageCredits(str_notary_id, str_recipient_nym_id);
  5416. // In the case of -2 and 0, the problem has to do with the usage credits,
  5417. // and it already pops up an error box. Otherwise, the user had enough usage
  5418. // credits, so there must have been some other problem, so we pop up an error box.
  5419. //
  5420. if ((lUsageCredits != (-2)) && (lUsageCredits != 0)) {
  5421. QMessageBox::information(this, tr("Import Failure"), tr("Failed trying to deposit cheque."));
  5422. return;
  5423. }
  5424. }
  5425. }
  5426. } // dialog accepted.
  5427. } // recipient Nym is mine.
  5428. // ----------------------------
  5429. //else: There's a recipient Nym, but it's not mine.
  5430. const auto strRecipientNymId = opentxs::String::Factory(recipient_nym_id);
  5431. const std::string str_recipient_nym_id{strRecipientNymId->Get()};
  5432. std::string str_recipient_name = ot_.Exec().GetNym_Name(str_recipient_nym_id);
  5433. QString qstrRecipientId = str_recipient_nym_id.empty()
  5434. ? QString("")
  5435. : QString::fromStdString(str_recipient_nym_id);
  5436. QString qstrRecipientName = str_recipient_name.empty()
  5437. ? QString("")
  5438. : QString::fromStdString(str_recipient_name);
  5439. const QString qstrMsg = QString("%1: %2. %3: %4, \"%5\"")
  5440. .arg(tr("Unable to import this instrument"))
  5441. .arg(tr("It has a recipient, but the recipient is NOT you"))
  5442. .arg(tr("Recipient ID and name (if known)"))
  5443. .arg(qstrRecipientId)
  5444. .arg(qstrRecipientName);
  5445. // todo: Use a different dlg here and actually display the
  5446. // unarmored plaintext of the instrument so the user can view it,
  5447. // and copy to clipboard.
  5448. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), qstrMsg);
  5449. return;
  5450. }
  5451. // else has no recipient at all...
  5452. // Here it's NOT a purse (something else)
  5453. // and it does NOT have a recipient Nym.
  5454. //
  5455. // So it might be a cheque with a blank recipient,
  5456. // because we already know it's not cash.
  5457. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME),
  5458. tr("Sorry - it's probably a cheque with a blank recipient, and this import dialog can't handle those yet. (Soon!)"));
  5459. //todo, resume (invoices, plus cheques with no recipient ID).
  5460. // "This is an invoice, requesting payment from you. Do you want to
  5461. // pay it now?"
  5462. //
  5463. // "This cheque has a blank recipient. Do you want to go ahead and
  5464. // deposit it?"
  5465. return;
  5466. }
  5467. // ************************************************************************
  5468. // else CASH PURSE...
  5469. //
  5470. std::string strNotaryID = ot_.Exec().Instrmnt_GetNotaryID(strInstrument);
  5471. //resume
  5472. if (strNotaryID.empty())
  5473. {
  5474. QMessageBox::warning(this, tr("Indeterminate Server"),
  5475. tr("Unable to determine server ID for this instrument. Are you sure it's properly formed?"));
  5476. return;
  5477. }
  5478. // -----------------------
  5479. std::string strInstrumentDefinitionID = ot_.Exec().Instrmnt_GetInstrumentDefinitionID(strInstrument);
  5480. if (strInstrumentDefinitionID.empty())
  5481. {
  5482. QMessageBox::warning(this, tr("Indeterminate Asset Type"),
  5483. tr("Unable to determine asset ID for this instrument. Are you sure it's properly formed?"));
  5484. return;
  5485. }
  5486. // -----------------------
  5487. std::string strServerContract = ot_.Exec().LoadServerContract(strNotaryID);
  5488. if (strServerContract.empty())
  5489. {
  5490. QMessageBox::warning(this, tr("No Server Contract Found"),
  5491. QString("%1 '%2'<br/>%3").arg(tr("Unable to load the server contract for server ID")).
  5492. arg(QString::fromStdString(strNotaryID)).arg(tr("Are you sure that server contract is even in your wallet?")));
  5493. return;
  5494. }
  5495. // -----------------------
  5496. std::string strAssetContract = ot_.Exec().GetAssetType_Contract(strInstrumentDefinitionID);
  5497. if (strAssetContract.empty())
  5498. {
  5499. QMessageBox::warning(this, tr("No Asset Contract Found"),
  5500. QString("%1 '%2'<br/>%3").arg(tr("Unable to load the asset contract for asset ID")).
  5501. arg(QString::fromStdString(strInstrumentDefinitionID)).arg(tr("Are you sure that asset type is even in your wallet?")));
  5502. return;
  5503. }
  5504. // -----------------------
  5505. // By this point, we know it's a purse, and we know it has Server
  5506. // and Asset IDs for contracts that are found in this wallet.
  5507. //
  5508. // Next, let's see if the purse is password-protected, and if not,
  5509. // let's see if the recipient Nym is named on the instrument. (He may not be.)
  5510. //
  5511. #if OT_CASH
  5512. const bool bHasPassword = ot_.Exec().Purse_HasPassword(strNotaryID, strInstrument);
  5513. std::string strPurseOwner("");
  5514. if (!bHasPassword)
  5515. {
  5516. // If the purse isn't password-protected, then it's DEFINITELY encrypted to
  5517. // a specific Nym.
  5518. //
  5519. // The purse MAY include the NymID for this Nym, but it MAY also be blank, in
  5520. // which case the user will have to select a Nym to TRY.
  5521. //
  5522. strPurseOwner = ot_.Exec().Instrmnt_GetRecipientNymID(strInstrument); // TRY and get the Nym ID (it may have been left blank.)
  5523. if (strPurseOwner.empty())
  5524. {
  5525. // Looks like it was left blank...
  5526. // (Meaning we need to ask the user to tell us which Nym it was.)
  5527. //
  5528. // Select from Nyms in local wallet.
  5529. //
  5530. DlgChooser theChooser(this, tr("The cash purse is encrypted to a specific Nym, "
  5531. "but that Nym isn't named on the purse. Therefore, you must select the intended Nym. "
  5532. "But choose wisely -- for if you pick the wrong Nym, the import will fail!"));
  5533. // -----------------------------------------------
  5534. mapIDName & the_map = theChooser.m_map;
  5535. bool bFoundDefault = false;
  5536. // -----------------------------------------------
  5537. const int32_t nym_count = ot_.Exec().GetNymCount();
  5538. // -----------------------------------------------
  5539. for (int32_t ii = 0; ii < nym_count; ++ii)
  5540. {
  5541. //Get OT Nym ID
  5542. QString OT_nym_id = QString::fromStdString(ot_.Exec().GetNym_ID(ii));
  5543. QString OT_nym_name("");
  5544. // -----------------------------------------------
  5545. if (!OT_nym_id.isEmpty())
  5546. {
  5547. if (!default_nym_id.isEmpty() && (OT_nym_id == default_nym_id))
  5548. bFoundDefault = true;
  5549. // -----------------------------------------------
  5550. OT_nym_name = QString::fromStdString(ot_.Exec().GetNym_Name(OT_nym_id.toStdString()));
  5551. // -----------------------------------------------
  5552. the_map.insert(OT_nym_id, OT_nym_name);
  5553. }
  5554. }
  5555. // -----------------------------------------------
  5556. if (bFoundDefault && !default_nym_id.isEmpty())
  5557. theChooser.SetPreSelected(default_nym_id);
  5558. // -----------------------------------------------
  5559. theChooser.setWindowTitle(tr("Choose Recipient Nym for Cash"));
  5560. // -----------------------------------------------
  5561. if (theChooser.exec() != QDialog::Accepted)
  5562. return;
  5563. else
  5564. {
  5565. if (theChooser.m_qstrCurrentID.isEmpty())
  5566. return; // Should never happen.
  5567. // -----------------------------
  5568. strPurseOwner = theChooser.m_qstrCurrentID.toStdString();
  5569. }
  5570. } // if strPurseOwner is empty (above the user selects him then.)
  5571. // --------------------------------------
  5572. if (!ot_.Exec().IsNym_RegisteredAtServer(strPurseOwner, strNotaryID))
  5573. {
  5574. QMessageBox::warning(this, tr("Nym Isn't Registered at Server"),
  5575. QString("%1 '%2'<br/>%3 '%4'<br/>%5").
  5576. arg(tr("The Nym with ID")).
  5577. arg(QString::fromStdString(strPurseOwner)).
  5578. arg(tr("isn't registered at the Server with ID")).
  5579. arg(QString::fromStdString(strNotaryID)).
  5580. arg(tr("Try using that nym to create an asset account on that server, and then try importing this cash again.")));
  5581. return;
  5582. }
  5583. } // If the purse is NOT password protected. (e.g. if the purse is encrypted to a specific Nym.)
  5584. // -----------------------------------------------------------------
  5585. // By this point, we know the purse is either password-protected, or that it's
  5586. // encrypted to a Nym who IS registered at the appropriate server.
  5587. //
  5588. // ---------------------------------------------
  5589. // DEPOSIT the cash to an ACCOUNT.
  5590. //
  5591. // We can't just import it to the wallet because the cash tokens aren't truly safe
  5592. // until they are redeemed. (Until then, the sender still has a copy of them.)
  5593. //
  5594. // Use opentxs::OT_ME::deposit_cash (vs deposit_local_purse) since the cash is external.
  5595. // Otherwise if the deposit fails, OT will try to "re-import" them, even though
  5596. // they were never in the purse in the first place.
  5597. //
  5598. // This would, of course, mix up coins that the sender has a copy of, with coins
  5599. // that only I have a copy of -- which we don't want to do.
  5600. //
  5601. // Select from Accounts in local wallet.
  5602. //
  5603. DlgChooser theChooser(this);
  5604. theChooser.SetIsAccounts();
  5605. // -----------------------------------------------
  5606. mapIDName & the_map = theChooser.m_map;
  5607. bool bFoundDefault = false;
  5608. for (const auto& [accountID, alias] : ot_.Storage().AccountList())
  5609. {
  5610. //Get OT Acct ID
  5611. QString OT_acct_id = QString::fromStdString(accountID);
  5612. QString OT_acct_name("");
  5613. // -----------------------------------------------
  5614. if (!OT_acct_id.isEmpty())
  5615. {
  5616. std::string str_acct_nym_id = ot_.Exec().GetAccountWallet_NymID (OT_acct_id.toStdString());
  5617. std::string str_acct_asset_id = ot_.Exec().GetAccountWallet_InstrumentDefinitionID(OT_acct_id.toStdString());
  5618. std::string str_acct_notary_id = ot_.Exec().GetAccountWallet_NotaryID (OT_acct_id.toStdString());
  5619. if (!strPurseOwner.empty() && (0 != strPurseOwner.compare(str_acct_nym_id)))
  5620. continue;
  5621. if (0 != strInstrumentDefinitionID.compare(str_acct_asset_id))
  5622. continue;
  5623. if (0 != strNotaryID.compare(str_acct_notary_id))
  5624. continue;
  5625. // -----------------------------------------------
  5626. if (!default_account_id.isEmpty() && (OT_acct_id == default_account_id))
  5627. bFoundDefault = true;
  5628. // -----------------------------------------------
  5629. OT_acct_name = QString::fromStdString(ot_.Exec().GetAccountWallet_Name(OT_acct_id.toStdString()));
  5630. // -----------------------------------------------
  5631. the_map.insert(OT_acct_id, OT_acct_name);
  5632. }
  5633. }
  5634. // -----------------------------------------------
  5635. if (the_map.size() < 1)
  5636. {
  5637. QMessageBox::warning(this, tr("No Matching Accounts"),
  5638. tr("The Nym doesn't have any accounts of the appropriate asset type, "
  5639. "on the appropriate server. Please create one and then try again."));
  5640. return;
  5641. }
  5642. // -----------------------------------------------
  5643. if (bFoundDefault && !default_account_id.isEmpty())
  5644. theChooser.SetPreSelected(default_account_id);
  5645. // -----------------------------------------------
  5646. theChooser.setWindowTitle(tr("Deposit Cash to Which Account?"));
  5647. // -----------------------------------------------
  5648. if (theChooser.exec() == QDialog::Accepted)
  5649. {
  5650. if (!theChooser.m_qstrCurrentID.isEmpty())
  5651. {
  5652. if (strPurseOwner.empty())
  5653. strPurseOwner = ot_.Exec().GetAccountWallet_NymID(theChooser.m_qstrCurrentID.toStdString());
  5654. // -------------------------------------------
  5655. // const bool bImported = ot_.Exec().Wallet_ImportPurse(strNotaryID, strInstrumentDefinitionID, strPurseOwner, strInstrument);
  5656. int32_t nDepositCash = 0;
  5657. {
  5658. MTSpinner theSpinner;
  5659. nDepositCash = ot_.Cash().deposit_cash(strNotaryID, strPurseOwner,
  5660. theChooser.m_qstrCurrentID.toStdString(), // AcctID.
  5661. strInstrument);
  5662. }
  5663. // --------------------------------------------
  5664. if (1 == nDepositCash)
  5665. {
  5666. QMessageBox::information(this, tr("Success"), tr("Success depositing cash purse."));
  5667. emit balancesChanged();
  5668. }
  5669. else
  5670. {
  5671. const int64_t lUsageCredits = Moneychanger::It()->HasUsageCredits(strNotaryID, strPurseOwner);
  5672. // In the case of -2 and 0, the problem has to do with the usage credits,
  5673. // and it already pops up an error box. Otherwise, the user had enough usage
  5674. // credits, so there must have been some other problem, so we pop up an error box.
  5675. //
  5676. if ((lUsageCredits != (-2)) && (lUsageCredits != 0)) {
  5677. QMessageBox::information(this, tr("Import Failure"), tr("Failed trying to deposit cash purse."));
  5678. return;
  5679. }
  5680. }
  5681. }
  5682. }
  5683. #else
  5684. return;
  5685. #endif // OT_CASH
  5686. }
  5687. // -----------------------------------------------
  5688. /**
  5689. * Propose Payment Plan
  5690. **/
  5691. void Moneychanger::mc_proposeplan_slot()
  5692. {
  5693. mc_proposeplan_show_dialog();
  5694. }
  5695. void Moneychanger::mc_proposeplan_show_dialog(QString qstrAcct/*=QString("")*/, QString qstrContact/*=QString("")*/)
  5696. {
  5697. // --------------------------------------------------
  5698. ProposePlanDlg * plan_window = new ProposePlanDlg(nullptr);
  5699. plan_window->setAttribute(Qt::WA_DeleteOnClose);
  5700. // --------------------------------------------------
  5701. QString qstr_acct_id = qstrAcct.isEmpty() ? this->get_default_account_id() : qstrAcct;
  5702. if (!qstr_acct_id.isEmpty())
  5703. plan_window->setInitialMyAcct(qstr_acct_id);
  5704. // ---------------------------------------
  5705. plan_window->dialog();
  5706. // --------------------------------------------------
  5707. }
  5708. void Moneychanger::mc_proposeplan_to_acct(QString qstrAcct)
  5709. {
  5710. mc_proposeplan_show_dialog(qstrAcct);
  5711. }
  5712. void Moneychanger::mc_proposeplan_to_acct_from_contact(QString qstrAcct, QString qstrContact)
  5713. {
  5714. mc_proposeplan_show_dialog(qstrAcct, qstrContact);
  5715. }
  5716. /**
  5717. * Request Funds
  5718. **/
  5719. void Moneychanger::mc_requestfunds_slot()
  5720. {
  5721. mc_requestfunds_show_dialog();
  5722. }
  5723. void Moneychanger::mc_request_to_acct_from_contact(QString qstrAcct, QString qstrContact)
  5724. {
  5725. mc_requestfunds_show_dialog(qstrAcct, qstrContact);
  5726. }
  5727. void Moneychanger::mc_request_to_acct(QString qstrAcct)
  5728. {
  5729. mc_requestfunds_show_dialog(qstrAcct);
  5730. }
  5731. void Moneychanger::mc_requestfunds_show_dialog(QString qstrAcct/*=QString("")*/, QString qstrContact/*=QString("")*/)
  5732. {
  5733. // --------------------------------------------------
  5734. MTRequestDlg * request_window = new MTRequestDlg(nullptr);
  5735. request_window->setAttribute(Qt::WA_DeleteOnClose);
  5736. // --------------------------------------------------
  5737. QString qstr_acct_id = qstrAcct.isEmpty() ? this->get_default_account_id() : qstrAcct;
  5738. if (!qstr_acct_id.isEmpty())
  5739. request_window->setInitialMyAcct(qstr_acct_id);
  5740. // --------------------------------------------------
  5741. if (!qstrContact.isEmpty())
  5742. {
  5743. request_window->setInitialHisContact(qstrContact);
  5744. }
  5745. // ---------------------------------------
  5746. request_window->dialog();
  5747. // --------------------------------------------------
  5748. }
  5749. /**
  5750. * Send Funds
  5751. **/
  5752. void Moneychanger::mc_sendfunds_slot()
  5753. {
  5754. mc_sendfunds_show_dialog();
  5755. }
  5756. void Moneychanger::mc_send_from_acct_to_contact(QString qstrAcct, QString qstrContact)
  5757. {
  5758. mc_sendfunds_show_dialog(qstrAcct, qstrContact);
  5759. }
  5760. void Moneychanger::mc_sendfunds_show_dialog(QString qstrAcct/*=QString("")*/, QString qstrContact/*=QString("")*/)
  5761. {
  5762. // --------------------------------------------------
  5763. MTSendDlg * send_window = new MTSendDlg(nullptr);
  5764. send_window->setAttribute(Qt::WA_DeleteOnClose);
  5765. // --------------------------------------------------
  5766. QString qstr_acct_id = qstrAcct.isEmpty() ? this->get_default_account_id() : qstrAcct;
  5767. if (!qstr_acct_id.isEmpty())
  5768. send_window->setInitialMyAcct(qstr_acct_id);
  5769. // --------------------------------------------------
  5770. if (!qstrContact.isEmpty())
  5771. {
  5772. send_window->setInitialHisContact(qstrContact);
  5773. }
  5774. // ---------------------------------------
  5775. send_window->dialog();
  5776. // --------------------------------------------------
  5777. }
  5778. void Moneychanger::mc_send_from_acct(QString qstrAcct)
  5779. {
  5780. mc_sendfunds_show_dialog(qstrAcct);
  5781. }
  5782. /**
  5783. * Compose Message
  5784. **/
  5785. void Moneychanger::mc_composemessage_slot()
  5786. {
  5787. mc_composemessage_show_dialog();
  5788. }
  5789. //Send a message, optionally from a given Nym and optionally to a given Contact.
  5790. void Moneychanger::mc_message_contact_slot(QString qstrFromNym, QString qstrToOpentxsContact) // Compose Message to specific opentxs contact
  5791. {
  5792. if (opentxs::Messagability::READY ==
  5793. Moneychanger::It()->OT().Sync().CanMessage(opentxs::Identifier::Factory(qstrFromNym.toStdString()),
  5794. opentxs::Identifier::Factory(qstrToOpentxsContact.toStdString())))
  5795. {
  5796. mc_composemessage_show_dialog(qstrToOpentxsContact, qstrFromNym);
  5797. }
  5798. else
  5799. {
  5800. QMessageBox::warning(this, tr(MONEYCHANGER_APP_NAME), tr("Sorry, but the selected contact is not yet messagable."));
  5801. }
  5802. }
  5803. void Moneychanger::mc_composemessage_show_dialog(QString qstrToOpentxsContact/*=""*/, QString qstrFromNym/*=""*/)
  5804. {
  5805. // --------------------------------------------------
  5806. MTCompose * compose_window = new MTCompose;
  5807. compose_window->setAttribute(Qt::WA_DeleteOnClose);
  5808. // --------------------------------------------------
  5809. // If Moneychanger has a default Nym set, we use that for the Sender.
  5810. // (User can always change it.)
  5811. //
  5812. if (qstrFromNym.isEmpty())
  5813. {
  5814. QString qstrDefaultNym = this->get_default_nym_id();
  5815. if (!qstrDefaultNym.isEmpty()) // Sender Nym is set.
  5816. qstrFromNym = qstrDefaultNym;
  5817. }
  5818. compose_window->setInitialSenderNym(qstrFromNym);
  5819. // --------------------------------------------------
  5820. if (!qstrToOpentxsContact.isEmpty()) {
  5821. compose_window->setInitialRecipientContactID(qstrToOpentxsContact);
  5822. }
  5823. // --------------------------------------------------
  5824. else {
  5825. QString qstrDefaultServer = this->get_default_notary_id();
  5826. if (!qstrDefaultServer.isEmpty())
  5827. compose_window->setInitialServer(qstrDefaultServer);
  5828. }
  5829. // --------------------------------------------------
  5830. compose_window->dialog();
  5831. Focuser f(compose_window);
  5832. f.show();
  5833. f.focus();
  5834. // --------------------------------------------------
  5835. }
  5836. void Moneychanger::mc_messages_slot()
  5837. {
  5838. mc_messages_dialog();
  5839. }
  5840. void Moneychanger::mc_messages_dialog()
  5841. {
  5842. if (!messages_window)
  5843. {
  5844. messages_window = new Messages(this);
  5845. connect(messages_window, SIGNAL(needToDownloadMail()), this, SLOT(onNeedToDownloadMail()));
  5846. // connect(this, SIGNAL(populatedRecordlist()), messages_window, SLOT(onRecordlistPopulated()));
  5847. // connect(this, SIGNAL(claimsUpdatedForNym(QString)), messages_window, SLOT(onClaimsUpdatedForNym(QString)));
  5848. }
  5849. // ---------------------------------
  5850. messages_window->dialog();
  5851. }
  5852. void Moneychanger::mc_payments_slot()
  5853. {
  5854. mc_payments_dialog();
  5855. }
  5856. void Moneychanger::mc_show_payment_slot(int nSourceRow, int nFolder)
  5857. {
  5858. mc_payments_dialog(nSourceRow, nFolder);
  5859. }
  5860. void Moneychanger::mc_payments_dialog(int nSourceRow/*=-1*/, int nFolder/*=-1*/)
  5861. {
  5862. if (!payments_window)
  5863. {
  5864. payments_window = new Payments(this);
  5865. connect(payments_window, SIGNAL(showDashboard()), this, SLOT(mc_overview_slot()));
  5866. // connect(payments_window, SIGNAL(needToDownloadAccountData()), this, SLOT(onNeedToDownloadAccountData()));
  5867. // connect(this, SIGNAL(populatedRecordlist()), payments_window, SLOT(onRecordlistPopulated()));
  5868. // connect(payments_window, SIGNAL(needToPopulateRecordlist()), this, SLOT(onNeedToPopulateRecordlist()));
  5869. // connect(this, SIGNAL(balancesChanged()), payments_window, SLOT(onBalancesChanged()));
  5870. // connect(this, SIGNAL(claimsUpdatedForNym(QString)), payments_window, SLOT(onClaimsUpdatedForNym(QString)));
  5871. }
  5872. // ---------------------------------
  5873. payments_window->dialog(nSourceRow, nFolder);
  5874. }
  5875. void Moneychanger::mc_activity_slot()
  5876. {
  5877. mc_activity_dialog();
  5878. }
  5879. void Moneychanger::mc_agreements_slot()
  5880. {
  5881. mc_agreements_dialog();
  5882. }
  5883. void Moneychanger::mc_show_agreement_slot(int nSourceRow, int nFolder)
  5884. {
  5885. mc_agreements_dialog(nSourceRow, nFolder);
  5886. }
  5887. void Moneychanger::mc_activity_dialog()
  5888. {
  5889. if (!activity_window)
  5890. {
  5891. activity_window = new Activity(this);
  5892. connect(activity_window, SIGNAL(showDashboard()), this, SLOT(mc_overview_slot()));
  5893. // connect(activity_window, SIGNAL(needToDownloadAccountData()), this, SLOT(onNeedToDownloadAccountData()));
  5894. // connect(this, SIGNAL(populatedRecordlist()), activity_window, SLOT(onRecordlistPopulated()));
  5895. // connect(activity_window, SIGNAL(needToPopulateRecordlist()), this, SLOT(onNeedToPopulateRecordlist()));
  5896. // connect(this, SIGNAL(balancesChanged()), activity_window, SLOT(onBalancesChanged()));
  5897. // connect(this, SIGNAL(claimsUpdatedForNym(QString)), activity_window, SLOT(onClaimsUpdatedForNym(QString)));
  5898. connect(this, SIGNAL(opentxsWidgetUpdated(QString)), activity_window, SLOT(onOpentxsWidgetUpdated(QString)));
  5899. }
  5900. // ---------------------------------
  5901. activity_window->dialog();
  5902. }
  5903. void Moneychanger::mc_agreements_dialog(int nSourceRow/*=-1*/, int nFolder/*=-1*/)
  5904. {
  5905. if (!agreements_window)
  5906. {
  5907. agreements_window = new Agreements(this);
  5908. connect(agreements_window, SIGNAL(showDashboard()), this, SLOT(mc_overview_slot()));
  5909. // connect(agreements_window, SIGNAL(needToDownloadAccountData()), this, SLOT(onNeedToDownloadAccountData()));
  5910. // connect(this, SIGNAL(populatedRecordlist()), agreements_window, SLOT(onRecordlistPopulated()));
  5911. // connect(agreements_window, SIGNAL(needToPopulateRecordlist()), this, SLOT(onNeedToPopulateRecordlist()));
  5912. // connect(this, SIGNAL(balancesChanged()), agreements_window, SLOT(onBalancesChanged()));
  5913. // connect(this, SIGNAL(claimsUpdatedForNym(QString)), agreements_window, SLOT(onClaimsUpdatedForNym(QString)));
  5914. }
  5915. // ---------------------------------
  5916. agreements_window->dialog(nSourceRow, nFolder);
  5917. }
  5918. /**
  5919. * Overview Window
  5920. **/
  5921. //Overview slots
  5922. void Moneychanger::mc_overview_slot()
  5923. {
  5924. //The operator has requested to open the dialog to the "Overview";
  5925. mc_overview_dialog();
  5926. }
  5927. void Moneychanger::mc_overview_dialog_refresh()
  5928. {
  5929. // if (homewindow && !homewindow->isHidden())
  5930. // {
  5931. // mc_overview_dialog();
  5932. // }
  5933. }
  5934. void Moneychanger::mc_overview_dialog()
  5935. {
  5936. // if (!homewindow)
  5937. // {
  5938. // // MTHome is a widget, not a dialog. Therefore *this is set as the parent.
  5939. // // (Therefore no need to delete it ever, since *this will delete it on destruction.)
  5940. // //
  5941. // homewindow = new MTHome(this);
  5942. //// connect(homewindow, SIGNAL(needToDownloadAccountData()),
  5943. //// this, SLOT(onNeedToDownloadAccountData()));
  5944. //// connect(homewindow, SIGNAL(needToPopulateRecordlist()),
  5945. //// this, SLOT(onNeedToPopulateRecordlist()));
  5946. //// connect(this, SIGNAL(populatedRecordlist()),
  5947. //// homewindow, SLOT(onRecordlistPopulated()));
  5948. //// connect(this, SIGNAL(balancesChanged()),
  5949. //// homewindow, SLOT(onBalancesChanged()));
  5950. // qDebug() << "Overview Opened";
  5951. // }
  5952. // // ---------------------------------
  5953. // homewindow->dialog();
  5954. }
  5955. // End Overview
  5956. void Moneychanger::onServersChanged()
  5957. {
  5958. // Because the Nym details page has a list of servers that Nym is registered on.
  5959. // So if we've added a new Server, we should update that page, if it's open.
  5960. if (nullptr != nymswindow)
  5961. nymswindow->RefreshRecords();
  5962. if (menuwindow)
  5963. menuwindow->refreshOptions();
  5964. }
  5965. void Moneychanger::onAssetsChanged()
  5966. {
  5967. if (menuwindow)
  5968. menuwindow->refreshOptions();
  5969. }
  5970. void Moneychanger::onNymsChanged()
  5971. {
  5972. if (menuwindow)
  5973. menuwindow->refreshOptions();
  5974. }
  5975. void Moneychanger::onAccountsChanged()
  5976. {
  5977. if (menuwindow)
  5978. menuwindow->refreshOptions();
  5979. }
  5980. void Moneychanger::onNewNymAdded(QString qstrID)
  5981. {
  5982. // Add a new Contact in the Address Book for this Nym as well.
  5983. // (When testing, it's a pain having to add my own Nyms to the address book
  5984. // by hand for sending payments between them, every time I create a new Nym.)
  5985. // QString qstrNymName("");
  5986. // if (!qstrID.isEmpty())
  5987. // {
  5988. // qstrNymName = QString::fromStdString(ot_.Exec().GetNym_Name(qstrID.toStdString()));
  5989. // if (!qstrNymName.isEmpty())
  5990. // qstrNymName += QString(" (%1)").arg(tr("Me"));
  5991. //// QString qstrContactID = MTContactHandler::getInstance()->GetOrCreateOpentxsContactBasedOnNym(qstrNymName, qstrID, "");
  5992. // int nContactId = MTContactHandler::getInstance()->CreateContactBasedOnNym(qstrID);
  5993. // if (!qstrNymName.isEmpty() && (nContactId > 0))
  5994. // {
  5995. // MTContactHandler::getInstance()->SetContactName(nContactId, qstrNymName);
  5996. // if (nullptr != contactswindow)
  5997. // mc_addressbook_show();
  5998. // }
  5999. // // --------------------------------------------------
  6000. //// GetRecordlist().AddNymID(qstrID.toStdString());
  6001. // }
  6002. // onNymsChanged();
  6003. }
  6004. void Moneychanger::onNewAccountAdded(QString qstrID)
  6005. {
  6006. // GetRecordlist().AddAccountID(qstrID.toStdString());
  6007. onAccountsChanged();
  6008. }
  6009. // --------------------------------------------------
  6010. void Moneychanger::onNewServerAdded(QString qstrID)
  6011. {
  6012. // GetRecordlist().AddNotaryID(qstrID.toStdString());
  6013. onServersChanged();
  6014. }
  6015. void Moneychanger::onNewAssetAdded(QString qstrID)
  6016. {
  6017. // GetRecordlist().AddInstrumentDefinitionID(qstrID.toStdString());
  6018. onAssetsChanged();
  6019. }
  6020. void Moneychanger::PublicNymNotify(std::string id)
  6021. {
  6022. auto pNym = ot_.Wallet().Nym(opentxs::Identifier::Factory((id)));
  6023. if (pNym)
  6024. {
  6025. qDebug() << "I was notified that the DHT downloaded Nym "
  6026. << QString::fromStdString(id);
  6027. }
  6028. else // The Nym is not already in the wallet.
  6029. {
  6030. // I don't think I have to do anything at all then.
  6031. // No need to reload the wallet, since the Nym isn't loaded
  6032. // in the wallet, and if it ever does load that Nym in the
  6033. // near future, it will get the latest version then.
  6034. }
  6035. emit nymWasJustChecked(QString::fromStdString(id));
  6036. }
  6037. void Moneychanger::ServerContractNotify(std::string id)
  6038. {
  6039. auto pContract =
  6040. ot_.Wallet().Server(opentxs::Identifier::Factory((id)));
  6041. if (pContract) {
  6042. qDebug() << "I was notified that the DHT downloaded contract "
  6043. << QString::fromStdString(id);
  6044. emit serversChanged();
  6045. }
  6046. else {
  6047. qDebug() << "Strange: I was notified that we downloaded contract "
  6048. << QString::fromStdString(id)
  6049. << " but then failed trying to load it up.";
  6050. }
  6051. }
  6052. void Moneychanger::AssetContractNotify(std::string id)
  6053. {
  6054. const auto ot_id = opentxs::Identifier::Factory(id);
  6055. auto pContract = ot_.Wallet().UnitDefinition(ot_id);
  6056. if (pContract) {
  6057. qDebug() << "I was notified that the DHT downloaded contract "
  6058. << QString::fromStdString(id);
  6059. emit assetsChanged();
  6060. }
  6061. else {
  6062. qDebug() << "Strange: I was notified that we downloaded contract "
  6063. << QString::fromStdString(id)
  6064. << " but then failed trying to load it up.";
  6065. }
  6066. }
  6067. // --------------------------------------------------
  6068. /**
  6069. * Main Menu Window (For people who can't see the menu on the systray.)
  6070. **/
  6071. // Main Menu slots
  6072. void Moneychanger::mc_main_menu_slot()
  6073. {
  6074. //The operator has requested to open the dialog to the "main menu";
  6075. mc_main_menu_dialog();
  6076. }
  6077. // --------------------------------------------------
  6078. void Moneychanger::mc_main_menu_dialog(bool bShow/*=true*/)
  6079. {
  6080. if (!menuwindow)
  6081. {
  6082. // --------------------------------------------------
  6083. menuwindow = new DlgMenu(this);
  6084. // --------------------------------------------------
  6085. QCoreApplication * pCore = QCoreApplication::instance();
  6086. connect(pCore, SIGNAL(aboutToQuit()),
  6087. menuwindow, SLOT(onAboutToQuit()));
  6088. // --------------------------------------------------
  6089. connect(menuwindow, SIGNAL(sig_on_toolButton_payments_clicked()),
  6090. this, SLOT(mc_payments_slot()));
  6091. connect(menuwindow, SIGNAL(sig_on_toolButton_messages_clicked()),
  6092. this, SLOT(mc_messages_slot()));
  6093. connect(menuwindow, SIGNAL(sig_on_toolButton_pending_clicked()),
  6094. this, SLOT(mc_overview_slot()));
  6095. connect(menuwindow, SIGNAL(sig_on_toolButton_markets_clicked()),
  6096. this, SLOT(mc_market_slot()));
  6097. connect(menuwindow, SIGNAL(sig_on_toolButton_trade_archive_clicked()),
  6098. this, SLOT(mc_trade_archive_slot()));
  6099. connect(menuwindow, SIGNAL(sig_on_toolButton_secrets_clicked()),
  6100. this, SLOT(mc_passphrase_manager_slot()));
  6101. connect(menuwindow, SIGNAL(sig_on_toolButton_importCash_clicked()),
  6102. this, SLOT(mc_import_slot()));
  6103. connect(menuwindow, SIGNAL(sig_on_toolButton_contacts_clicked()),
  6104. this, SLOT(mc_addressbook_slot()));
  6105. connect(menuwindow, SIGNAL(sig_on_toolButton_manageAccounts_clicked()),
  6106. this, SLOT(mc_show_account_manager_slot()));
  6107. connect(menuwindow, SIGNAL(sig_on_toolButton_manageAssets_clicked()),
  6108. this, SLOT(mc_defaultasset_slot()));
  6109. connect(menuwindow, SIGNAL(sig_on_toolButton_manageNyms_clicked()),
  6110. this, SLOT(mc_defaultnym_slot()));
  6111. connect(menuwindow, SIGNAL(sig_on_toolButton_manageServers_clicked()),
  6112. this, SLOT(mc_defaultserver_slot()));
  6113. connect(menuwindow, SIGNAL(sig_on_toolButton_smartContracts_clicked()),
  6114. this, SLOT(mc_smartcontract_slot()));
  6115. connect(menuwindow, SIGNAL(sig_on_toolButton_Corporations_clicked()),
  6116. this, SLOT(mc_corporation_slot()));
  6117. connect(menuwindow, SIGNAL(sig_on_toolButton_Transport_clicked()),
  6118. this, SLOT(mc_transport_slot()));
  6119. connect(menuwindow, SIGNAL(sig_on_toolButton_settings_clicked()),
  6120. this, SLOT(mc_settings_slot()));
  6121. connect(menuwindow, SIGNAL(sig_on_toolButton_quit_clicked()),
  6122. this, SLOT(mc_shutdown_slot()));
  6123. connect(menuwindow, SIGNAL(sig_on_toolButton_encrypt_clicked()),
  6124. this, SLOT(mc_crypto_encrypt_slot()));
  6125. connect(menuwindow, SIGNAL(sig_on_toolButton_sign_clicked()),
  6126. this, SLOT(mc_crypto_sign_slot()));
  6127. connect(menuwindow, SIGNAL(sig_on_toolButton_decrypt_clicked()),
  6128. this, SLOT(mc_crypto_decrypt_slot()));
  6129. connect(menuwindow, SIGNAL(sig_on_toolButton_requestPayment_clicked()),
  6130. this, SLOT(mc_requestfunds_slot()));
  6131. connect(menuwindow, SIGNAL(sig_on_toolButton_recurringPayment_clicked()),
  6132. this, SLOT(mc_proposeplan_slot()));
  6133. connect(menuwindow, SIGNAL(sig_on_toolButton_liveAgreements_clicked()),
  6134. this, SLOT(mc_agreements_slot()));
  6135. connect(menuwindow, SIGNAL(sig_on_toolButton_activity_clicked()),
  6136. this, SLOT(mc_activity_slot()));
  6137. }
  6138. // ---------------------------------
  6139. if (bShow)
  6140. {
  6141. if (!menuwindow->isVisible())
  6142. menuwindow->setVisible(true);
  6143. menuwindow->dialog();
  6144. }
  6145. else
  6146. {
  6147. menuwindow->setVisible(false);
  6148. }
  6149. }
  6150. // End Main Menu
  6151. /**
  6152. * Agreement Window
  6153. **/
  6154. void Moneychanger::mc_smartcontract_slot()
  6155. {
  6156. mc_smartcontract_dialog();
  6157. }
  6158. void Moneychanger::mc_smartcontract_dialog()
  6159. {
  6160. // -------------------------------------
  6161. if (!smartcontract_window)
  6162. smartcontract_window = new MTDetailEdit(this);
  6163. // -------------------------------------
  6164. mapIDName & the_map = smartcontract_window->m_map;
  6165. // -------------------------------------
  6166. the_map.clear();
  6167. // -------------------------------------
  6168. MTContactHandler::getInstance()->GetSmartContracts(the_map);
  6169. // -------------------------------------
  6170. smartcontract_window->setWindowTitle(tr("Smart Contracts"));
  6171. // -------------------------------------
  6172. smartcontract_window->dialog(MTDetailEdit::DetailEditTypeAgreement);
  6173. }
  6174. /**
  6175. * Market Window
  6176. **/
  6177. void Moneychanger::mc_market_slot()
  6178. {
  6179. mc_market_dialog();
  6180. }
  6181. void Moneychanger::mc_market_dialog()
  6182. {
  6183. if (!market_window)
  6184. {
  6185. market_window = new DlgMarkets(this);
  6186. // When Moneychanger's signal "balancesChanged" is triggered,
  6187. // it will call accountswindow's "onBalancesChangedFromAbove" function.
  6188. //
  6189. // connect(market_window, SIGNAL(needToDownloadAccountData()),
  6190. // this, SLOT(onNeedToDownloadAccountData()));
  6191. // connect(market_window, SIGNAL(needToDownloadSingleAcct(QString, QString)),
  6192. // this, SLOT(onNeedToDownloadSingleAcct(QString, QString)));
  6193. // connect(market_window, SIGNAL(needToDisplayTradeArchive()),
  6194. // this, SLOT(mc_trade_archive_slot()));
  6195. // connect(this, SIGNAL(balancesChanged()),
  6196. // market_window, SLOT(onBalancesChangedFromAbove()));
  6197. }
  6198. // ------------------------------------
  6199. market_window->dialog();
  6200. }
  6201. void Moneychanger::mc_trade_archive_slot()
  6202. {
  6203. mc_trade_archive_dialog();
  6204. }
  6205. void Moneychanger::mc_trade_archive_dialog()
  6206. {
  6207. if (!trade_archive_window)
  6208. {
  6209. trade_archive_window = new DlgTradeArchive(this);
  6210. // connect(this, SIGNAL(balancesChanged()),
  6211. // trade_archive_window, SLOT(onBalancesChangedFromAbove()));
  6212. }
  6213. // ------------------------------------
  6214. trade_archive_window->dialog();
  6215. }
  6216. // LOG: The Error Log dialog.
  6217. void Moneychanger::mc_log_slot()
  6218. {
  6219. mc_log_dialog();
  6220. }
  6221. // Same, except choose a specific one when opening.
  6222. void Moneychanger::mc_showlog_slot(QString text)
  6223. {
  6224. mc_log_dialog(text);
  6225. }
  6226. void Moneychanger::mc_log_dialog(QString qstrAppend/*=QString("")*/)
  6227. {
  6228. if (!log_window)
  6229. log_window = new DlgLog(this);
  6230. // -------------------------------------
  6231. if (!qstrAppend.isEmpty())
  6232. log_window->appendToLog(qstrAppend);
  6233. // -------------------------------------
  6234. // log_window->setWindowTitle(tr("Error Log"));
  6235. // -------------------------------------
  6236. log_window->dialog();
  6237. }
  6238. // CORPORATIONS
  6239. void Moneychanger::mc_corporation_slot()
  6240. {
  6241. mc_corporation_dialog();
  6242. }
  6243. void Moneychanger::mc_corporation_dialog()
  6244. {
  6245. // -------------------------------------
  6246. if (!corporation_window)
  6247. corporation_window = new MTDetailEdit(this);
  6248. // -------------------------------------
  6249. mapIDName & the_map = corporation_window->m_map;
  6250. // -------------------------------------
  6251. the_map.clear();
  6252. // TODO: populate the map here.
  6253. // -------------------------------------
  6254. corporation_window->setWindowTitle(tr("Corporations"));
  6255. // -------------------------------------
  6256. corporation_window->dialog(MTDetailEdit::DetailEditTypeCorporation);
  6257. }
  6258. // TRANSPORT: Various messaging system connection info
  6259. void Moneychanger::mc_transport_slot()
  6260. {
  6261. mc_transport_dialog();
  6262. }
  6263. // Same, except choose a specific one when opening.
  6264. void Moneychanger::mc_showtransport_slot(QString text)
  6265. {
  6266. mc_transport_dialog(text);
  6267. }
  6268. void Moneychanger::mc_transport_dialog(QString qstrPresetID/*=QString("")*/)
  6269. {
  6270. if (!transport_window)
  6271. transport_window = new MTDetailEdit(this);
  6272. // -------------------------------------
  6273. transport_window->m_map.clear();
  6274. // -------------------------------------
  6275. MTContactHandler::getInstance()->GetMsgMethods(transport_window->m_map);
  6276. // -------------------------------------
  6277. if (!qstrPresetID.isEmpty())
  6278. transport_window->SetPreSelected(qstrPresetID);
  6279. // -------------------------------------
  6280. transport_window->setWindowTitle(tr("Transport Methods"));
  6281. // -------------------------------------
  6282. transport_window->dialog(MTDetailEdit::DetailEditTypeTransport);
  6283. }
  6284. /**
  6285. * Create insurance company wizard
  6286. **/
  6287. void Moneychanger::mc_createinsurancecompany_slot()
  6288. {
  6289. //The operator has requested to open the create insurance company wizard;
  6290. mc_createinsurancecompany_dialog();
  6291. }
  6292. void Moneychanger::mc_createinsurancecompany_dialog()
  6293. {
  6294. if(!createinsurancecompany_window)
  6295. createinsurancecompany_window = new CreateInsuranceCompany(this);
  6296. // ------------------------------------
  6297. Focuser f(createinsurancecompany_window);
  6298. f.show();
  6299. f.focus();
  6300. }
  6301. void Moneychanger::onConfirmSmartContract(QString qstrTemplate, QString qstrLawyerID, int32_t index)
  6302. {
  6303. if (qstrTemplate.isEmpty())
  6304. {
  6305. qDebug() << "onConfirmSmartContract: Strange, the smart contract was empty. (Failure.)";
  6306. return;
  6307. }
  6308. std::string str_template = qstrTemplate.toStdString();
  6309. // ------------------------------------------------
  6310. if (qstrLawyerID.isEmpty())
  6311. qstrLawyerID = get_default_nym_id();
  6312. // ------------------------------------------------
  6313. if (0 == ot_.Exec().Smart_GetPartyCount(str_template))
  6314. {
  6315. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("There are no parties listed on this smart contract, so you cannot sign it as a party."));
  6316. return;
  6317. }
  6318. // ------------------------------------------------
  6319. if (ot_.Exec().Smart_AreAllPartiesConfirmed(str_template))
  6320. {
  6321. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, all parties are already confirmed on this contract. (Failure.)"));
  6322. return;
  6323. }
  6324. // ------------------------------------------------
  6325. std::string str_server = ot_.Exec().Instrmnt_GetNotaryID(str_template);
  6326. // ------------------------------------------------
  6327. WizardConfirmSmartContract theWizard(this);
  6328. theWizard.setWindowTitle(tr("Confirm smart contract"));
  6329. QString qstrNotaryID("");
  6330. if (!str_server.empty())
  6331. {
  6332. qstrNotaryID = QString::fromStdString(str_server);
  6333. }
  6334. else
  6335. {
  6336. qDebug() << "onConfirmSmartContract: Failed trying to get NotaryID from smart contract. (Failure.)";
  6337. return;
  6338. }
  6339. // ------------------------------------------------
  6340. if (!qstrLawyerID.isEmpty())
  6341. theWizard.setField(QString("NymID"), qstrLawyerID);
  6342. theWizard.setField(QString("SmartTemplate"), qstrTemplate);
  6343. // ------------------------------------------------
  6344. theWizard.setField(QString("NymPrompt"), QString(tr("Choose a Nym to be a party to, and a signer of, the smart contract:")));
  6345. // ------------------------------------------------
  6346. if (QDialog::Accepted != theWizard.exec())
  6347. return;
  6348. // ------------------------------------------------
  6349. qstrLawyerID = theWizard.field("NymID") .toString();
  6350. std::string str_lawyer_id = qstrLawyerID.toStdString();
  6351. // QString qstrNotaryID = theWizard.field("NotaryID").toString();
  6352. // str_server = qstrNotaryID.toStdString();
  6353. // -----------------------------------------
  6354. QString qstrPartyName = theWizard.field("PartyName") .toString();
  6355. std::string str_party = qstrPartyName.toStdString();
  6356. // ---------------------------------------------------
  6357. // By this point the user has selected the server ID, the Nym ID, and the Party Name.
  6358. //
  6359. std::string serverFromContract = ot_.Exec().Instrmnt_GetNotaryID(str_template);
  6360. if ("" != serverFromContract && str_server != serverFromContract) {
  6361. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Mismatched server ID in contract. (Failure.)"));
  6362. return;
  6363. }
  6364. // ----------------------------------------------------
  6365. if (!ot_.Exec().IsNym_RegisteredAtServer(str_lawyer_id, str_server)) {
  6366. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Nym is not registered on server. (Failure.)"));
  6367. return;
  6368. }
  6369. // ----------------------------------------------------
  6370. // See if there are accounts for that party via Party_GetAcctCount.
  6371. // If there are, confirm those accounts.
  6372. //
  6373. int32_t nAccountCount = ot_.Exec().Party_GetAcctCount(str_template, str_party);
  6374. if (0 >= nAccountCount)
  6375. {
  6376. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, the chosen party has no accounts named on this smart contract. (Failed.)"));
  6377. return;
  6378. }
  6379. // ----------------------------------------------------
  6380. // Need to LOOP here until all the accounts are confirmed.
  6381. mapIDName mapConfirmed, mapAgents;
  6382. while (nAccountCount > 0)
  6383. {
  6384. WizardPartyAcct otherWizard(this);
  6385. otherWizard.setWindowTitle(tr("Confirm smart contract"));
  6386. otherWizard.setField("PartyName", qstrPartyName);
  6387. otherWizard.setField("SmartTemplate", qstrTemplate);
  6388. std::string str_shown_state;
  6389. if (showPartyAccounts(str_template, str_party, str_shown_state) && !str_shown_state.empty())
  6390. otherWizard.setField("AccountState", QString::fromStdString(str_shown_state));
  6391. otherWizard.m_qstrNotaryID = qstrNotaryID;
  6392. otherWizard.m_qstrNymID = qstrLawyerID;
  6393. otherWizard.m_mapConfirmed = mapConfirmed;
  6394. // ------------------------------------------------
  6395. if (QDialog::Accepted != otherWizard.exec())
  6396. return;
  6397. mapConfirmed = otherWizard.m_mapConfirmed;
  6398. // ------------------------------------------------
  6399. QString qstrAcctName = otherWizard.field("AcctName").toString();
  6400. std::string str_acct_name = qstrAcctName.toStdString();
  6401. QString qstrAcctID = otherWizard.field("AcctID").toString();
  6402. std::string str_acct_id = qstrAcctID.toStdString();
  6403. // -----------------------------------------
  6404. std::string agentName = ot_.Exec().Party_GetAcctAgentName(str_template, str_party, str_acct_name);
  6405. if ("" == agentName)
  6406. agentName = ot_.Exec().Party_GetAgentNameByIndex(str_template, str_party, 0);
  6407. if ("" == agentName)
  6408. {
  6409. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, but apparently this smart contract doesn't have any agents for this party. (Failed.)"));
  6410. return;
  6411. }
  6412. mapConfirmed.insert(qstrAcctName, qstrAcctID);
  6413. mapAgents.insert(qstrAcctName, QString::fromStdString(agentName));
  6414. --nAccountCount;
  6415. }
  6416. // --------------------------------------------
  6417. // By this point, mapConfirmed and mapAgents are populated for all the relevant accounts.
  6418. //
  6419. // Let's make sure we have enough transaction numbers for all those accounts.
  6420. //
  6421. int32_t needed = 0;
  6422. for (auto x = mapConfirmed.begin(); x != mapConfirmed.end(); x++)
  6423. {
  6424. QString qstrAgent = mapAgents[x.key()];
  6425. needed += ot_.Exec().SmartContract_CountNumsNeeded(str_template, qstrAgent.toStdString());
  6426. }
  6427. // --------------------------------------------
  6428. const auto notaryID = opentxs::Identifier::Factory(str_server),
  6429. nymID = opentxs::Identifier::Factory(str_lawyer_id);
  6430. if (!ot_.ServerAction().GetTransactionNumbers(nymID, notaryID, needed + 1))
  6431. {
  6432. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed trying to reserve enough transaction numbers from the notary."));
  6433. return;
  6434. }
  6435. // --------------------------------------------
  6436. // CONFIRM THE ACCOUNTS HERE
  6437. //
  6438. // Note: Any failure below this point needs to harvest back ALL
  6439. // transaction numbers. Because we haven't even TRIED to activate it,
  6440. // therefore ALL numbers on the contract are still good (even the opening
  6441. // number.)
  6442. //
  6443. // Whereas after a failed activation, we'd need to harvest only the closing
  6444. // numbers, and not the opening numbers. But in here, this is confirmation,
  6445. // not activation.
  6446. //
  6447. std::string myAcctID = "";
  6448. std::string myAcctAgentName = "";
  6449. QString qstr_default_acct_id = get_default_account_id();
  6450. for (auto x = mapConfirmed.begin(); x != mapConfirmed.end(); x++)
  6451. {
  6452. // Here we check to see if default account ID exists -- if so we compare it to the
  6453. // current acctID in the loop and if they match, we set myAcctID. Later on,
  6454. // if/when activating, we can just use myAcctID to activate.
  6455. // (Otherwise we will have to pick one from the confirmed accounts.)
  6456. if ("" == myAcctID && (0 == qstr_default_acct_id.compare(x.value())))
  6457. {
  6458. myAcctID = qstr_default_acct_id.toStdString();
  6459. QString qstrMyAcctAgentName = mapAgents[x.key()];
  6460. myAcctAgentName = qstrMyAcctAgentName.toStdString();
  6461. }
  6462. QString qstrCurrentAcctName = x.key();
  6463. QString qstrCurrentAcctID = x.value();
  6464. QString qstrCurrentAgentname = mapAgents[x.key()];
  6465. // confirm a theoretical acct by giving it a real acct id.
  6466. std::string confirmed = ot_.Exec().SmartContract_ConfirmAccount(
  6467. str_template, str_lawyer_id, str_party, qstrCurrentAcctName.toStdString(), qstrCurrentAgentname.toStdString(), qstrCurrentAcctID.toStdString());
  6468. if ("" == confirmed)
  6469. {
  6470. qDebug() << "Failure while calling "
  6471. "OT_API_SmartContract_ConfirmAccount. Acct Name: "
  6472. << qstrCurrentAcctName << " Agent Name: " << qstrCurrentAgentname
  6473. << " Acct ID: " << qstrCurrentAcctID << " \n";
  6474. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed while calling OT_API_SmartContract_ConfirmAccount."));
  6475. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6476. return;
  6477. }
  6478. str_template = confirmed;
  6479. }
  6480. // ----------------------------------------
  6481. // Then we try to activate it or pass on to the next party.
  6482. std::string confirmed =
  6483. ot_.Exec().SmartContract_ConfirmParty(str_template, str_party, str_lawyer_id, str_server);
  6484. if ("" == confirmed)
  6485. {
  6486. qDebug() << "Error: cannot confirm smart contract party.\n";
  6487. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed while calling SmartContract_ConfirmParty."));
  6488. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6489. return;
  6490. }
  6491. if (ot_.Exec().Smart_AreAllPartiesConfirmed(confirmed))
  6492. {
  6493. // If you are the last party to sign, then ACTIVATE THE SMART CONTRACT.
  6494. activateContract(str_server, str_lawyer_id, confirmed, str_party, myAcctID, myAcctAgentName);
  6495. return;
  6496. }
  6497. // -------------------------------
  6498. // Below this point, we know there are still parties waiting to confirm the contract before
  6499. // it can be activated.
  6500. // So we pop up a list of Contacts to send the contract on to next.
  6501. // -----------------------------------------------
  6502. DlgChooser theChooser(this);
  6503. // -----------------------------------------------
  6504. mapIDName & the_map = theChooser.m_map;
  6505. MTContactHandler::getInstance()->GetContacts(the_map);
  6506. theChooser.setWindowTitle(tr("Choose the next signer"));
  6507. // -----------------------------------------------
  6508. if (theChooser.exec() != QDialog::Accepted)
  6509. {
  6510. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6511. return;
  6512. }
  6513. // -----------------------------------------------
  6514. QString qstrContactName = theChooser.m_qstrCurrentName;
  6515. int nSelectedContactID = theChooser.m_qstrCurrentID.toInt();
  6516. // -----------------------------------------------
  6517. DlgChooser theNymChooser(this);
  6518. mapIDName & the_nym_map = theNymChooser.m_map;
  6519. MTContactHandler::getInstance()->GetNyms(the_nym_map, nSelectedContactID);
  6520. theNymChooser.setWindowTitle(tr("Choose one of his nyms"));
  6521. // -----------------------------------------------
  6522. if (theNymChooser.exec() != QDialog::Accepted)
  6523. {
  6524. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6525. return;
  6526. }
  6527. // -----------------------------------------------
  6528. QString qstrNymID = theNymChooser.m_qstrCurrentID;
  6529. QString qstrNymName = theNymChooser.m_qstrCurrentName;
  6530. // -----------------------------------------------
  6531. // NOTE: No matter which party you are (perhaps you are the middle one),
  6532. // when you confirm the contract, you will send it on to the NEXT
  6533. // UNCONFIRMED ONE. This means you don't know which party it will be,
  6534. // since all the unconfirmed parties have no NymID (yet.) Rather, it's
  6535. // YOUR problem to provide the NymID you're sending the contract on to.
  6536. // And then it's HIS problem to decide which party he will sign on as.
  6537. // (Unless you are the LAST PARTY to confirm, in which case YOU are the
  6538. // activator.)
  6539. //
  6540. sendToNextParty(str_server, str_lawyer_id, qstrNymID.toStdString(), confirmed);
  6541. if (-1 != index)
  6542. {
  6543. // not a pasted contract, but it's an index in the payments inbox.
  6544. //
  6545. ot_.Exec().RecordPayment(str_server, str_lawyer_id, true, index, false);
  6546. }
  6547. }
  6548. void Moneychanger::onRunSmartContract(QString qstrTemplate, QString qstrLawyerID, int32_t index)
  6549. {
  6550. if (qstrTemplate.isEmpty())
  6551. return;
  6552. std::string str_template = qstrTemplate.toStdString();
  6553. // ------------------------------------------------
  6554. if (qstrLawyerID.isEmpty())
  6555. qstrLawyerID = get_default_nym_id();
  6556. // ------------------------------------------------
  6557. if (0 == ot_.Exec().Smart_GetPartyCount(str_template))
  6558. {
  6559. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("There are no parties listed on this smart contract, so you cannot sign it as a party."));
  6560. return;
  6561. }
  6562. // ------------------------------------------------
  6563. if (ot_.Exec().Smart_AreAllPartiesConfirmed(str_template))
  6564. {
  6565. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, all parties are already confirmed on this contract. (Failure.)"));
  6566. return;
  6567. }
  6568. // ------------------------------------------------
  6569. std::string str_server = ot_.Exec().Instrmnt_GetNotaryID(str_template);
  6570. // ------------------------------------------------
  6571. WizardRunSmartContract theWizard(this);
  6572. theWizard.setWindowTitle(tr("Run smart contract"));
  6573. if (!str_server.empty())
  6574. theWizard.setField(QString("NotaryID"), QString::fromStdString(str_server));
  6575. // ------------------------------------------------
  6576. if (!qstrLawyerID.isEmpty())
  6577. theWizard.setField(QString("NymID"), qstrLawyerID);
  6578. theWizard.setField(QString("SmartTemplate"), qstrTemplate);
  6579. // ------------------------------------------------
  6580. theWizard.setField(QString("NymPrompt"), QString(tr("Choose a Nym to be a party to, and a signer of, the smart contract:")));
  6581. // ------------------------------------------------
  6582. if (QDialog::Accepted != theWizard.exec())
  6583. return;
  6584. // ------------------------------------------------
  6585. qstrLawyerID = theWizard.field("NymID") .toString();
  6586. std::string str_lawyer_id = qstrLawyerID.toStdString();
  6587. QString qstrNotaryID = theWizard.field("NotaryID").toString();
  6588. str_server = qstrNotaryID.toStdString();
  6589. // -----------------------------------------
  6590. QString qstrPartyName = theWizard.field("PartyName") .toString();
  6591. std::string str_party = qstrPartyName.toStdString();
  6592. // ---------------------------------------------------
  6593. // By this point the user has selected the server ID, the Nym ID, and the Party Name.
  6594. //
  6595. std::string serverFromContract = ot_.Exec().Instrmnt_GetNotaryID(str_template);
  6596. if ("" != serverFromContract && str_server != serverFromContract) {
  6597. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Mismatched server ID in contract. (Failure.)"));
  6598. return;
  6599. }
  6600. // ----------------------------------------------------
  6601. if (!ot_.Exec().IsNym_RegisteredAtServer(str_lawyer_id, str_server)) {
  6602. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Nym is not registered on server. (Failure.)"));
  6603. return;
  6604. }
  6605. // ----------------------------------------------------
  6606. // See if there are accounts for that party via Party_GetAcctCount.
  6607. // If there are, confirm those accounts.
  6608. //
  6609. int32_t nAccountCount = ot_.Exec().Party_GetAcctCount(str_template, str_party);
  6610. if (0 >= nAccountCount)
  6611. {
  6612. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, the chosen party has no accounts named on this smart contract. (Failed.)"));
  6613. return;
  6614. }
  6615. // ----------------------------------------------------
  6616. // Need to LOOP here until all the accounts are confirmed.
  6617. mapIDName mapConfirmed, mapAgents;
  6618. while (nAccountCount > 0)
  6619. {
  6620. WizardPartyAcct otherWizard(this);
  6621. otherWizard.setWindowTitle(tr("Run smart contract"));
  6622. otherWizard.setField("PartyName", qstrPartyName);
  6623. otherWizard.setField("SmartTemplate", qstrTemplate);
  6624. std::string str_shown_state;
  6625. if (showPartyAccounts(str_template, str_party, str_shown_state) && !str_shown_state.empty())
  6626. otherWizard.setField("AccountState", QString::fromStdString(str_shown_state));
  6627. otherWizard.m_qstrNotaryID = qstrNotaryID;
  6628. otherWizard.m_qstrNymID = qstrLawyerID;
  6629. otherWizard.m_mapConfirmed = mapConfirmed;
  6630. // ------------------------------------------------
  6631. if (QDialog::Accepted != otherWizard.exec())
  6632. return;
  6633. mapConfirmed = otherWizard.m_mapConfirmed;
  6634. // ------------------------------------------------
  6635. QString qstrAcctName = otherWizard.field("AcctName").toString();
  6636. std::string str_acct_name = qstrAcctName.toStdString();
  6637. QString qstrAcctID = otherWizard.field("AcctID").toString();
  6638. std::string str_acct_id = qstrAcctID.toStdString();
  6639. // -----------------------------------------
  6640. std::string agentName = ot_.Exec().Party_GetAcctAgentName(str_template, str_party, str_acct_name);
  6641. if ("" == agentName)
  6642. agentName = ot_.Exec().Party_GetAgentNameByIndex(str_template, str_party, 0);
  6643. if ("" == agentName)
  6644. {
  6645. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Strange, but apparently this smart contract doesn't have any agents for this party. (Failed.)"));
  6646. return;
  6647. }
  6648. mapConfirmed.insert(qstrAcctName, qstrAcctID);
  6649. mapAgents.insert(qstrAcctName, QString::fromStdString(agentName));
  6650. --nAccountCount;
  6651. }
  6652. // --------------------------------------------
  6653. // By this point, mapConfirmed and mapAgents are populated for all the relevant accounts.
  6654. //
  6655. // Let's make sure we have enough transaction numbers for all those accounts.
  6656. //
  6657. int32_t needed = 0;
  6658. for (auto x = mapConfirmed.begin(); x != mapConfirmed.end(); x++)
  6659. {
  6660. QString qstrAgent = mapAgents[x.key()];
  6661. needed += ot_.Exec().SmartContract_CountNumsNeeded(str_template, qstrAgent.toStdString());
  6662. }
  6663. // --------------------------------------------
  6664. const auto notaryID = opentxs::Identifier::Factory(str_server),
  6665. nymID = opentxs::Identifier::Factory(str_lawyer_id);
  6666. if (!ot_.ServerAction().GetTransactionNumbers(nymID, notaryID, needed + 1))
  6667. {
  6668. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed trying to reserve enough transaction numbers from the notary."));
  6669. return;
  6670. }
  6671. // --------------------------------------------
  6672. // CONFIRM THE ACCOUNTS HERE
  6673. //
  6674. // Note: Any failure below this point needs to harvest back ALL
  6675. // transaction numbers. Because we haven't even TRIED to activate it,
  6676. // therefore ALL numbers on the contract are still good (even the opening
  6677. // number.)
  6678. //
  6679. // Whereas after a failed activation, we'd need to harvest only the closing
  6680. // numbers, and not the opening numbers. But in here, this is confirmation,
  6681. // not activation.
  6682. //
  6683. std::string myAcctID = "";
  6684. std::string myAcctAgentName = "";
  6685. QString qstr_default_acct_id = get_default_account_id();
  6686. for (auto x = mapConfirmed.begin(); x != mapConfirmed.end(); x++)
  6687. {
  6688. // Here we check to see if default account ID exists -- if so we compare it to the
  6689. // current acctID in the loop and if they match, we set myAcctID. Later on,
  6690. // if/when activating, we can just use myAcctID to activate.
  6691. // (Otherwise we will have to pick one from the confirmed accounts.)
  6692. if ("" == myAcctID && (0 == qstr_default_acct_id.compare(x.value())))
  6693. {
  6694. myAcctID = qstr_default_acct_id.toStdString();
  6695. QString qstrMyAcctAgentName = mapAgents[x.key()];
  6696. myAcctAgentName = qstrMyAcctAgentName.toStdString();
  6697. }
  6698. QString qstrCurrentAcctName = x.key();
  6699. QString qstrCurrentAcctID = x.value();
  6700. QString qstrCurrentAgentname = mapAgents[x.key()];
  6701. // confirm a theoretical acct by giving it a real acct id.
  6702. std::string confirmed = ot_.Exec().SmartContract_ConfirmAccount(
  6703. str_template, str_lawyer_id, str_party, qstrCurrentAcctName.toStdString(), qstrCurrentAgentname.toStdString(), qstrCurrentAcctID.toStdString());
  6704. if ("" == confirmed)
  6705. {
  6706. qDebug() << "Failure while calling "
  6707. "OT_API_SmartContract_ConfirmAccount. Acct Name: "
  6708. << qstrCurrentAcctName << " Agent Name: " << qstrCurrentAgentname
  6709. << " Acct ID: " << qstrCurrentAcctID << " \n";
  6710. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed while calling OT_API_SmartContract_ConfirmAccount."));
  6711. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6712. return;
  6713. }
  6714. str_template = confirmed;
  6715. }
  6716. // ----------------------------------------
  6717. // Then we try to activate it or pass on to the next party.
  6718. std::string confirmed =
  6719. ot_.Exec().SmartContract_ConfirmParty(str_template, str_party, str_lawyer_id, str_server);
  6720. if ("" == confirmed)
  6721. {
  6722. qDebug() << "Error: cannot confirm smart contract party.\n";
  6723. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed while calling SmartContract_ConfirmParty."));
  6724. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6725. return;
  6726. }
  6727. if (ot_.Exec().Smart_AreAllPartiesConfirmed(confirmed))
  6728. {
  6729. // If you are the last party to sign, then ACTIVATE THE SMART CONTRACT.
  6730. activateContract(str_server, str_lawyer_id, confirmed, str_party, myAcctID, myAcctAgentName);
  6731. return;
  6732. }
  6733. // -------------------------------
  6734. // Below this point, we know there are still parties waiting to confirm the contract before
  6735. // it can be activated.
  6736. // So we pop up a list of Contacts to send the contract on to next.
  6737. // -----------------------------------------------
  6738. DlgChooser theChooser(this);
  6739. // -----------------------------------------------
  6740. mapIDName & the_map = theChooser.m_map;
  6741. MTContactHandler::getInstance()->GetContacts(the_map);
  6742. theChooser.setWindowTitle(tr("Choose the next signer"));
  6743. // -----------------------------------------------
  6744. if (theChooser.exec() != QDialog::Accepted)
  6745. {
  6746. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6747. return;
  6748. }
  6749. // -----------------------------------------------
  6750. QString qstrContactName = theChooser.m_qstrCurrentName;
  6751. int nSelectedContactID = theChooser.m_qstrCurrentID.toInt();
  6752. // -----------------------------------------------
  6753. DlgChooser theNymChooser(this);
  6754. mapIDName & the_nym_map = theNymChooser.m_map;
  6755. MTContactHandler::getInstance()->GetNyms(the_nym_map, nSelectedContactID);
  6756. theNymChooser.setWindowTitle(tr("Choose one of his nyms"));
  6757. // -----------------------------------------------
  6758. if (theNymChooser.exec() != QDialog::Accepted)
  6759. {
  6760. ot_.Exec().Msg_HarvestTransactionNumbers(str_template, str_lawyer_id, false, false, false, false, false);
  6761. return;
  6762. }
  6763. // -----------------------------------------------
  6764. QString qstrNymID = theNymChooser.m_qstrCurrentID;
  6765. QString qstrNymName = theNymChooser.m_qstrCurrentName;
  6766. // -----------------------------------------------
  6767. // NOTE: No matter which party you are (perhaps you are the middle one),
  6768. // when you confirm the contract, you will send it on to the NEXT
  6769. // UNCONFIRMED ONE. This means you don't know which party it will be,
  6770. // since all the unconfirmed parties have no NymID (yet.) Rather, it's
  6771. // YOUR problem to provide the NymID you're sending the contract on to.
  6772. // And then it's HIS problem to decide which party he will sign on as.
  6773. // (Unless you are the LAST PARTY to confirm, in which case YOU are the
  6774. // activator.)
  6775. //
  6776. sendToNextParty(str_server, str_lawyer_id, qstrNymID.toStdString(), confirmed);
  6777. if (-1 != index)
  6778. {
  6779. // not a pasted contract, but it's an index in the payments inbox.
  6780. //
  6781. ot_.Exec().RecordPayment(str_server, str_lawyer_id, true, index, false);
  6782. }
  6783. }
  6784. int32_t Moneychanger::activateContract(const std::string& server, const std::string& mynym,
  6785. const std::string& contract, const std::string& name,
  6786. std::string myAcctID,
  6787. std::string myAcctAgentName)
  6788. {
  6789. // We don't need MyAcct except when actually ACTIVATING the smart contract
  6790. // on the server. This variable might get set later to MyAcct, if it matches
  6791. // one of the accounts being confirmed. (Meaning if this variable is set by
  6792. // the time we reach the bottom, then we can use it for activation, if/when
  6793. // needed.)
  6794. // We need the ACCT_ID that we're using to activate it with, and we need the
  6795. // AGENT NAME for that account.
  6796. if ("" == myAcctID || "" == myAcctAgentName)
  6797. {
  6798. DlgChooser theChooser(this);
  6799. // -----------------------------------------------
  6800. mapIDName & the_map = theChooser.m_map;
  6801. // -----------------------------------------------
  6802. int32_t acct_count = ot_.Exec().Party_GetAcctCount(contract, name);
  6803. for (int32_t i = 0; i < acct_count; i++)
  6804. {
  6805. std::string acctName = ot_.Exec().Party_GetAcctNameByIndex(contract, name, i);
  6806. QString qstrAcctName = QString::fromStdString(acctName);
  6807. // -----------------------------------------------
  6808. std::string partyAcctID = ot_.Exec().Party_GetAcctID(contract, name, acctName);
  6809. QString qstrPartyAcctID = QString::fromStdString(partyAcctID);
  6810. // -----------------------------------------------
  6811. QString OT_id = qstrPartyAcctID;
  6812. QString OT_name = qstrAcctName;
  6813. // -----------------------------------------------
  6814. if (!OT_id.isEmpty())
  6815. the_map.insert(OT_id, OT_name);
  6816. }
  6817. // -----------------------------------------------
  6818. theChooser.setWindowTitle(tr("Choose the activation account"));
  6819. // -----------------------------------------------
  6820. if (theChooser.exec() != QDialog::Accepted || theChooser.m_qstrCurrentID.isEmpty())
  6821. {
  6822. return ot_.Exec().Msg_HarvestTransactionNumbers(contract, mynym, false, false, false, false, false);
  6823. }
  6824. // ------------------------------------------------
  6825. std::string acctName = theChooser.m_qstrCurrentName.toStdString();
  6826. if ("" == acctName) {
  6827. qDebug() << "Error: account name empty on smart contract.\n";
  6828. return ot_.Exec().Msg_HarvestTransactionNumbers(contract, mynym, false, false, false, false, false);
  6829. }
  6830. myAcctID = theChooser.m_qstrCurrentID.toStdString();
  6831. myAcctAgentName = ot_.Exec().Party_GetAcctAgentName(contract, name, acctName);
  6832. if ("" == myAcctAgentName) {
  6833. qDebug() << "Error: account agent is not yet confirmed.\n";
  6834. return ot_.Exec().Msg_HarvestTransactionNumbers(contract, mynym, false, false, false, false, false);
  6835. }
  6836. }
  6837. const auto notaryID = opentxs::Identifier::Factory(server),
  6838. myNymID = opentxs::Identifier::Factory(mynym),
  6839. accountID = opentxs::Identifier::Factory(myAcctID);
  6840. auto smartContract{ot_.Factory().SmartContract()};
  6841. OT_ASSERT(false != bool(smartContract));
  6842. smartContract->LoadContractFromString(opentxs::String::Factory(contract));
  6843. auto action = ot_.ServerAction().ActivateSmartContract(myNymID, notaryID, accountID, myAcctAgentName, smartContract);
  6844. std::string response = action->Run();
  6845. if (1 != opentxs::VerifyMessageSuccess(ot_, response))
  6846. {
  6847. qDebug() << "Error: cannot activate smart contract.\n";
  6848. return ot_.Exec().Msg_HarvestTransactionNumbers(contract, mynym, false, false, false, false, false);
  6849. }
  6850. // BELOW THIS POINT, the transaction has definitely processed.
  6851. int32_t reply = opentxs::InterpretTransactionMsgReply(ot_, server, mynym, myAcctID, "activate_smart_contract", response);
  6852. if (1 != reply) {
  6853. return reply;
  6854. }
  6855. if (!ot_.ServerAction().DownloadAccount(myNymID, notaryID, accountID, true)) {
  6856. qDebug() << "Error retrieving intermediary files for account.\n";
  6857. }
  6858. return 1;
  6859. }
  6860. int32_t Moneychanger::sendToNextParty(const std::string& server, const std::string& mynym,
  6861. const std::string& hisnym,
  6862. const std::string& contract)
  6863. {
  6864. // But if all the parties are NOT confirmed, then we need to send it to
  6865. // the next guy. In that case:
  6866. // If HisNym is provided, and it's different than mynym, then use it.
  6867. // He's the next receipient.
  6868. // If HisNym is NOT provided, then display the list of NymIDs, and allow
  6869. // the user to paste one. We can probably select him based on abbreviated
  6870. // ID or Name as well (I think there's an API call for that...)
  6871. std::string hisNymID = hisnym;
  6872. std::shared_ptr<const opentxs::OTPayment> payment{ot_.Factory().Payment(opentxs::String::Factory(contract.c_str())).release()};
  6873. OT_ASSERT(false != bool(payment));
  6874. auto action = ot_.ServerAction().SendPayment(opentxs::Identifier::Factory(mynym), opentxs::Identifier::Factory(server), opentxs::Identifier::Factory(hisNymID), payment);
  6875. std::string response = action->Run();
  6876. if (1 != opentxs::VerifyMessageSuccess(ot_, response)) {
  6877. qDebug() << "\nFor whatever reason, our attempt to send the instrument on "
  6878. "to the next user has failed.\n";
  6879. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Failed while calling send_user_payment."));
  6880. return ot_.Exec().Msg_HarvestTransactionNumbers(contract, mynym, false, false, false, false, false);
  6881. }
  6882. // Success. (Remove the payment instrument we just successfully sent from
  6883. // our payments inbox.)
  6884. // In the case of smart contracts, it might be sent on to a chain of 2 or
  6885. // 3 users, before finally being activated by the last one in the chain.
  6886. // All of the users in the chain (except the first one) will thus have a
  6887. // copy of the smart contract in their payments inbox AND outbox.
  6888. //
  6889. // But once the smart contract has successfully been sent on to the next
  6890. // user, and thus a copy of it is in my outbox already, then there is
  6891. // definitely no reason for a copy of it to stay in my inbox as well.
  6892. // Might as well remove that copy.
  6893. //
  6894. // We can't really expect to remove the payments inbox copy inside OT
  6895. // itself, when we receive the server's SendNymInstrumentResponse reply
  6896. // message,
  6897. // without opening up the (encrypted) contents. (Although that would
  6898. // actually be ideal, since it would cover all cases included dropped
  6899. // messages...) But we CAN easily remove it RIGHT HERE.
  6900. // Perhaps in the future I WILL move this code to the
  6901. // SendNymInstrumentResponse
  6902. // reply processing, but that will require it to be encrypted to my own
  6903. // key as well as the recipient's, which we already do for sending cash,
  6904. // but which we up until now have not done for the other instruments.
  6905. // So perhaps we'll start doing that sometime in the future, and then move
  6906. // this code.
  6907. //
  6908. // In the meantime, this is good enough.
  6909. qDebug() << "Success sending the agreement on to the next party.\n";
  6910. QMessageBox::information(this, tr(MONEYCHANGER_APP_NAME), tr("Success sending the agreement on to the next party."));
  6911. return 1;
  6912. }
  6913. bool Moneychanger::showPartyAccounts(const std::string& contract, const std::string& name, std::string & str_output)
  6914. {
  6915. std::ostringstream os;
  6916. int32_t accounts = ot_.Exec().Party_GetAcctCount(contract, name);
  6917. if (0 > accounts) {
  6918. qDebug() << QString("Error: Party '%1' has bad value for number of asset accounts.").arg(QString::fromStdString(name));
  6919. return false;
  6920. }
  6921. for (int32_t i = 0; i < accounts; i++)
  6922. {
  6923. std::string acctName =
  6924. ot_.Exec().Party_GetAcctNameByIndex(contract, name, i);
  6925. if ("" == acctName) {
  6926. qDebug() << QString("Error: Failed retrieving Asset Account Name from party '%1' at account index: %2")
  6927. .arg(QString::fromStdString(name)).arg(i);
  6928. return false;
  6929. }
  6930. std::string acctInstrumentDefinitionID =
  6931. ot_.Exec().Party_GetAcctInstrumentDefinitionID(contract, name,
  6932. acctName);
  6933. if ("" != acctInstrumentDefinitionID) {
  6934. os << "-------------------\nAccount '" << acctName << "' (index "
  6935. << i << " on Party '" << name
  6936. << "') has instrument definition: "
  6937. << acctInstrumentDefinitionID << " ("
  6938. << ot_.Exec().GetAssetType_Name(acctInstrumentDefinitionID)
  6939. << ")\n";
  6940. }
  6941. std::string acctID = ot_.Exec().Party_GetAcctID(contract, name, acctName);
  6942. if ("" != acctID) {
  6943. os << "Account '" << acctName << "' (party '" << name
  6944. << "') is confirmed as Account ID: " << acctID << " ("
  6945. << ot_.Exec().GetAccountWallet_Name(acctID) << ")\n";
  6946. }
  6947. std::string strAcctAgentName =
  6948. ot_.Exec().Party_GetAcctAgentName(contract, name, acctName);
  6949. if ("" != strAcctAgentName) {
  6950. os << "Account '" << acctName << "' (party '" << name
  6951. << "') is managed by agent: " << strAcctAgentName << "\n";
  6952. }
  6953. }
  6954. str_output = os.str();
  6955. return true;
  6956. }
  6957. /**
  6958. * (Advantced ->) Settings Window
  6959. **/
  6960. void Moneychanger::mc_settings_slot()
  6961. {
  6962. // This is a glaring memory leak, but it's only a temporary placeholder before I redo how windows are handled.
  6963. if (!settingswindow)
  6964. settingswindow = new Settings(this);
  6965. // ------------------------------------
  6966. connect(settingswindow, SIGNAL(expertModeUpdated(bool)), this, SIGNAL(expertModeUpdated(bool)));
  6967. connect(settingswindow, SIGNAL(hideNavUpdated(bool)), this, SLOT(onHideNavUpdated(bool)));
  6968. // ------------------------------------
  6969. Focuser f(settingswindow);
  6970. f.show();
  6971. f.focus();
  6972. }
  6973. //static
  6974. QString Moneychanger::cashBalance(QString qstr_notary_id, QString qstr_asset_id, QString qstr_nym_id)
  6975. {
  6976. int64_t balance = 0;
  6977. QString return_value = QString("");
  6978. std::string str_output;
  6979. balance = Moneychanger::rawCashBalance(qstr_notary_id, qstr_asset_id, qstr_nym_id);
  6980. str_output = Moneychanger::It()->OT().Exec().FormatAmount(qstr_asset_id.toStdString(), balance);
  6981. if (!str_output.empty())
  6982. return_value = QString::fromStdString(str_output);
  6983. return return_value;
  6984. }
  6985. // ----------------------------------------------------------------------
  6986. //static
  6987. int64_t Moneychanger::rawCashBalance(QString qstr_notary_id, QString qstr_asset_id, QString qstr_nym_id)
  6988. {
  6989. int64_t balance = 0;
  6990. std::string NotaryID(qstr_notary_id.toStdString());
  6991. std::string InstrumentDefinitionID (qstr_asset_id.toStdString());
  6992. std::string nymId (qstr_nym_id.toStdString());
  6993. #if OT_CASH
  6994. std::string str_purse = Moneychanger::It()->OT().Exec().LoadPurse(NotaryID, InstrumentDefinitionID, nymId);
  6995. if (!str_purse.empty())
  6996. {
  6997. int64_t temp_balance = Moneychanger::It()->OT().Exec().Purse_GetTotalValue(NotaryID, InstrumentDefinitionID, str_purse);
  6998. if (temp_balance >= 0)
  6999. balance = temp_balance;
  7000. }
  7001. #endif // OT_CASH
  7002. return balance;
  7003. }
  7004. // ----------------------------------------------------------------------
  7005. //static
  7006. QString Moneychanger::shortAcctBalance(QString qstr_acct_id, QString qstr_asset_id/*=QString("")*/, bool bWithSymbol/*=true*/)
  7007. {
  7008. QString return_value("");
  7009. // -------------------------------------------
  7010. if (qstr_acct_id.isEmpty())
  7011. return return_value; // Might want to assert here... (returns blank string.)
  7012. // -------------------------------------------
  7013. std::string acctID = qstr_acct_id.toStdString();
  7014. int64_t balance = Moneychanger::It()->OT().Exec().GetAccountWallet_Balance(acctID);
  7015. std::string InstrumentDefinitionID;
  7016. // -------------------------------------------
  7017. if (!qstr_asset_id.isEmpty())
  7018. InstrumentDefinitionID = qstr_asset_id.toStdString();
  7019. else
  7020. InstrumentDefinitionID = Moneychanger::It()->OT().Exec().GetAccountWallet_InstrumentDefinitionID(acctID);
  7021. // -------------------------------------------
  7022. std::string str_output;
  7023. if (!InstrumentDefinitionID.empty())
  7024. {
  7025. str_output = bWithSymbol ?
  7026. Moneychanger::It()->OT().Exec().FormatAmount(InstrumentDefinitionID, balance) :
  7027. Moneychanger::It()->OT().Exec().FormatAmountWithoutSymbol(InstrumentDefinitionID, balance);
  7028. if (!str_output.empty())
  7029. return_value = QString::fromStdString(str_output);
  7030. else
  7031. {
  7032. std::string str_asset_name = Moneychanger::It()->OT().Exec().GetAssetType_Name(InstrumentDefinitionID);
  7033. return_value = QString("%1 %2").arg(balance).arg(QString::fromStdString(str_asset_name));
  7034. }
  7035. }
  7036. // -------------------------------------------
  7037. return return_value;
  7038. }
  7039. // ----------------------------------------------------------------------
  7040. //static
  7041. int64_t Moneychanger::rawAcctBalance(QString qstrAcctId)
  7042. {
  7043. int64_t ret = qstrAcctId.isEmpty() ? 0 : Moneychanger::It()->OT().Exec().GetAccountWallet_Balance(qstrAcctId.toStdString());
  7044. return ret;
  7045. }
  7046. //static
  7047. QString Moneychanger::FormDisplayLabelForAcctButton(QString qstr_acct_id, QString qstr_display_name)
  7048. {
  7049. QString display_name("");
  7050. QString button_text("");
  7051. // -----------------------------------------
  7052. if (qstr_display_name.isEmpty())
  7053. display_name = QString("");
  7054. else
  7055. display_name = qstr_display_name;
  7056. // -----------------------------------------
  7057. std::string str_acct_id = qstr_acct_id.toStdString();
  7058. std::string str_acct_nym = Moneychanger::It()->OT().Exec().GetAccountWallet_NymID (str_acct_id);
  7059. std::string str_acct_server = Moneychanger::It()->OT().Exec().GetAccountWallet_NotaryID (str_acct_id);
  7060. std::string str_acct_asset = Moneychanger::It()->OT().Exec().GetAccountWallet_InstrumentDefinitionID(str_acct_id);
  7061. // -----------------------------------------
  7062. QString qstr_acct_nym = QString::fromStdString(str_acct_nym);
  7063. QString qstr_acct_server = QString::fromStdString(str_acct_server);
  7064. QString qstr_acct_asset = QString::fromStdString(str_acct_asset);
  7065. // -----------------------------------
  7066. button_text = QString("%1 (%2").
  7067. arg(display_name).
  7068. arg(Moneychanger::shortAcctBalance(qstr_acct_id, qstr_acct_asset));
  7069. // --------------------------------------------
  7070. if (!qstr_acct_nym.isEmpty() && !qstr_acct_server.isEmpty() && !qstr_acct_asset.isEmpty())
  7071. {
  7072. int64_t raw_cash_balance = Moneychanger::rawCashBalance(qstr_acct_server, qstr_acct_asset, qstr_acct_nym);
  7073. if (raw_cash_balance > 0)
  7074. button_text += QString(" + %1 %2").arg(Moneychanger::cashBalance(qstr_acct_server, qstr_acct_asset, qstr_acct_nym)).arg(tr("in cash"));
  7075. }
  7076. // --------------------------------------------
  7077. button_text += QString( ")" );
  7078. // -----------------------------------------
  7079. return button_text;
  7080. }