Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
main.cpp
Go to the documentation of this file.
1 /*************************************************************
2  *
3  * main.cpp (Uses ZMQ for transport.)
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "opentxs/core/stdafx.hpp"
134 
135 #include "opentxs/client/OTAPI.hpp"
137 #include "opentxs/client/OT_ME.hpp"
142 
143 #include "opentxs/cash/Purse.hpp"
144 
148 #include "opentxs/core/OTLog.hpp"
154 
155 #include <anyoption/anyoption.hpp>
156 
157 #ifndef WIN32
158 #include <iterator>
159 #include <memory>
160 #endif
161 
162 #ifdef __APPLE__
163 #include "TargetConditionals.h"
164 #endif
165 
166 using namespace opentxs;
167 
168 #define OT_OPTIONS_FILE_DEFAULT "command-line-ot.opt"
169 #define CLIENT_PATH_DEFAULT "client_data" // should get programmatically
170 
171 #define CA_FILE "certs/special/ca.crt"
172 #define KEY_FILE "certs/special/client.pem"
173 
174 void HandleCommandLineArguments(int32_t argc, char* argv[], AnyOption* opt);
175 
176 /*
177 
178 --server (SERVER_ID)
179 
180 USAGE: ot -COMMAND [AMOUNT] [--from ACCT/NYM/ASSET] [--to ACCT or NYM]
181 
182 ot -w 100 (WITHDRAW 100 FROM DEFAULT ACCOUNT.)
183 ot -d 100 (DEPOSIT FROM DEFAULT PURSE TO DEFAULT ACCOUNT.)
184 ot -t 100 --to j43k (TRANSFER 100 FROM DEFAULT ACCT TO ACCT STARTING WITH j43k)
185 ot -t 100 --from qwer --to j43k (TRANSFER 100 from ACCT STARTING WITH qwer TO
186 ACCT starting j43k)
187 
188 */
189 
190 // If false, error happened, usually based on what user just attemped.
191 //
193  std::string& str_ServerID, std::string& str_MyNym, OTPseudonym*& pMyNym,
194  OTWallet*& pWallet, OTServerContract*& pServerContract)
195 {
196  // If we got down here, that means there were no commands on the command
197  // line
198  // (That's why we dropped into the OT prompt.)
199  // However, there still may have been OPTIONS -- and if so, we'll go ahead
200  // and
201  // load the wallet. (If there were NOT ANY OPTIONS, then we do NOT load the
202  // wallet,
203  // although there is a COMMAND for doing that.)
204  //
205 
207 
208  //
209  pWallet = OTAPI_Wrap::OTAPI()->GetWallet();
210 
211  if (nullptr == pWallet) {
212  otOut
213  << "The wallet object is still nullptr, somehow. Please load it.\n";
214  return false;
215  }
216 
217  // Below this point, pWallet is available :-)
218 
219  if (str_ServerID.size() > 0) {
220  const OTIdentifier SERVER_ID(str_ServerID.c_str());
221 
222  pServerContract = pWallet->GetServerContract(SERVER_ID);
223  // If failure, then we try PARTIAL match.
224  if (nullptr == pServerContract)
225  pServerContract =
226  pWallet->GetServerContractPartialMatch(str_ServerID);
227 
228  if (nullptr != pServerContract) {
229  OTString strTemp;
230  pServerContract->GetIdentifier(strTemp);
231 
232  str_ServerID = strTemp.Get();
233  otOut << "Using as server: " << str_ServerID << "\n";
234  }
235  else {
236  otOut
237  << "Unable to find a server contract. Please use the option: "
238  "--server SERVER_ID\n"
239  "(Where SERVER_ID is the server ID. Partial matches are "
240  "accepted "
241  "if the contract is already in the wallet.)\n"
242  "Also, see default values located in "
243  "~/.ot/comand-line-ot.opt \n";
244  // return false;
245  }
246  }
247  // Below this point, pServerContract MAY be available, but also may be
248  // nullptr.
249  //
250 
251  if (str_MyNym.size() > 0) {
252  const OTIdentifier MY_NYM_ID(str_MyNym.c_str());
253 
254  pMyNym = pWallet->GetNymByID(MY_NYM_ID);
255 
256  // If failure, then we try PARTIAL match.
257  if (nullptr == pMyNym)
258  pMyNym = pWallet->GetNymByIDPartialMatch(str_MyNym);
259 
260  if (nullptr != pMyNym) {
261  OTString strTemp;
262  pMyNym->GetIdentifier(strTemp);
263 
264  str_MyNym = strTemp.Get();
265  otOut << "Using as mynym: " << str_MyNym << "\n";
266  }
267  else {
268  otOut << "==> Unable to find My Nym. Please use the option: "
269  "--mynym USER_ID\n"
270  "(Where USER_ID is the Nym's ID. Partial matches are "
271  "accepted "
272  "if the nym is already in the wallet.)\n"
273  "Also, see default values located in "
274  "~/.ot/comand-line-ot.opt\n";
275  // return false;
276  }
277  } // Below this point, pMyNym MIGHT be a valid pointer, or MIGHT be nullptr.
278 
279  // Below THIS point, there's no guarantee of pWallet, though it MIGHT be
280  // there.
281  // Same with pServerContract. (MIGHT be there.)
282 
283  return true;
284 }
285 
286 void HandleCommandLineArguments(int32_t argc, char* argv[], AnyOption* opt)
287 {
288  if (nullptr == opt) return;
289 
290  OTString strConfigPath(OTPaths::AppDataFolder());
291  {
292  bool GetConfigPathSuccess =
293  strConfigPath.Exists() && 3 < strConfigPath.GetLength();
295  GetConfigPathSuccess,
296  "HandleCommandLineArguments: Must Set Conifg Path First!");
297  }
298 
299  /* 1. CREATE AN OBJECT */
300  // AnyOption *opt = new AnyOption();
301  // OT_ASSERT(nullptr != opt);
302  // std::unique_ptr<AnyOption> theOptionAngel(opt);
303 
304  /* 2. SET PREFERENCES */
305  // opt->noPOSIX(); /* do not check for POSIX style character options */
306  // opt->setVerbose(); /* print warnings about unknown options */
307  // opt->autoUsagePrint(true); /* print usage for bad options */
308 
309  /* 3. SET THE USAGE/HELP */
310  opt->addUsage("");
311  opt->addUsage(" **** NOTE: DO NOT USE 'ot' !! Use 'opentxs help' instead! "
312  "*** OT CLI Usage: ");
313  opt->addUsage("");
314  opt->addUsage(
315  "ot --stat (Prints the wallet contents) ot --prompt (Enter "
316  "the OT prompt)");
317  opt->addUsage("ot [-h|-?|--help] (Prints this help) ot --script "
318  "<filename> [--args \"key value ...\"]");
319  opt->addUsage(
320  "The '|' symbol means use --balance or -b, use --withdraw or -w, etc.");
321  opt->addUsage(
322  "The brackets '[]' show required arguments, where default values are");
323  opt->addUsage(
324  "normally expected to be found in: ~/.ot/command-line-ot.opt");
325  opt->addUsage(
326  "ot --balance | -b [--myacct <acct_id>] (Display "
327  "account balance)");
328  opt->addUsage("ot --withdraw | -w <amount> [--myacct <acct_id>] "
329  "(Withdraw as CASH)");
330  opt->addUsage(
331  "ot --transfer | -t <amount> [--myacct <acct_id>] [--hisacct "
332  "<acct_id>]");
333  opt->addUsage(
334  "ot --cheque | -c <amount> [--myacct <acct_id>] [--hisnym "
335  "<nym_id> ]");
336  opt->addUsage(
337  "ot --voucher | -v <amount> [--myacct <acct_id>] [--hisnym "
338  "<nym_id> ]");
339  opt->addUsage(
340  "ot --depositcheque [--myacct <acct_id>] (Deposit a cheque.)");
341  opt->addUsage(
342  "ot --depositpurse [--myacct <acct_id>] (Deposit a cash purse.)");
343  opt->addUsage("ot --deposittokens [--myacct <acct_id>] (Deposit "
344  "individual cash tokens.)");
345  opt->addUsage(
346  "ot --inbox | -i [--myacct <acct_id>] (Display the inbox.)");
347  opt->addUsage(
348  "ot --sign | -s [--mynym <nym_id> ] (Sign a contract.)");
349  opt->addUsage(
350  "ot --verify [--mynym <nym_id> ] (Verify a signature.)");
351  opt->addUsage(
352  "ot --purse | -p <arguments> (Display a purse.)");
353  opt->addUsage(
354  " Arguments: [--mynym <nym_id> ] [--mypurse <asset_type_id>]");
355  opt->addUsage("ot --refresh | -r [--myacct <acct_id>] (Download "
356  "account files from server.)");
357  opt->addUsage("ot --refreshnym [--mynym <nym_id> ] (Download nym "
358  "files from server.)");
359  opt->addUsage(
360  "ot --marketoffer [--mynym <nym_id> ] (Place an offer "
361  "on a market.)");
362  opt->addUsage(
363  "Also, [--server <server_id>] will work with all of the above.");
364  opt->addUsage("");
365  opt->addUsage("Recurring payments:");
366  opt->addUsage("ot --proposeplan <arguments> (Merchant)");
367  opt->addUsage(" Arguments: [--mynym <nym_id> ] [--myacct <acct_id>] "
368  "(continued.)");
369  opt->addUsage(" Continued: [--hisnym <nym_id> ] [--hisacct <acct_id> ]");
370  opt->addUsage("ot --confirmplan <arguments> (Customer)");
371  opt->addUsage("ot --activateplan <arguments> (Customer again)");
372  opt->addUsage(" Arguments: [--mynym <nym_id> ] [--myacct <acct_id>]");
373  opt->addUsage(
374  " **** NOTE: DO NOT USE 'ot' !! Use 'opentxs help' instead! ***");
375 
376  /* 4. SET THE OPTION STRINGS/CHARACTERS */
377  //
378  // COMMAND LINE *AND* RESOURCE FILE
379 
380  // opt->setOption( "server" ); /* an option (takes an argument),
381  // supporting only int64_t form */
382 
383  /* 4. SET THE OPTION STRINGS/CHARACTERS */
384  //
385  // COMMAND LINE *AND* RESOURCE FILE
386 
387  // opt->setOption( "server" ); /* an option (takes an argument),
388  // supporting only int64_t form */
389 
390  // COMMAND LINE ONLY
391  /* for options that will be checked only on the command and line not in
392  * option/resource file */
393  // opt->setCommandFlag( "zip" , 'z'); /* a flag (takes no argument),
394  // supporting int64_t and short form */
395  opt->setCommandOption("withdraw",
396  'w'); // withdraw from acct to purse, myacct, topurse
397  opt->setCommandOption("transfer",
398  't'); // transfer acct-to-acct, myacct, toacct
399  opt->setCommandOption("cheque", 'c'); // write a cheque myacct, tonym
400  opt->setCommandOption("voucher", 'v'); // withdraw voucher myacct, tonym
401  opt->setCommandFlag("marketoffer"); // add an offer to the market.
402  opt->setCommandFlag("balance", 'b'); // Display account balance
403  opt->setCommandFlag("depositcheque"); // deposit a cheque to myacct
404  opt->setCommandFlag("depositpurse"); // deposit cash purse to myacct
405  opt->setCommandFlag(
406  "deposittokens"); // deposit individual cash tokens to myacct
407  opt->setCommandFlag("proposeplan"); // Merchant proposes a payment plan.
408  opt->setCommandFlag("confirmplan"); // Customer confirms a payment plan.
409  opt->setCommandFlag("activateplan"); // Customer activates a payment plan.
410  opt->setCommandFlag("inbox", 'i'); // displays inbox (for ACCT_ID...)
411  opt->setCommandFlag("sign", 's'); // sign a contract mynym
412  opt->setCommandFlag("verify"); // verify a signature
413  opt->setCommandFlag("purse", 'p'); // display purse contents.
414  opt->setCommandFlag("refresh", 'r'); // refresh intermediary files from
415  // server + verify against last receipt.
416  opt->setCommandFlag("refreshnym"); // refresh intermediary files from server
417  // + verify against last receipt.
418  opt->setCommandFlag("stat"); // print out the wallet contents.
419  opt->setCommandFlag("prompt"); // Enter the OT prompt.
420  opt->setCommandOption(
421  "script"); // Process a script from out of a scriptfile
422  opt->setCommandOption(
423  "args"); // Pass custom arguments from command line: --args "key1 value1
424  // key2 \"here is value2\" key3 value3"
425 
426  opt->setCommandFlag("help", 'h'); // the Help screen.
427  opt->setCommandFlag('?'); // the Help screen.
428 
429  /*
430  --myacct (ACCT ID)
431  --mynym (NYM ID)
432  --mypurse (ASSET TYPE ID)
433 
434  --toacct (ACCT ID)
435  --tonym (NYM ID)
436  --topurse (ASSET TYPE ID)
437  */
438  opt->setCommandOption("server");
439 
440  opt->setCommandOption("myacct");
441  opt->setCommandOption("mynym");
442  opt->setCommandOption("mypurse");
443  opt->setCommandOption("hisacct");
444  opt->setCommandOption("hisnym");
445  opt->setCommandOption("hispurse");
446 
447  // NOTE: Above and Below me are IDs. This interface should allow PARTIAL
448  // IDs.
449 
450  // RESOURCE FILE ONLY
451  /* for options that will be checked only from the option/resource file */
452  opt->setFileOption("defaultserver");
453  /* an option (takes an argument), supporting only int64_t form */
454 
455  opt->setFileOption("defaultmyacct");
456  /* an option (takes an argument), supporting only int64_t form */
457  opt->setFileOption("defaultmynym");
458  /* an option (takes an argument), supporting only int64_t form */
459  opt->setFileOption("defaultmypurse");
460  /* an option (takes an argument), supporting only int64_t form */
461  opt->setFileOption("defaulthisacct");
462  /* an option (takes an argument), supporting only int64_t form */
463  opt->setFileOption("defaulthisnym");
464  /* an option (takes an argument), supporting only int64_t form */
465  opt->setFileOption("defaulthispurse");
466  /* an option (takes an argument), supporting only int64_t form */
467  /*
468  --defaultmyacct (ACCT ID)
469  --defaultmynym (NYM ID)
470  --defaultmypurse (ASSET TYPE ID)
471 
472  --defaulttoacct (ACCT ID)
473  --defaulttonym (NYM ID)
474  --defaulttopurse (ASSET TYPE ID)
475  */
476 
477  /* 5. PROCESS THE COMMANDLINE AND RESOURCE FILE */
478 
479  /* read options from a option/resource file with ':' separated options or
480  * flags, one per line */
481 
482  OTString strOptionsFile(OT_OPTIONS_FILE_DEFAULT), strIniFileExact;
483  {
484  bool bBuildFullPathSuccess = OTPaths::RelativeToCanonical(
485  strIniFileExact, strConfigPath, strOptionsFile);
486  OT_ASSERT_MSG(bBuildFullPathSuccess, "Unalbe to set Full Path");
487  }
488 
489  opt->processFile(strIniFileExact.Get());
490  opt->processCommandArgs(argc, argv);
491 }
492 
493 /*
494 I'm starting to need this in possibly multiple places below, so I
495 made a function to avoid duplicating code. These are values such
496 as "my account ID" and "his NymID" that are provided on the command
497 line, and which also can be defaulted in a config file in ~/.ot
498 */
499 void CollectDefaultedCLValues(AnyOption* opt, std::string& str_ServerID,
500  std::string& str_MyAcct, std::string& str_MyNym,
501  std::string& str_MyPurse,
502  std::string& str_HisAcct, std::string& str_HisNym,
503  std::string& str_HisPurse)
504 {
505  OT_ASSERT(nullptr != opt);
506 
507  OTAPI_Wrap::Output(1, "\n");
508 
509  // First we pre-set all the values based on the defaults from the options
510  // file.
511  //
512  if (opt->getValue("defaultserver") != nullptr) {
513  // cerr << "Server default: " << (str_ServerID = opt->getValue(
514  // "defaultserver" )) << endl;
515  str_ServerID = opt->getValue("defaultserver");
516  otWarn << "Server default: " << str_ServerID << " \n";
517  }
518 
519  if (opt->getValue("defaultmyacct") != nullptr) {
520  // cerr << "MyAcct default: " << (str_MyAcct = opt->getValue(
521  // "defaultmyacct" )) << endl;
522  str_MyAcct = opt->getValue("defaultmyacct");
523  otWarn << "MyAcct default: " << str_MyAcct << " \n";
524  }
525  if (opt->getValue("defaultmynym") != nullptr) {
526  // cerr << "MyNym default: " << (str_MyNym = opt->getValue(
527  // "defaultmynym" )) << endl;
528  str_MyNym = opt->getValue("defaultmynym");
529  otWarn << "MyNym default: " << str_MyNym << " \n";
530  }
531  if (opt->getValue("defaultmypurse") != nullptr) {
532  // cerr << "MyPurse default: " << (str_MyPurse = opt->getValue(
533  // "defaultmypurse" )) << endl;
534  str_MyPurse = opt->getValue("defaultmypurse");
535  otWarn << "MyPurse default: " << str_MyPurse << " \n";
536  }
537 
538  if (opt->getValue("defaulthisacct") != nullptr) {
539  // cerr << "HisAcct default: " << (str_HisAcct = opt->getValue(
540  // "defaulthisacct" )) << endl;
541  str_HisAcct = opt->getValue("defaulthisacct");
542  otWarn << "HisAcct default: " << str_HisAcct << " \n";
543  }
544  if (opt->getValue("defaulthisnym") != nullptr) {
545  // cerr << "HisNym default: " << (str_HisNym = opt->getValue(
546  // "defaulthisnym" )) << endl;
547  str_HisNym = opt->getValue("defaulthisnym");
548  otWarn << "HisNym default: " << str_HisNym << " \n";
549  }
550  if (opt->getValue("defaulthispurse") != nullptr) {
551  // cerr << "HisPurse default: " << (str_HisPurse = opt->getValue(
552  // "defaulthispurse" )) << endl;
553  str_HisPurse = opt->getValue("defaulthispurse");
554  otWarn << "HisPurse default: " << str_HisPurse << " \n";
555  }
556 
557  // Next, we overwrite those with any that were passed in on the command
558  // line.
559 
560  if (opt->getValue("server") != nullptr) {
561  // cerr << "Server from command-line: " << (str_ServerID =
562  // opt->getValue( "server" )) << endl;
563  str_ServerID = opt->getValue("server");
564  otWarn << "Server from command-line: " << str_ServerID << " \n";
565  }
566 
567  if (opt->getValue("myacct") != nullptr) {
568  // cerr << "MyAcct from command-line: " << (str_MyAcct =
569  // opt->getValue(
570  // "myacct" )) << endl;
571  str_MyAcct = opt->getValue("myacct");
572  otWarn << "MyAcct from command-line: " << str_MyAcct << " \n";
573  }
574  if (opt->getValue("mynym") != nullptr) {
575  // cerr << "MyNym from command-line: " << (str_MyNym =
576  // opt->getValue(
577  // "mynym" )) << endl;
578  str_MyNym = opt->getValue("mynym");
579  otWarn << "MyNym from command-line: " << str_MyNym << " \n";
580  }
581  if (opt->getValue("mypurse") != nullptr) {
582  // cerr << "MyPurse from command-line: " << (str_MyPurse =
583  // opt->getValue( "mypurse" )) << endl;
584  str_MyPurse = opt->getValue("mypurse");
585  otWarn << "MyPurse from command-line: " << str_MyPurse << " \n";
586  }
587 
588  if (opt->getValue("hisacct") != nullptr) {
589  // cerr << "HisAcct from command-line: " << (str_HisAcct =
590  // opt->getValue( "hisacct" )) << endl;
591  str_HisAcct = opt->getValue("hisacct");
592  otWarn << "HisAcct from command-line: " << str_HisAcct << " \n";
593  }
594  if (opt->getValue("hisnym") != nullptr) {
595  // cerr << "HisNym from command-line: " << (str_HisNym =
596  // opt->getValue(
597  // "hisnym" )) << endl;
598  str_HisNym = opt->getValue("hisnym");
599  otWarn << "HisNym from command-line: " << str_HisNym << " \n";
600  }
601  if (opt->getValue("hispurse") != nullptr) {
602  // cerr << "HisPurse from command-line: " << (str_HisPurse =
603  // opt->getValue( "hispurse" )) << endl;
604  str_HisPurse = opt->getValue("hispurse");
605  otWarn << "HisPurse from command-line: " << str_HisPurse << " \n";
606  }
607 }
608 
609 // ************************************* MAIN FUNCTION
610 
611 using std::cerr;
612 using std::endl;
613 
614 int32_t main(int32_t argc, char* argv[])
615 {
616  class __OTclient_RAII
617  {
618  public:
619  __OTclient_RAII()
620  {
621  // OT_API class exists only on the client side.
622 
623  OTAPI_Wrap::AppInit(); // SSL gets initialized in here, before any
624  // keys
625  // are loaded.
626  }
627  ~__OTclient_RAII()
628  {
630  }
631  };
632  //
633  // This makes SURE that AppCleanup() gets called before main() exits
634  // (without
635  // any
636  // twisted logic being necessary below, for that to happen.)
637  //
638  __OTclient_RAII the_client_cleanup;
639  //
640 
641  if (nullptr == OTAPI_Wrap::OTAPI())
642  return -1; // error out if we don't have the API.
643 
644  OTString strConfigPath(OTPaths::AppDataFolder());
645  bool bConfigPathFound =
646  strConfigPath.Exists() && 3 < strConfigPath.GetLength();
647 
648  OT_ASSERT_MSG(bConfigPathFound,
649  "RegisterAPIWithScript: Must set Config Path first!\n");
650 
651  otWarn << "Using configuration path: " << strConfigPath << "\n";
652 
653  // otOut << "Prefix Path: " << OTPaths::PrefixFolder() << "\n";
654  // otOut << "Scripts Path: " << OTPaths::ScriptsFolder() << "\n";
655  //
656  // OTString out_strHomeFolder;
657  // OTPaths::GetHomeFromSystem(out_strHomeFolder);
658  // otOut << "Home from System: " << out_strHomeFolder << "\n";
659 
660  // COMMAND-LINE OPTIONS (and default values from files.)
661  //
662  AnyOption* opt = new AnyOption();
663  OT_ASSERT(nullptr != opt);
664  std::unique_ptr<AnyOption> theOptionAngel(opt);
665 
666  // Process the command line args
667  //
668  HandleCommandLineArguments(argc, argv, opt);
669 
670  // command line values such as account ID, Nym ID, etc.
671  // Also available as defaults in a config file in the ~/.ot folder
672  //
673  std::string str_ServerID;
674 
675  std::string str_MyAcct;
676  std::string str_MyNym;
677  std::string str_MyPurse;
678 
679  std::string str_HisAcct;
680  std::string str_HisNym;
681  std::string str_HisPurse;
682 
683  CollectDefaultedCLValues(opt, str_ServerID, str_MyAcct, str_MyNym,
684  str_MyPurse, str_HisAcct, str_HisNym,
685  str_HisPurse);
686  // Users can put --args "key value key value key value etc"
687  // Then they can access those values from within their scripts.
688 
689  std::string str_Args;
690 
691  if (opt->getValue("args") != nullptr)
692  cerr << "User-defined arguments aka: --args "
693  << (str_Args = opt->getValue("args")) << endl;
694 
695  /* USAGE SCREEN (HELP) */
696  //
697  if (opt->getFlag("help") || opt->getFlag('h') || opt->getFlag('?')) {
698  opt->printUsage();
699 
700  return 0;
701  }
702 
703  bool bIsCommandProvided = false;
704 
705  // See if there's a COMMAND chosen at command line.
706  //
707  if (opt->hasOptions()) {
708  // Below are COMMANDS (only one of them can be true...)
709  //
710 
711  if (opt->getValue('w') != nullptr ||
712  opt->getValue("withdraw") != nullptr) {
713  bIsCommandProvided = true;
714  cerr << "withdraw amount = " << opt->getValue('w') << endl;
715  }
716  else if (opt->getValue('t') != nullptr ||
717  opt->getValue("transfer") != nullptr) {
718  bIsCommandProvided = true;
719  cerr << "transfer amount = " << opt->getValue('t') << endl;
720  }
721  else if (opt->getValue('c') != nullptr ||
722  opt->getValue("cheque") != nullptr) {
723  bIsCommandProvided = true;
724  cerr << "cheque amount = " << opt->getValue('c') << endl;
725  }
726  else if (opt->getFlag("marketoffer") == true) {
727  bIsCommandProvided = true;
728  cerr << "marketoffer flag set " << endl;
729  }
730  else if (opt->getValue('v') != nullptr ||
731  opt->getValue("voucher") != nullptr) {
732  bIsCommandProvided = true;
733  cerr << "voucher amount = " << opt->getValue('v') << endl;
734  }
735  else if (opt->getFlag("depositcheque")) {
736  bIsCommandProvided = true;
737  cerr << "deposit cheque flag set " << endl;
738  }
739  else if (opt->getFlag("depositpurse")) {
740  bIsCommandProvided = true;
741  cerr << "deposit purse flag set " << endl;
742  }
743  else if (opt->getFlag("deposittokens")) {
744  bIsCommandProvided = true;
745  cerr << "deposit tokens flag set " << endl;
746  }
747  else if (opt->getFlag("proposepaymentplan")) {
748  bIsCommandProvided = true;
749  cerr << "proposepaymentplan flag set " << endl;
750  }
751  else if (opt->getFlag("confirmpaymentplan")) {
752  bIsCommandProvided = true;
753  cerr << "confirm payment plan flag set " << endl;
754  }
755  else if (opt->getFlag("activatepaymentplan")) {
756  bIsCommandProvided = true;
757  cerr << "activate payment plan flag set " << endl;
758  }
759  else if (opt->getFlag('b') || opt->getFlag("balance")) {
760  bIsCommandProvided = true;
761  cerr << "balance flag set " << endl;
762  }
763  else if (opt->getFlag('i') || opt->getFlag("inbox")) {
764  bIsCommandProvided = true;
765  cerr << "inbox flag set " << endl;
766  }
767  else if (opt->getFlag('p') || opt->getFlag("purse")) {
768  bIsCommandProvided = true;
769  cerr << "purse flag set " << endl;
770  }
771  else if (opt->getFlag('s') || opt->getFlag("sign")) {
772  bIsCommandProvided = true;
773  cerr << "sign flag set " << endl;
774  }
775  else if (opt->getFlag("verify")) {
776  bIsCommandProvided = true;
777  cerr << "verify flag set " << endl;
778  }
779  else if (opt->getFlag("stat")) {
780  bIsCommandProvided = true;
781  cerr << "stat flag set " << endl;
782  }
783  else if (opt->getFlag("prompt")) {
784  bIsCommandProvided = true;
785  cerr << "prompt flag set " << endl;
786  }
787  else if (opt->getValue("script") != nullptr) {
788  bIsCommandProvided = true;
789  cerr << "script filename: " << opt->getValue("script") << endl;
790  }
791  else if (opt->getFlag('r') || opt->getFlag("refresh")) {
792  bIsCommandProvided = true;
793  cerr << "refresh flag set " << endl;
794  }
795  else if (opt->getFlag("refreshnym")) {
796  bIsCommandProvided = true;
797  cerr << "refreshnym flag set " << endl;
798  }
799 
800  cerr << endl;
801  }
802  else
803  bIsCommandProvided = false;
804 
805  //
806  if (!(opt->getArgc() > 0) && (false == bIsCommandProvided)) // If no command
807  // was provided
808  // (though other
809  // command-line options may have been...)
810  { // then we expect a script to come in through stdin, and we run it
811  // through the script interpreter!
812  otOut << "\n\nYou probably don't want to do this... Use CTRL-C, "
813  "and try \"ot --help\" for instructions.\n\n "
814  "==> Expecting ot script from standard input. (Terminate "
815  "with CTRL-D):\n\n";
816 
817  // don't skip the whitespace while reading
818  std::cin >> std::noskipws;
819 
820  // use stream iterators to copy the stream to a string
821  std::istream_iterator<char> it(std::cin);
822  std::istream_iterator<char> end;
823  std::string results(it, end);
824 
825  OT_ME madeEasy;
827  madeEasy.ExecuteScript_ReturnVoid(results, ("stdin"));
828 
829  return 0;
830  }
831 
832  // Otherwise a command WAS provided at the command line, so we execute a
833  // single time, once just for that command.
834  {
835  OTWallet* pWallet = nullptr;
836  OTServerContract* pServerContract = nullptr;
837  OTPseudonym* pMyNym = nullptr;
838 
839  // This does LoadWallet, andif Nym or Server IDs were provided, loads
840  // those
841  // up as well.
842  // (They may still be nullptr after this call, however.)
843  //
844  bool bMainPointersSetupSuccessful =
846  str_ServerID, str_MyNym, pMyNym, pWallet, pServerContract);
847 
849  bMainPointersSetupSuccessful,
850  "main: SetupPointersForWalletMyNymAndServerContract failed "
851  "to return true");
852 
853  // Below this point, pWallet is available :-)
854  // Later I can split the below commands into "those that need a server
855  // contract"
856  // and "those that don't need a server contract", and put this code
857  // between
858  // them.
859  // That's what the OT Prompt loop does. For now I'm making things easy
860  // here
861  // by just
862  // making it a blanket requirement.
863  //
864  if (nullptr == pServerContract) {
865  otOut << "Unable to find a server contract to use. Please use "
866  "the option: --server SERVER_ID\n"
867  "(Where SERVER_ID is the Server's ID. Partial matches "
868  "ARE accepted.)\n";
869  // return 0;
870  }
871 
872  OTIdentifier theServerID;
873  OTString strServerID;
874 
875  if (nullptr != pServerContract) {
876  pServerContract->GetIdentifier(theServerID);
877  theServerID.GetString(strServerID);
878  }
879  // int32_t nServerPort = 0;
880  // OTString strServerHostname;
881  // You can't just connect to any hostname and port.
882  // Instead, you give me the Server Contract, and *I'll* look up all that
883  // stuff FOR you...
884  // (We verify this up here, but use it at the bottom of the function
885  // once
886  // the message is set up.)
887  //
888 
889  // if (!pServerContract->GetConnectInfo(strServerHostname,
890  // nServerPort))
891  // {
892  // otErr << "Failed retrieving connection info from server "
893  // "contract: " << strServerID << "\n";
894  // return 0;
895  // }
896 
897  // Below this point, pWallet and pServerContract are both available.
898  // UPDATE: Not necessarily... (pServerContract may be nullptr...)
899  //
900 
901  OTAccount* pMyAccount = nullptr;
902  OTAccount* pHisAccount = nullptr;
903 
904  if (str_MyAcct.size() > 0) {
905  const OTIdentifier MY_ACCOUNT_ID(str_MyAcct.c_str());
906 
907  pMyAccount = pWallet->GetAccount(MY_ACCOUNT_ID);
908 
909  // If failure, then we try PARTIAL match.
910  if (nullptr == pMyAccount)
911  pMyAccount = pWallet->GetAccountPartialMatch(str_MyAcct);
912 
913  if (nullptr != pMyAccount) {
914  OTString strTemp;
915  pMyAccount->GetPurportedAccountID().GetString(strTemp);
916 
917  str_MyAcct = strTemp.Get();
918  otOut << "Using as myacct: " << str_MyAcct << "\n";
919  }
920  else // Execution aborts if we cannot find MyAcct when one was
921  // provided.
922  {
923  otOut << "Aborting: Unable to find specified myacct: "
924  << str_MyAcct << "\n";
925  return 0;
926  }
927  }
928  // TODO: I wouldn't have HIS account in MY wallet -- I'd only have his
929  // account ID.
930  // Therefore need to be able to retrieve this info from the ADDRESS BOOK
931  // (in
932  // order
933  // to be able to do PARTIAL MATCHES...)
934  //
935  if (str_HisAcct.size() > 0) {
936  const OTIdentifier HIS_ACCOUNT_ID(str_HisAcct.c_str());
937 
938  pHisAccount = pWallet->GetAccount(HIS_ACCOUNT_ID);
939 
940  // If failure, then we try PARTIAL match.
941  if (nullptr == pHisAccount)
942  pHisAccount = pWallet->GetAccountPartialMatch(str_HisAcct);
943  if (nullptr != pHisAccount) {
944  OTString strTemp;
945  pHisAccount->GetPurportedAccountID().GetString(strTemp);
946 
947  str_HisAcct = strTemp.Get();
948  otOut << "Using as hisacct: " << str_HisAcct << "\n";
949  }
950 
951  // Execution continues, even if we fail to find his account.
952  // (Only my accounts will be in my wallet. Anyone else's account
953  // will exist on the server, even if it's not in my wallet.
954  // Therefore
955  // we still allow users to use HisAcctID since their server messages
956  // will usually actually work.)
957  //
958  // Again: Just because account lkjsf09234lkjafkljasd098q345lkjasdf
959  // doesn't
960  // appear in my wallet, doesn't mean the account doesn't exist on
961  // the
962  // server
963  // and in reality. Therefore I must assume, if I didn't find it by
964  // abbreviation,
965  // that it exists exactly as entered. The server message will just
966  // fail,
967  // if it
968  // doesn't exist. (But then that's the user's fault...)
969  //
970  // We can still keep account IDs in the address book, even if they
971  // aren't
972  // in the wallet (since they're owned by someone else...)
973  //
974  }
975 
976  // I put this here too since I think it's required in all cases.
977  // Update: commented out the return in order to allow for empty wallets.
978  //
979  if (nullptr ==
980  pMyNym) // Todo maybe move this check to the commands below
981  // (ONLY the ones that use a nym.)
982  {
983  otOut << "Unable to find My Nym. Please use the option: --mynym "
984  "USER_ID\n"
985  "(Where USER_ID is the Nym's ID. Partial matches and "
986  "names are "
987  "accepted.)\n";
988  // return 0;
989  }
990 
991  OTIdentifier MY_NYM_ID;
992 
993  if (nullptr != pMyNym) pMyNym->GetIdentifier(MY_NYM_ID);
994  OTPseudonym* pHisNym = nullptr;
995 
996  if (str_HisNym.size() > 0) {
997  const OTIdentifier HIS_NYM_ID(str_HisNym.c_str());
998 
999  pHisNym = pWallet->GetNymByID(HIS_NYM_ID);
1000  // If failure, then we try PARTIAL match.
1001  if (nullptr == pHisNym)
1002  pHisNym = pWallet->GetNymByIDPartialMatch(str_HisNym);
1003  if (nullptr != pHisNym) {
1004  OTString strTemp;
1005  pHisNym->GetIdentifier(strTemp);
1006 
1007  str_HisNym = strTemp.Get();
1008  otOut << "Using as hisnym: " << str_HisNym << "\n";
1009  }
1010  }
1011 
1012  // Below this point, if Nyms or Accounts were specified, they are now
1013  // available.
1014  // (Pointers might be null, though currently My Nym is required to be
1015  // there.)
1016  //
1017  // Execution continues, even if we fail to find his nym.
1018  // This is so the script has the opportunity to "check nym" (Download
1019  // it)
1020  // based on the ID that the user has entered here.
1021 
1022  OTIdentifier thePurseAssetTypeID;
1023  OTAssetContract* pMyAssetContract = nullptr;
1024 
1025  if (str_MyPurse.size() > 0) {
1026  const OTIdentifier MY_ASSET_TYPE_ID(str_MyPurse.c_str());
1027  pMyAssetContract = pWallet->GetAssetContract(MY_ASSET_TYPE_ID);
1028 
1029  // If failure, then we try PARTIAL match.
1030  if (nullptr == pMyAssetContract)
1031  pMyAssetContract =
1032  pWallet->GetAssetContractPartialMatch(str_MyPurse);
1033 
1034  if (nullptr != pMyAssetContract) {
1035  OTString strTemp;
1036  pMyAssetContract->GetIdentifier(strTemp);
1037 
1038  str_MyPurse = strTemp.Get();
1039  otOut << "Using as mypurse: " << str_MyPurse << "\n";
1040 
1041  pMyAssetContract->GetIdentifier(thePurseAssetTypeID);
1042  }
1043  // Execution continues here, so the script has the option to
1044  // download
1045  // any asset contract, if it can't find it in the wallet.
1046  }
1047  // if no purse (asset type) ID was provided, but MyAccount WAS provided,
1048  // then
1049  // use the asset type for the account instead.
1050  else if (nullptr != pMyAccount)
1051  thePurseAssetTypeID = pMyAccount->GetAssetTypeID();
1052  if (!thePurseAssetTypeID.IsEmpty()) {
1053  OTString strTempAssetType(thePurseAssetTypeID);
1054  str_MyPurse = strTempAssetType.Get();
1055  }
1056  // BELOW THIS POINT, pMyAssetContract MIGHT be nullptr, or MIGHT be an
1057  // asset
1058  // type specified by the user.
1059  // There's no guarantee that it's available, but if it IS, then it WILL
1060  // be
1061  // available below this point.
1062  OTIdentifier hisPurseAssetTypeID;
1063 
1064  if (str_HisPurse.size() > 0) {
1065  const OTIdentifier HIS_ASSET_TYPE_ID(str_HisPurse.c_str());
1066  OTAssetContract* pHisAssetContract =
1067  pWallet->GetAssetContract(HIS_ASSET_TYPE_ID);
1068 
1069  // If failure, then we try PARTIAL match.
1070  if (nullptr == pHisAssetContract)
1071  pHisAssetContract =
1072  pWallet->GetAssetContractPartialMatch(str_HisPurse);
1073 
1074  if (nullptr != pHisAssetContract) {
1075  OTString strTemp;
1076  pHisAssetContract->GetIdentifier(strTemp);
1077 
1078  str_HisPurse = strTemp.Get();
1079  otOut << "Using as hispurse: " << str_HisPurse << "\n";
1080 
1081  pHisAssetContract->GetIdentifier(hisPurseAssetTypeID);
1082  }
1083  }
1084  // If no "HisPurse" was provided, but HisAcct WAS, then we use the
1085  // asset type of HisAcct as HisPurse.
1086  else if (nullptr != pHisAccount)
1087  hisPurseAssetTypeID = pHisAccount->GetAssetTypeID();
1088  if (!hisPurseAssetTypeID.IsEmpty()) {
1089  OTString strTempAssetType(hisPurseAssetTypeID);
1090  str_HisPurse = strTempAssetType.Get();
1091  }
1092 
1093  otOut << "\n";
1094 
1095  // Also, pAccount and pMyAssetContract have not be validated AGAINST
1096  // EACH
1097  // OTHER (yet)...
1098  // Also, pHisAccount and pHisAssetContract have not be validated AGAINST
1099  // EACH OTHER (yet)...
1100 
1101  /* GET THE ACTUAL ARGUMENTS AFTER THE OPTIONS */
1102  //
1103  // for( int32_t i = 0 ; i < opt->getArgc() ; i++ )
1104  // {
1105  // cerr << "arg = " << opt->getArgv( i ) << endl ;
1106  // }
1107 
1108  bool bSendCommand = false; // Determines whether to actually send a
1109  // message to the server.
1110 
1111  OTMessage theMessage;
1112 
1113  // If we can match the user's request to a client command,
1114  // AND theClient object is able to process that request into
1115  // theMessage, then we send it down the pipe.
1116 
1117  // In lieu of maintaining a constant connection to the server, in ZMQ
1118  // mode,
1119  // the
1120  // client updates its internal "connection" object to make sure the
1121  // right
1122  // pointers
1123  // are in place (since in ZMQ mode, each message could be from a
1124  // different
1125  // nym
1126  // and to a different server.)
1127  //
1128  if ((nullptr != pServerContract) && (nullptr != pMyNym))
1130  *pServerContract, *pMyNym,
1131  OTAPI_Wrap::OTAPI()->GetTransportCallback());
1132  // NOTE -- This MAY be unnecessary for ProcessUserCommand (since these
1133  // args
1134  // are passed
1135  // in there already) but it's definitely necessary soon after for
1136  // ProcessServerReply()
1137  // (which comes next.)
1138 
1139  // (OTClient::OT_CLIENT_CMD_TYPE requestedCommand,
1140  // OTMessage & theMessage,
1141  // OTPseudonym & theNym,
1142  // OTServerContract & theServer,
1143  // OTAccount * pAccount,
1144  // lAmount
1145  // OTAssetContract * pMyAssetType,
1146  // OTAccount * pHisAcct,
1147  // OTPseudonym * pHisNym)
1148 
1149  // COMMANDS
1150 
1151  if ((opt->getValue("script") != nullptr) || (opt->getArgc() > 0)) {
1152  OTAPI_Wrap::OTAPI()->GetClient()->SetRunningAsScript(); // This way
1153  // it won't
1154  // go firing
1155  // off
1156  // messages
1157  // automatically based on receiving certain
1158  // server replies to previous requests.
1159  // Todo: Research whether the above call is still necessary. (OTAPI
1160  // no
1161  // longer fires off ANY auto messages based on server replies. API
1162  // CLIENT
1163  // MUST do those things itself now.)
1164 
1165  std::string strFilename;
1166 
1167  // If a filename is provided as a normal argument (like this: ot
1168  // <filename>)
1169  // then it will work...
1170  //
1171  if (opt->getArgc() > 0) {
1172  strFilename = opt->getArgv(0);
1173  }
1174 
1175  // the --script option will ALSO work for the filename, and will
1176  // override
1177  // the above.
1178  // so: ot --script <filename>
1179  // also: ot --script <actual_filename> <ignored_filename>
1180  //
1181  // In this above example, ignored_filename WOULD have been used, but
1182  // then
1183  // it got
1184  // overridden by the --script actual_filename.
1185 
1186  if (nullptr != opt->getValue("script")) {
1187  strFilename = opt->getValue("script");
1188  }
1189 
1190  std::ifstream t(strFilename.c_str(),
1191  std::ios::in | std::ios::binary);
1192  std::stringstream buffer;
1193  buffer << t.rdbuf();
1194  std::string results = buffer.str();
1195  OT_ME madeEasy;
1196 
1197  std::unique_ptr<OTVariable> angelArgs;
1198 
1199  std::unique_ptr<OTVariable> angelMyNymVar;
1200  std::unique_ptr<OTVariable> angelHisNymVar;
1201  std::unique_ptr<OTVariable> angelServer;
1202  std::unique_ptr<OTVariable> angelMyAcct;
1203  std::unique_ptr<OTVariable> angelHisAcct;
1204  std::unique_ptr<OTVariable> angelMyPurse;
1205  std::unique_ptr<OTVariable> angelHisPurse;
1206 
1207  if ((str_Args.size() > 0) || (opt->getArgc() > 1)) {
1208  const std::string str_var_name("Args");
1209  std::string str_var_value, str_command;
1210 
1211  if (str_Args.size() > 0) str_var_value += str_Args;
1212 
1213  if (opt->getArgc() > 1) {
1214  if (str_Args.size() > 0) str_var_value += " ";
1215 
1216  str_command = opt->getArgv(1);
1217  str_var_value += "ot_cli_command ";
1218  str_var_value += str_command;
1219  }
1220 
1221  otWarn << "Adding user-defined command line arguments as '"
1222  << str_var_name << "' "
1223  "containing value: " << str_var_value
1224  << "\n";
1225 
1226  OTVariable* pVar =
1227  new OTVariable(str_var_name, // "Args"
1228  str_var_value, // "key1 value1 key2 value2
1229  // key3 value3 key4 value4"
1230  OTVariable::Var_Constant); // constant,
1231  // persistent, or
1232  // important.
1233  angelArgs.reset(pVar);
1234  OT_ASSERT(nullptr != pVar);
1235  madeEasy.AddVariable(str_var_name, *pVar);
1236  }
1237  else {
1238  otInfo << "Args variable (optional user-defined "
1239  "arguments) isn't set...\n";
1240  }
1241 
1242  if (str_ServerID.size() > 0) {
1243  const std::string str_var_name("Server");
1244  const std::string str_var_value(str_ServerID);
1245 
1246  otWarn << "Adding constant with name " << str_var_name
1247  << " and value: " << str_var_value << " ...\n";
1248 
1249  OTVariable* pVar = new OTVariable(
1250  str_var_name, // "Server"
1251  str_var_value, // "lkjsdf09834lk5j34lidf09" (Whatever)
1252  OTVariable::Var_Constant); // constant, persistent, or
1253  // important.
1254  angelServer.reset(pVar);
1255  OT_ASSERT(nullptr != pVar);
1256  madeEasy.AddVariable(str_var_name, *pVar);
1257  }
1258  else {
1259  otInfo << "Server variable isn't set...\n";
1260  }
1261 
1262  if (nullptr != pMyNym) {
1263  const std::string str_party_name("MyNym");
1264 
1265  otWarn << "Adding constant with name " << str_party_name
1266  << " and value: " << str_MyNym << " ...\n";
1267 
1268  OTVariable* pVar = new OTVariable(
1269  str_party_name, // "MyNym"
1270  str_MyNym, // "lkjsdf09834lk5j34lidf09" (Whatever)
1271  OTVariable::Var_Constant); // constant, persistent, or
1272  // important.
1273  angelMyNymVar.reset(pVar);
1274  OT_ASSERT(nullptr != pVar);
1275  madeEasy.AddVariable(str_party_name, *pVar);
1276  }
1277  else {
1278  otInfo << "MyNym variable isn't set...\n";
1279  }
1280 
1281  if ((nullptr != pHisNym) || (str_HisNym.size() > 0)) // Even if we
1282  // didn't find
1283  // him, we still
1284  // let
1285  // the ID through, if there is one.
1286  {
1287  const std::string str_party_name("HisNym");
1288 
1289  otWarn << "Adding constant with name " << str_party_name
1290  << " and value: " << str_HisNym << " ...\n";
1291 
1292  OTVariable* pVar = new OTVariable(
1293  str_party_name, // "HisNym"
1294  str_HisNym, // "lkjsdf09834lk5j34lidf09" (Whatever)
1295  OTVariable::Var_Constant); // constant, persistent, or
1296  // important.
1297  angelHisNymVar.reset(pVar);
1298  OT_ASSERT(nullptr != pVar);
1299  madeEasy.AddVariable(str_party_name, *pVar);
1300  }
1301  else {
1302  otInfo << "HisNym variable isn't set...\n";
1303  }
1304  // WE NO LONGER PASS THE PARTY DIRECTLY TO THE SCRIPT,
1305  // BUT INSTEAD, ONLY THE PARTY'S NAME.
1306  //
1307  // (Because often, "HisNym" isn't in my wallet and wouldn't be found
1308  // anyway,
1309  // even though it ends up to contain a perfectly legitimate Nym
1310  // ID.)
1311  /*
1312  if (nullptr != pMyNym)
1313  {
1314  const std::string str_party_name("MyNym"),
1315  str_agent_name("mynym"), str_acct_name("myacct");
1316 
1317  pPartyMyNym = new OTParty (str_party_name, *pMyNym,
1318  str_agent_name, pMyAccount, &str_acct_name);
1319  angelMyNym.reset(pPartyMyNym);
1320  OT_ASSERT(nullptr != pPartyMyNym);
1321  pScript-> AddParty("MyNym", *pPartyMyNym);
1322  }
1323  else
1324  {
1325  otErr << "MyNym variable isn't set...\n";
1326  }
1327  if (nullptr != pHisNym)
1328  {
1329  const std::string str_party_name("HisNym"),
1330  str_agent_name("hisnym"), str_acct_name("hisacct");
1331 
1332  pPartyHisNym = new OTParty (str_party_name, *pHisNym,
1333  str_agent_name, pHisAccount, &str_acct_name);
1334  angelHisNym.reset(pPartyHisNym);
1335  OT_ASSERT(nullptr != pPartyHisNym);
1336  pScript-> AddParty("HisNym", *pPartyHisNym);
1337  }
1338  else
1339  {
1340  otErr << "HisNym variable isn't set...\n";
1341  }
1342  */
1343 
1344  if (str_MyAcct.size() > 0) {
1345  const std::string str_var_name("MyAcct");
1346  const std::string str_var_value(str_MyAcct);
1347 
1348  otWarn << "Adding variable with name " << str_var_name
1349  << " and value: " << str_var_value << " ...\n";
1350 
1351  OTVariable* pVar = new OTVariable(
1352  str_var_name, // "MyAcct"
1353  str_var_value, // "lkjsdf09834lk5j34lidf09" (Whatever)
1354  OTVariable::Var_Constant); // constant, persistent, or
1355  // important.
1356  angelMyAcct.reset(pVar);
1357  OT_ASSERT(nullptr != pVar);
1358  madeEasy.AddVariable(str_var_name, *pVar);
1359  }
1360  else {
1361  otInfo << "MyAcct variable isn't set...\n";
1362  }
1363 
1364  if (str_MyPurse.size() > 0) {
1365  const std::string str_var_name("MyPurse");
1366  const std::string str_var_value(str_MyPurse);
1367 
1368  otWarn << "Adding variable with name " << str_var_name
1369  << " and value: " << str_var_value << " ...\n";
1370 
1371  OTVariable* pVar = new OTVariable(
1372  str_var_name, // "MyPurse"
1373  str_var_value, // "lkjsdf09834lk5j34lidf09" (Whatever)
1374  OTVariable::Var_Constant); // constant, persistent, or
1375  // important.
1376  angelMyPurse.reset(pVar);
1377  OT_ASSERT(nullptr != pVar);
1378  madeEasy.AddVariable(str_var_name, *pVar);
1379  }
1380  else {
1381  otInfo << "MyPurse variable isn't set...\n";
1382  }
1383 
1384  if (str_HisAcct.size() > 0) {
1385  const std::string str_var_name("HisAcct");
1386  const std::string str_var_value(str_HisAcct);
1387 
1388  otWarn << "Adding variable with name " << str_var_name
1389  << " and value: " << str_var_value << " ...\n";
1390 
1391  OTVariable* pVar = new OTVariable(
1392  str_var_name, // "HisAcct"
1393  str_var_value, // "lkjsdf09834lk5j34lidf09" (Whatever)
1394  OTVariable::Var_Constant); // constant, persistent, or
1395  // important.
1396  angelHisAcct.reset(pVar);
1397  OT_ASSERT(nullptr != pVar);
1398  madeEasy.AddVariable(str_var_name, *pVar);
1399  }
1400  else {
1401  otInfo << "HisAcct variable isn't set...\n";
1402  }
1403 
1404  if (str_HisPurse.size() > 0) {
1405  const std::string str_var_name("HisPurse");
1406  const std::string str_var_value(str_HisPurse);
1407 
1408  otWarn << "Adding variable with name " << str_var_name
1409  << " and value: " << str_var_value << " ...\n";
1410 
1411  OTVariable* pVar = new OTVariable(
1412  str_var_name, // "HisPurse"
1413  str_var_value, // "lkjsdf09834lk5j34lidf09" (Whatever)
1414  OTVariable::Var_Constant); // constant, persistent, or
1415  // important.
1416  angelHisPurse.reset(pVar);
1417  OT_ASSERT(nullptr != pVar);
1418  madeEasy.AddVariable(str_var_name, *pVar);
1419  }
1420  else {
1421  otInfo << "MyPurse variable isn't set...\n";
1422  }
1423 
1425 
1426  otWarn << "Script output:\n\n";
1427 
1428  return madeEasy.ExecuteScript_ReturnInt(results, strFilename);
1429  }
1430  // OT SCRIPT ABOVE.
1431 
1432  if ((nullptr == pServerContract) || (nullptr == pMyNym)) {
1433  otErr << "Unexpected nullptr: "
1434  << ((nullptr == pServerContract) ? "pServerContract" : "")
1435  << " " << ((nullptr == pMyNym) ? "pMyNym" : "") << "\n";
1436  }
1437  else if (opt->getValue('w') != nullptr ||
1438  opt->getValue("withdraw") != nullptr) {
1439  const int64_t lAmount = atol(opt->getValue('w'));
1440 
1441  otOut << "(User has instructed to withdraw cash...)\n";
1442 
1443  // if successful setting up the command payload...
1444 
1446  OTClient::notarizeWithdrawal, theMessage, *pMyNym,
1447  *pServerContract, pMyAccount, lAmount)) {
1448  bSendCommand = true;
1449  }
1450  else
1451  otErr
1452  << "Error processing withdraw command in ProcessMessage.\n";
1453  }
1454  else if (opt->getValue('t') != nullptr ||
1455  opt->getValue("transfer") != nullptr) {
1456  const int64_t lAmount = atol(opt->getValue('t'));
1457 
1458  OTIdentifier HIS_ACCT_ID(
1459  (str_HisAcct.size() > 0) ? str_HisAcct.c_str() : "aaaaaaaa");
1460 
1461  otOut << "User has instructed to send a Transfer command "
1462  "(Notarize Transactions)...\n";
1463 
1464  // if successful setting up the command payload...
1465 
1467  OTClient::notarizeTransfer, theMessage, *pMyNym,
1468  *pServerContract, pMyAccount, lAmount,
1469  nullptr, // asset contract
1470  nullptr, // his Nym
1471  (str_HisAcct.size() > 0) ? &HIS_ACCT_ID
1472  : nullptr)) // his acct
1473  {
1474  bSendCommand = true;
1475  }
1476  else
1477  otErr << "Error processing notarizeTransactions (transfer) "
1478  "command "
1479  "in ProcessMessage.\n";
1480  }
1481  else if (opt->getValue('c') != nullptr ||
1482  opt->getValue("cheque") != nullptr) {
1483  otOut << "(User has instructed to write a cheque...)\n";
1484 
1485  const int64_t lAmount = atol(opt->getValue('c'));
1486 
1487  OTIdentifier HIS_NYM_ID((str_HisNym.size() > 0)
1488  ? str_HisNym.c_str()
1489  : "aaaaaaaa"); // todo hardcoding
1490 
1492  OTClient::writeCheque, theMessage, *pMyNym, *pServerContract,
1493  pMyAccount, lAmount, nullptr, // asset contract
1494  (str_HisNym.size() > 0) ? &HIS_NYM_ID : nullptr);
1495  }
1496  else if (opt->getValue('v') != nullptr ||
1497  opt->getValue("voucher") != nullptr) {
1498  otOut << "(User has instructed to withdraw a voucher...)\n";
1499 
1500  const int64_t lAmount = atol(opt->getValue('v'));
1501 
1502  OTIdentifier HIS_NYM_ID((str_HisNym.size() > 0) ? str_HisNym.c_str()
1503  : "aaaaaaaa");
1504 
1506  OTClient::withdrawVoucher, theMessage, *pMyNym,
1507  *pServerContract, pMyAccount, lAmount,
1508  nullptr, // asset contract
1509  (str_HisNym.size() > 0) ? &HIS_NYM_ID : nullptr)) {
1510  bSendCommand = true;
1511  }
1512  else
1513  otErr << "Error processing withdraw voucher command in "
1514  "ProcessMessage.\n";
1515 
1516  }
1517 
1518  // make an offer and put it onto a market.
1519  else if (opt->getValue("marketoffer") != nullptr) {
1520  otOut << "(User has instructed to send a marketOffer command to "
1521  "the server...)\n";
1522 
1523  // if successful setting up the command payload...
1524 
1526  OTClient::marketOffer, theMessage, *pMyNym,
1527  *pServerContract,
1528  nullptr)) // for now, keeping it simple.
1529  // Can add options later.
1530  {
1531  bSendCommand = true;
1532  }
1533  else
1534  otErr << "Error processing marketOffer command in "
1535  "ProcessMessage.\n";
1536  }
1537 
1538  /*
1539  bool ProcessUserCommand(OT_CLIENT_CMD_TYPE requestedCommand,
1540  OTMessage & theMessage,
1541  OTPseudonym & theNym,
1542  // OTAssetContract & theContract,
1543  OTServerContract & theServer,
1544  OTAccount * pAccount=nullptr,
1545  int64_t lTransactionAmount = 0,
1546  OTAssetContract * pMyAssetType=nullptr,
1547  OTIdentifier * pHisAcctID=nullptr,
1548  OTIdentifier * pHisNymID=nullptr);
1549  */
1550  else if (opt->getFlag("proposepaymentplan")) {
1551  otOut << "(User has instructed to propose a payment plan...)\n";
1552 
1553  OTIdentifier HIS_NYM_ID((str_HisNym.size() > 0) ? str_HisNym.c_str()
1554  : "aaaaaaaa");
1555  OTIdentifier HIS_ACCT_ID(
1556  (str_HisAcct.size() > 0) ? str_HisAcct.c_str() : "aaaaaaaa");
1557 
1559  OTClient::proposePaymentPlan, theMessage, *pMyNym,
1560  *pServerContract, pMyAccount, 0, pMyAssetContract,
1561  (str_HisNym.size() > 0) ? &HIS_NYM_ID : nullptr,
1562  (str_HisAcct.size() > 0) ? &HIS_ACCT_ID : nullptr);
1563  }
1564  else if (opt->getFlag("confirmpaymentplan")) {
1565  otOut << "(User has instructed to confirm a payment plan...)\n";
1566 
1568  OTClient::confirmPaymentPlan, theMessage, *pMyNym,
1569  *pServerContract,
1570  nullptr); // the account info is already on the plan, right?
1571  }
1572  else if (opt->getFlag("activatepaymentplan")) {
1573  otOut << "(User has instructed to activate a payment plan...)\n";
1574 
1576  OTClient::paymentPlan, theMessage, *pMyNym,
1577  *pServerContract, pMyAccount)) // if user DOES specify
1578  // an account
1579  // (unnecessary)
1580  { // then OT will verify that they match, and error otherwise.
1581  bSendCommand = true;
1582  }
1583  else
1584  otErr << "Error processing activate payment plan command in "
1585  "ProcessMessage.\n";
1586  }
1587  else if (opt->getFlag("depositcheque")) {
1588  otOut << "(User has instructed to deposit a cheque...)\n";
1589 
1590  // if successful setting up the command payload...
1591 
1593  OTClient::notarizeCheque, theMessage, *pMyNym,
1594  *pServerContract, pMyAccount)) {
1595  bSendCommand = true;
1596  }
1597  else
1598  otErr << "Error processing deposit cheque command in "
1599  "ProcessMessage.\n";
1600  }
1601  else if (opt->getFlag("depositpurse")) {
1602  otOut << "(User has instructed to deposit a cash purse...)\n";
1603 
1604  // if successful setting up the command payload...
1605 
1607  OTClient::notarizePurse, theMessage, *pMyNym,
1608  *pServerContract, pMyAccount, 0, // amount (unused here)
1609  pMyAssetContract)) {
1610  bSendCommand = true;
1611  }
1612  else
1613  otErr << "Error processing deposit purse command in "
1614  "ProcessMessage.\n";
1615  }
1616  else if (opt->getFlag("deposittokens")) {
1617  otOut << "(User has instructed to deposit individual cash "
1618  "tokens...)\n";
1619 
1620  // if successful setting up the command payload...
1621 
1623  OTClient::notarizeDeposit, theMessage, *pMyNym,
1624  *pServerContract, pMyAccount)) {
1625  bSendCommand = true;
1626  }
1627  else
1628  otErr << "Error processing deposit cash tokens command in "
1629  "ProcessMessage.\n";
1630  }
1631  else if (opt->getFlag('i') || opt->getFlag("inbox")) {
1632  cerr << "DISPLAY INBOX CONTENTS HERE... (When I code this. What "
1633  "can I "
1634  "say? Use the GUI.)" << endl;
1635  }
1636  else if (opt->getFlag('s') || opt->getFlag("sign")) {
1637  otOut << "(User has instructed to sign a contract...)\n";
1638 
1640  OTClient::signContract, theMessage, *pMyNym, *pServerContract,
1641  nullptr);
1642  }
1643  else if (opt->getFlag('p') || opt->getFlag("purse")) {
1644  cerr << "User wants to display purse contents (not coded yet here.)"
1645  << endl;
1646  }
1647  else if (opt->getFlag("verify")) {
1648  cerr << "User wants to verify a signature on a contract (not coded "
1649  "yet "
1650  "here) " << endl;
1651  }
1652  else if (opt->getFlag("stat")) {
1653  otOut << "User has instructed to display wallet contents...\n";
1654 
1655  OTString strStat;
1656  pWallet->DisplayStatistics(strStat);
1657  otOut << strStat << "\n";
1658  }
1659  else if (opt->getFlag("prompt")) {
1660  otOut << "User has instructed to enter the OT prompt...\n";
1661  }
1662  else if (opt->getFlag('b') || opt->getFlag("balance")) {
1663  otOut << "\n ACCT BALANCE (server-side): "
1664  << pMyAccount->GetBalance() << "\n\n";
1665 
1666  Purse* pPurse = OTAPI_Wrap::OTAPI()->LoadPurse(
1667  theServerID, thePurseAssetTypeID, MY_NYM_ID);
1668  std::unique_ptr<Purse> thePurseAngel(pPurse);
1669  if (nullptr != pPurse)
1670  otOut << " CASH PURSE (client-side): "
1671  << pPurse->GetTotalValue() << "\n";
1672  }
1673  else if (opt->getFlag('r') || opt->getFlag("refresh")) {
1674  otOut << "(User has instructed to download intermediary files "
1675  "for an asset account...)\n";
1676 
1677  // if successful setting up the command payload...
1678 
1680  OTClient::getAccount, theMessage, *pMyNym,
1681  *pServerContract, pMyAccount)) {
1682  bSendCommand = true;
1683  }
1684  else
1685  otErr << "Error processing getAccount command in "
1686  "ProcessMessage.\n";
1687  }
1688  else if (opt->getFlag("refreshnym")) {
1689  otOut << "(User has instructed to download intermediary files "
1690  "for a Nym...)\n";
1691 
1692  // if successful setting up the command payload...
1693 
1695  OTClient::getNymbox, theMessage, *pMyNym,
1696  *pServerContract, nullptr)) {
1697  bSendCommand = true;
1698  }
1699  else
1700  otErr << "Error processing getNymbox command in "
1701  "ProcessMessage.\n";
1702  }
1703 
1704  //
1705  const OTPseudonym* pServerNym = pServerContract->GetContractPublicNym();
1706 
1707  if ((nullptr == pServerNym) ||
1708  (false == pServerNym->VerifyPseudonym())) {
1709  otOut << "The server Nym was nullptr or failed to verify on server "
1710  "contract: " << strServerID << "\n";
1711  return 0;
1712  }
1713  //
1714 
1715  if (bSendCommand && pServerNym->VerifyPseudonym()) {
1716  OTString strEnvelopeContents(theMessage);
1717  OTEnvelope theEnvelope; // Seal the string up into an encrypted
1718  // Envelope
1719  theEnvelope.Seal(*pServerNym, strEnvelopeContents);
1720 
1721  OTAPI_Wrap::OTAPI()->GetTransportCallback()->operator()(
1722  *pServerContract, theEnvelope);
1723 
1724  } // if bSendCommand
1725 
1726  if (!opt->getFlag("prompt")) // If the user selected to enter the OT
1727  // prompt, then we
1728  // drop down below... (otherwise return.)
1729  {
1730  return 0;
1731  }
1732  } // Command line interface (versus below, which is the PROMPT interface.)
1733 
1734  otOut << "\nLOOKING FOR INSTRUCTIONS for the OT COMMAND LINE?\n"
1735  "Try: quit\n"
1736  "Followed by: ot -?\n"
1737  "or: ot -h\n"
1738  "or: ot --help\n"
1739  "\n"
1740  "(NOW ENTERING OT PROMPT) \n"
1741  "See docs/CLIENT-COMMANDS.txt\n\n";
1742 
1743  //
1744  // THE OPEN-TRANSACTIONS PROMPT
1745  //
1746  // OT>
1747  //
1748  // Basically, loop:
1749  //
1750  // 1) Present a prompt, and get a user string of input. Wait for that.
1751  //
1752  // 2) Process it out as an OTMessage to the server. It goes down the pipe.
1753  //
1754  // 3) Sleep for 1 second.
1755  //
1756  // 4) Awake and check for messages to be read in response from the server.
1757  // Loop. As long as there are any responses there, then process and
1758  // handle
1759  // them all.
1760  // Then continue back up to the prompt at step (1).
1761 
1762  OTPseudonym* pMyNym = nullptr;
1763  OTWallet* pWallet = nullptr;
1764  OTServerContract* pServerContract = nullptr;
1765 
1766  // If we got down here, that means there were no commands on the command
1767  // line
1768  // (That's why we dropped into the OT prompt.)
1769  // However, there still may have been OPTIONS -- and if so, we'll go ahead
1770  // and
1771  // load the wallet. (If there were NOT ANY OPTIONS, then we do NOT load the
1772  // wallet,
1773  // although there is a COMMAND for doing that.)
1774  //
1775  if ((str_ServerID.size() > 0) || (str_MyNym.size() > 0)) {
1776  if (false ==
1778  str_ServerID, str_MyNym, pMyNym, pWallet, pServerContract)) {
1779  return 0;
1780  }
1781  }
1782  else
1783  otOut << "\nYou may wish to 'load' then 'stat'.\n"
1784  "(FYI, --server SERVER_ID and --mynym NYM_ID were both "
1785  "valid options.)\n"
1786  "Also, see: ~/.ot/command-line-ot.opt for defaults.\n";
1787 
1788  // Below this point, pWallet is available and loaded, IF opt->HasOptions().
1789  // Otherwise, pWallet is NOT loaded, and we're waiting for the Load command.
1790 
1791  // Below this point, pMyNym MIGHT be a valid pointer (if it was specified),
1792  // or MIGHT be nullptr. Same with pServerContract. (MIGHT be there.)
1793  //
1794 
1795  char buf[200] = "";
1796 
1797  otLog4 << "Starting client loop.\n";
1798 
1799 // Set the logging level for the network transport code.
1800 #ifndef _WIN32
1801 // XmlRpc::setVerbosity(1);
1802 #endif
1803 
1804  for (;;) {
1805  buf[0] = 0; // Making it fresh again.
1806 
1807  // 1) Present a prompt, and get a user string of input. Wait for that.
1808  otOut << "\nOT -- WARNING: This prompt is too low-level for you.\nType "
1809  "'quit', and then try 'opentxs help' and 'opentxs "
1810  "list'.\n\nOT> ";
1811 
1812  if (nullptr ==
1813  fgets(buf, 190, stdin)) // Leaving myself 10 extra bytes at the
1814  // end for safety's sake.
1815  break;
1816 
1817  otOut << ".\n..\n...\n....\n.....\n......\n.......\n........\n........."
1818  "\n..........\n...........\n............\n.............\n";
1819 
1820  // so we can process the user input
1821  std::string strLine = buf;
1822 
1823  // Load wallet.xml
1824  if (strLine.compare(0, 4, "load") == 0) {
1825  otOut << "User has instructed to load wallet.xml...\n";
1826 
1828  str_ServerID, str_MyNym, pMyNym, pWallet,
1829  pServerContract)) {
1830  return 0;
1831  }
1832 
1833  continue;
1834  }
1835  else if ('\0' == buf[0]) {
1836  continue;
1837  }
1838  else if (strLine.compare(0, 4, "test") == 0) {
1839  std::string strScript = "print(\"Hello, world\")";
1840  OT_ME madeEasy;
1842  madeEasy.ExecuteScript_ReturnVoid(strScript, "hardcoded");
1843 
1844  /*
1845  // TODO: Make sure there's no issues with a known
1846  plaintext attack.
1847  // (Not here, but I am doing a similar thing in
1848  OTASCIIArmor to maintain a
1849  minimum size,
1850  // due to a bug in some other library that I can't
1851  recall at this time.)
1852  //
1853  const char * szBlah = "Transaction processor
1854  featuring Untraceable Digital
1855  Cash, "
1856  "Anonymous Numbered Accounts, Triple-Signed
1857  Receipts, Basket Currencies,
1858  and Signed "
1859  "XML Contracts. Also supports cheques, invoices,
1860  payment plans, markets
1861  with trades, "
1862  "and other instruments... it's like PGP for
1863  Money.... Uses OpenSSL and
1864  Lucre blinded tokens.\n";
1865 
1866  OTASCIIArmor theArmoredText(szBlah);
1867  otOut << "Armored text:\n" << theArmoredText << "\n";
1868 
1869  OTString theFixedText(theArmoredText);
1870  otOut << "Uncompressed, etc text:\n" << theFixedText << "\n";
1871  */
1872 
1873  continue;
1874  }
1875  else if (strLine.compare(0, 8, "clearreq") ==
1876  0) // clear request numbers
1877  {
1878  if (nullptr == pMyNym) {
1879  otOut << "No Nym yet available. Try 'load'.\n";
1880  continue;
1881  }
1882 
1883  OTString strServerID;
1884  pServerContract->GetIdentifier(strServerID);
1885 
1886  otOut << "You are trying to mess around with your (clear your) "
1887  "request numbers.\n"
1888  "Enter the relevant server ID [" << strServerID << "]: ";
1889 
1890  std::string str_ServerID = OT_CLI_ReadLine();
1891 
1892  const OTString strReqNumServerID((str_ServerID.size() > 0)
1893  ? str_ServerID.c_str()
1894  : strServerID.Get());
1895 
1896  pMyNym->RemoveReqNumbers(&strReqNumServerID);
1897 
1898  pMyNym->SaveSignedNymfile(*pMyNym);
1899 
1900  otOut << "Successfully removed request number for server "
1901  << strReqNumServerID << ". Saving nym...\n";
1902  continue;
1903  }
1904  else if (strLine.compare(0, 5, "clear") == 0) {
1905  if (nullptr == pMyNym) {
1906  otOut << "No Nym yet available. Try 'load'.\n";
1907  continue;
1908  }
1909 
1910  OTString strServerID;
1911  pServerContract->GetIdentifier(strServerID);
1912 
1913  otOut << "You are trying to mess around with your (clear your) "
1914  "transaction numbers.\n"
1915  "Enter the relevant server ID [" << strServerID << "]: ";
1916 
1917  std::string str_ServerID = OT_CLI_ReadLine();
1918 
1919  const OTString strTransNumServerID((str_ServerID.size() > 0)
1920  ? str_ServerID.c_str()
1921  : strServerID.Get());
1922 
1923  pMyNym->RemoveAllNumbers(&strTransNumServerID,
1924  true); // bRemoveHighestNum = true.
1925  pMyNym->SaveSignedNymfile(*pMyNym);
1926 
1927  otOut << "Successfully removed all issued and transaction "
1928  "numbers for server " << strTransNumServerID
1929  << ". Saving nym...\n";
1930  continue;
1931  }
1932  else if (strLine.compare(0, 7, "decrypt") == 0) {
1933  if (nullptr == pMyNym) {
1934  otOut << "No Nym yet available to decrypt with.\n";
1935  continue;
1936  }
1937 
1938  otOut << "Enter text to be decrypted:\n> ";
1939 
1940  OTASCIIArmor theArmoredText;
1941  char decode_buffer[200]; // Safe since we only read sizeof - 1
1942 
1943  do {
1944  decode_buffer[0] = 0;
1945  if (nullptr !=
1946  fgets(decode_buffer, sizeof(decode_buffer) - 1, stdin)) {
1947  theArmoredText.Concatenate("%s\n", decode_buffer);
1948  otOut << "> ";
1949  }
1950  else {
1951  break;
1952  }
1953  } while (strlen(decode_buffer) > 1);
1954 
1955  OTEnvelope theEnvelope(theArmoredText);
1956  OTString strDecodedText;
1957 
1958  theEnvelope.Open(*pMyNym, strDecodedText);
1959 
1960  otOut << "\n\nDECRYPTED TEXT:\n\n" << strDecodedText << "\n\n";
1961 
1962  continue;
1963  }
1964  else if (strLine.compare(0, 6, "decode") == 0) {
1965  otOut << "Enter text to be decoded:\n> ";
1966 
1967  OTASCIIArmor theArmoredText;
1968  char decode_buffer[200]; // Safe since we only read sizeof - 1.
1969 
1970  do {
1971  decode_buffer[0] = 0;
1972  if (nullptr !=
1973  fgets(decode_buffer, sizeof(decode_buffer) - 1, stdin)) {
1974  theArmoredText.Concatenate("%s\n", decode_buffer);
1975  otOut << "> ";
1976  }
1977  else {
1978  break;
1979  }
1980 
1981  } while (strlen(decode_buffer) > 1);
1982 
1983  OTString strDecodedText(theArmoredText);
1984 
1985  otOut << "\n\nDECODED TEXT:\n\n" << strDecodedText << "\n\n";
1986 
1987  continue;
1988  }
1989  else if (strLine.compare(0, 6, "encode") == 0) {
1990  otOut << "Enter text to be ascii-encoded (terminate with ~ on a "
1991  "new line):\n> ";
1992 
1993  OTString strDecodedText;
1994  char decode_buffer[200]; // Safe since we only read sizeof - 1.
1995 
1996  do {
1997  decode_buffer[0] = 0;
1998 
1999  if ((nullptr !=
2000  fgets(decode_buffer, sizeof(decode_buffer) - 1, stdin)) &&
2001  (decode_buffer[0] != '~')) {
2002  strDecodedText.Concatenate("%s", decode_buffer);
2003  otOut << "> ";
2004  }
2005  else {
2006  break;
2007  }
2008 
2009  } while (decode_buffer[0] != '~');
2010 
2011  OTASCIIArmor theArmoredText(strDecodedText);
2012 
2013  otOut << "\n\nENCODED TEXT:\n\n" << theArmoredText << "\n\n";
2014 
2015  continue;
2016  }
2017  else if (strLine.compare(0, 4, "hash") == 0) {
2018  otOut << "Enter text to be hashed (terminate with ~ on a "
2019  "new line):\n> ";
2020 
2021  OTString strDecodedText;
2022  char decode_buffer[200]; // Safe since we only read sizeof - 1.
2023 
2024  do {
2025  decode_buffer[0] = 0;
2026 
2027  if ((nullptr !=
2028  fgets(decode_buffer, sizeof(decode_buffer) - 1, stdin)) &&
2029  (decode_buffer[0] != '~')) {
2030  strDecodedText.Concatenate("%s\n", decode_buffer);
2031  otOut << "> ";
2032  }
2033  else {
2034  break;
2035  }
2036 
2037  } while (decode_buffer[0] != '~');
2038 
2039  std::string str_Trim(strDecodedText.Get());
2040  std::string str_Trim2 = OTString::trim(str_Trim);
2041  strDecodedText.Set(str_Trim2.c_str());
2042 
2043  OTIdentifier theIdentifier;
2044  theIdentifier.CalculateDigest(strDecodedText);
2045 
2046  OTString strHash(theIdentifier);
2047 
2048  otOut << "\n\nMESSAGE DIGEST:\n\n" << strHash << "\n\n";
2049 
2050  continue;
2051  }
2052  else if (strLine.compare(0, 4, "stat") == 0) {
2053  otOut << "User has instructed to display wallet contents...\n";
2054 
2055  if (pWallet) {
2056  OTString strStat;
2057  pWallet->DisplayStatistics(strStat);
2058  otOut << strStat << "\n";
2059  }
2060  else
2061  otOut << "No wallet is loaded...\n";
2062 
2063  continue;
2064  }
2065  else if (strLine.compare(0, 4, "help") == 0) {
2066  otOut << "User has instructed to display the help file...\nPlease "
2067  "see this file: docs/CLIENT_COMMANDS.txt\n";
2068 
2069  continue;
2070  }
2071  else if (strLine.compare(0, 4, "quit") == 0) {
2072  otOut << "User has instructed to exit the wallet...\n";
2073 
2074  break;
2075  }
2076 
2077  /*
2078  --myacct (ACCT ID)
2079  --mynym (NYM ID)
2080  --mypurse (ASSET TYPE ID)
2081 
2082  --toacct (ACCT ID)
2083  --tonym (NYM ID)
2084  --topurse (ASSET TYPE ID)
2085 
2086  OTPseudonym * GetNymByIDPartialMatch(const
2087  std::string PARTIAL_ID);
2088  OTServerContract * GetServerContractPartialMatch(const
2089  std::string
2090  PARTIAL_ID);
2091  OTAssetContract * GetAssetContractPartialMatch(const
2092  std::string
2093  PARTIAL_ID);
2094  OTAccount * GetAccountPartialMatch(const std::string
2095  PARTIAL_ID);
2096  */
2097 
2098  if (nullptr == pServerContract) {
2099  otOut << "Unable to find a server contract. Please restart using "
2100  "the option: --server SERVER_ID\n"
2101  "(Where SERVER_ID is the server ID. Partial matches ARE "
2102  "accepted.)\n";
2103  continue;
2104  }
2105 
2106  // You can't just connect to any hostname and port.
2107  // Instead, you give me the Server Contract, and *I'll* look up all that
2108  // stuff FOR you...
2109  // (We verify this up here, but use it at the bottom of the function
2110  // once
2111  // the message is set up.)
2112  //
2113  // int32_t nServerPort = 0;
2114  // OTString strServerHostname;
2115  // if (!pServerContract->GetConnectInfo(strServerHostname,
2116  // nServerPort))
2117  // {
2118  // otErr << "Failed retrieving connection info from"
2119  // "server contract.\n";
2120  // continue;
2121  // }
2122 
2123  // I put this here too since I think it's required in all cases below.
2124  //
2125  if (nullptr ==
2126  pMyNym) // Todo maybe move this check to the commands below
2127  // (ONLY the ones that use a nym.)
2128  {
2129  otOut
2130  << "Unable to find My Nym. Please restart and use the option:\n"
2131  " --mynym USER_ID\n"
2132  "(Where USER_ID is the Nym's ID. Partial matches ARE "
2133  "accepted.)\n";
2134  continue;
2135  }
2136 
2137  bool bSendCommand = false; // Determines whether to actually send a
2138  // message to the server.
2139 
2140  OTMessage theMessage;
2141 
2142  // If we can match the user's request to a client command,
2143  // AND theClient object is able to process that request into
2144  // theMessage, then we send it down the pipe.
2145 
2146  // In lieu of maintaining a constant connection to the server, in RPC
2147  // mode,
2148  // the
2149  // client updates its internal "connection" object to make sure the
2150  // right
2151  // pointers
2152  // are in place (since in RPC mode, each message could be from a
2153  // different
2154  // nym
2155  // and to a different server.)
2156  //
2158  *pServerContract, *pMyNym,
2159  OTAPI_Wrap::OTAPI()->GetTransportCallback());
2160  // NOTE -- This MAY be unnecessary for ProcessUserCommand (since these
2161  // args
2162  // are passed
2163  // in there already) but it's definitely necessary soon after for
2164  // ProcessServerReply()
2165  // (which comes next.)
2166 
2167  // 'check server ID' command
2168  if (buf[0] == 'c') {
2169  otOut << "(User has instructed to send a checkServerID command "
2170  "to the server...)\n";
2171 
2172  // if successful setting up the command payload...
2173 
2174  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2175  OTClient::checkServerID, theMessage, *pMyNym,
2176  *pServerContract,
2177  nullptr)) // nullptr pAccount on this command (so far).
2178  {
2179  bSendCommand = true;
2180  }
2181  else
2182  otErr << "Error processing checkServerID command in "
2183  "ProcessMessage: " << buf[0] << "\n";
2184 
2185  }
2186 
2187  // register new user account
2188  else if (buf[0] == 'r') {
2189  otOut << "(User has instructed to send a createUserAccount "
2190  "command to the server...)\n";
2191 
2192  // if successful setting up the command payload...
2193 
2194  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2195  OTClient::createUserAccount, theMessage, *pMyNym,
2196  *pServerContract,
2197  nullptr)) // nullptr pAccount on this command.
2198  {
2199  bSendCommand = true;
2200  }
2201  else
2202  otErr << "Error processing createUserAccount command in "
2203  "ProcessMessage: " << buf[0] << "\n";
2204 
2205  }
2206 
2207  // ALL MESSAGES BELOW THIS POINT SHOULD ATTACH A REQUEST NUMBER IF THEY
2208  // EXPECT THE SERVER TO PROCESS THEM.
2209  // (Handled inside ProcessUserCommand)
2210 
2211  // checkUser
2212  else if (buf[0] == 'u') {
2213  otOut << "(User has instructed to send a checkUser command to "
2214  "the server...)\n";
2215 
2216  // if successful setting up the command payload...
2217 
2218  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2219  OTClient::checkUser, theMessage, *pMyNym,
2220  *pServerContract,
2221  nullptr)) // nullptr pAccount on this command.
2222  {
2223  bSendCommand = true;
2224  }
2225  else
2226  otErr << "Error processing checkUser command in "
2227  "ProcessMessage: " << buf[0] << "\n";
2228 
2229  }
2230 
2231  // register new asset account
2232  else if (buf[0] == 'a') {
2233  otOut << "(User has instructed to send a createAccount command "
2234  "to the server...)\n";
2235 
2236  // if successful setting up the command payload...
2237 
2238  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2239  OTClient::createAccount, theMessage, *pMyNym,
2240  *pServerContract,
2241  nullptr)) // nullptr pAccount on this command.
2242  {
2243  bSendCommand = true;
2244  }
2245  else
2246  otErr << "Error processing createAccount command in "
2247  "ProcessMessage: " << buf[0] << "\n";
2248 
2249  }
2250 
2251  // issue a new asset type
2252  else if (!strcmp(buf, "issue\n")) {
2253  otOut << "(User has instructed to send an issueAssetType command "
2254  "to the server...)\n";
2255 
2256  // if successful setting up the command payload...
2257 
2258  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2259  OTClient::issueAssetType, theMessage, *pMyNym,
2260  *pServerContract,
2261  nullptr)) // nullptr pAccount on this command.
2262  {
2263  bSendCommand = true;
2264  }
2265  else
2266  otErr << "Error processing issueAssetType command in "
2267  "ProcessMessage: " << buf << "\n";
2268 
2269  }
2270 
2271  // issue a new basket asset type
2272  else if (!strcmp(buf, "basket\n")) {
2273  otOut << "(User has instructed to send an issueBasket command to "
2274  "the server...)\n";
2275 
2276  // if successful setting up the command payload...
2277 
2278  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2279  OTClient::issueBasket, theMessage, *pMyNym,
2280  *pServerContract,
2281  nullptr)) // nullptr pAccount on this command.
2282  {
2283  bSendCommand = true;
2284  }
2285  else
2286  otErr << "Error processing issueBasket command in "
2287  "ProcessMessage: " << buf << "\n";
2288 
2289  }
2290 
2291  // exchange in/out of a basket currency
2292  else if (!strcmp(buf, "exchange\n")) {
2293  otOut << "(User has instructed to send an exchangeBasket command "
2294  "to the server...)\n";
2295 
2296  // if successful setting up the command payload...
2297 
2298  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2299  OTClient::exchangeBasket, theMessage, *pMyNym,
2300  *pServerContract,
2301  nullptr)) // nullptr pAccount on this command.
2302  {
2303  bSendCommand = true;
2304  }
2305  else
2306  otErr << "Error processing exchangeBasket command in "
2307  "ProcessMessage: " << buf << "\n";
2308 
2309  }
2310 
2311  // make an offer and put it onto a market.
2312  else if (!strcmp(buf, "offer\n")) {
2313  otOut << "(User has instructed to send a marketOffer command to "
2314  "the server...)\n";
2315 
2316  // if successful setting up the command payload...
2317 
2318  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2319  OTClient::marketOffer, theMessage, *pMyNym,
2320  *pServerContract,
2321  nullptr)) // nullptr pAccount on this command.
2322  {
2323  bSendCommand = true;
2324  }
2325  else
2326  otErr << "Error processing marketOffer command in "
2327  "ProcessMessage: " << buf << "\n";
2328 
2329  }
2330 
2331  // Set a Server Contract's client-side name (merely a label.)
2332  else if (!strcmp(buf, "setservername\n")) {
2333  otOut << "(User wants to set a Server Contract's "
2334  "client-side name...)\n";
2335 
2336  // if successful setting up the command payload...
2337 
2338  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2339  OTClient::setServerName, theMessage, *pMyNym,
2340  *pServerContract,
2341  nullptr)) // nullptr pAccount on this command.
2342  {
2343  // bSendCommand = true; //
2344  // No
2345  // message needed. Local data only.
2346  }
2347  }
2348 
2349  // Set an Asset Contract's client-side name (merely a label.)
2350  else if (!strcmp(buf, "setassetname\n")) {
2351  otOut << "(User wants to set an Asset Contract's "
2352  "client-side name...)\n";
2353 
2354  // if successful setting up the command payload...
2355 
2356  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2357  OTClient::setAssetName, theMessage, *pMyNym,
2358  *pServerContract,
2359  nullptr)) // nullptr pAccount on this command.
2360  {
2361  // bSendCommand = true; //
2362  // No
2363  // message needed. Local data only.
2364  }
2365  }
2366 
2367  // Set a Nym's client-side name (merely a label.)
2368  else if (!strcmp(buf, "setnymname\n")) {
2369  otOut << "(User wants to set a Nym's client-side name...)\n";
2370 
2371  // if successful setting up the command payload...
2372 
2373  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2374  OTClient::setNymName, theMessage, *pMyNym,
2375  *pServerContract,
2376  nullptr)) // nullptr pAccount on this command.
2377  {
2378  // bSendCommand = true; //
2379  // No
2380  // message needed. Local data only.
2381  }
2382  }
2383 
2384  // Set an Asset Account's client-side name (merely a label.)
2385  else if (!strcmp(buf, "setaccountname\n")) {
2386  otOut << "(User wants to set an Asset Account's client-side "
2387  "name...)\n";
2388 
2389  // if successful setting up the command payload...
2390 
2391  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2392  OTClient::setAccountName, theMessage, *pMyNym,
2393  *pServerContract,
2394  nullptr)) // nullptr pAccount on this command.
2395  {
2396  // bSendCommand = true; //
2397  // No
2398  // message needed. Local data only.
2399  }
2400 
2401  }
2402 
2403  // sign contract
2404  // This doesn't message the server, but it DOES require the user's Nym
2405  // to be loaded.
2406  else if (!strcmp(buf, "signcontract\n")) {
2407  otOut << "(User has instructed to sign a contract...)\n";
2408 
2410  OTClient::signContract, theMessage, *pMyNym, *pServerContract,
2411  nullptr);
2412  continue;
2413  }
2414 
2415  // sendUserMessage
2416  else if (buf[0] == 's') {
2417  otOut << "(User has instructed to send a sendUserMessage command "
2418  "to the server...)\n";
2419 
2420  // if successful setting up the command payload...
2421 
2422  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2423  OTClient::sendUserMessage, theMessage, *pMyNym,
2424  *pServerContract,
2425  nullptr)) // nullptr pAccount on this command.
2426  {
2427  bSendCommand = true;
2428  }
2429  else
2430  otErr << "Error processing sendUserMessage command in "
2431  "ProcessMessage: " << buf[0] << "\n";
2432 
2433  }
2434 
2435  // process nymbox
2436  else if (strLine.compare(0, 2, "py") == 0) {
2437  otOut << "(User has instructed to send a processNymbox command "
2438  "to the server...)\n";
2439 
2440  // if successful setting up the command payload...
2441 
2443  OTClient::processEntireNymbox, theMessage, *pMyNym,
2444  *pServerContract,
2445  nullptr)) // nullptr pAccount on this command.
2446  {
2447  bSendCommand = true;
2448  }
2449  else
2450  otErr << "Error in processNymbox command in ProcessMessage: "
2451  << strLine << "\n";
2452 
2453  }
2454 
2455  // get nymbox
2456  else if (buf[0] == 'y') {
2457  otOut << "(User has instructed to send a getNymbox command to "
2458  "the server...)\n";
2459 
2460  // if successful setting up the command payload...
2461 
2463  OTClient::getNymbox, theMessage, *pMyNym,
2464  *pServerContract,
2465  nullptr)) // nullptr pAccount on this command.
2466  {
2467  bSendCommand = true;
2468  }
2469  else
2470  otErr << "Error processing getNymbox command in "
2471  "ProcessMessage: " << buf[0] << "\n";
2472 
2473  }
2474 
2475  // Nym, Account, Server ID, Server Contract
2476 
2477  // process inbox
2478  else if (strLine.compare(0, 2, "pi") == 0) {
2479  otOut << "(User has instructed to send a processInbox command to "
2480  "the server...)\n";
2481 
2482  // if successful setting up the command payload...
2483 
2485  OTClient::processEntireInbox, theMessage, *pMyNym,
2486  *pServerContract, nullptr)) // have to allow this to be
2487  // defaulted at some point...
2488  {
2489  bSendCommand = true;
2490  }
2491  else
2492  otErr << "Error in processInbox command in ProcessMessage: "
2493  << strLine << "\n";
2494 
2495  }
2496 
2497  // get inbox
2498  else if (buf[0] == 'i') {
2499  otOut << "(User has instructed to send a getInbox command to the "
2500  "server...)\n";
2501 
2502  // if successful setting up the command payload...
2503 
2505  OTClient::getInbox, theMessage, *pMyNym,
2506  *pServerContract, nullptr)) {
2507  bSendCommand = true;
2508  }
2509  else
2510  otErr << "Error processing getInbox command in ProcessMessage: "
2511  << buf[0] << "\n";
2512 
2513  }
2514 
2515  // get outbox
2516  else if (buf[0] == 'o') {
2517  otOut << "(User has instructed to send a getOutbox command to "
2518  "the server...)\n";
2519 
2520  // if successful setting up the command payload...
2521 
2523  OTClient::getOutbox, theMessage, *pMyNym,
2524  *pServerContract, nullptr)) {
2525  bSendCommand = true;
2526  }
2527  else
2528  otErr << "Error processing getOutbox command in "
2529  "ProcessMessage: " << buf[0] << "\n";
2530 
2531  }
2532 
2533  // deposit cheque
2534  else if (buf[0] == 'q') {
2535  otOut << "User has instructed to deposit a cheque...\n";
2536 
2537  // if successful setting up the command payload...
2538 
2540  OTClient::notarizeCheque, theMessage, *pMyNym,
2541  *pServerContract, nullptr)) {
2542  bSendCommand = true;
2543  }
2544  else
2545  otErr << "Error processing deposit cheque command in "
2546  "ProcessMessage: " << buf[0] << "\n";
2547 
2548  }
2549 
2550  // deposit purse
2551  else if (buf[0] == 'p') {
2552  otOut << "(User has instructed to deposit a purse "
2553  "containing cash...)\n";
2554 
2555  // if successful setting up the command payload...
2556 
2558  OTClient::notarizePurse, theMessage, *pMyNym,
2559  *pServerContract, nullptr)) {
2560  bSendCommand = true;
2561  }
2562  else
2563  otErr << "Error processing deposit command in ProcessMessage: "
2564  << buf[0] << "\n";
2565 
2566  }
2567 
2568  // deposit tokens
2569  else if (buf[0] == 'd') {
2570  otOut << "(User has instructed to deposit cash tokens...)\n";
2571 
2572  // if successful setting up the command payload...
2573 
2575  OTClient::notarizeDeposit, theMessage, *pMyNym,
2576  *pServerContract, nullptr)) {
2577  bSendCommand = true;
2578  }
2579  else
2580  otErr << "Error processing deposit command in ProcessMessage: "
2581  << buf[0] << "\n";
2582 
2583  }
2584 
2585  // withdraw voucher
2586  else if (buf[0] == 'v') {
2587  otOut << "User has instructed to withdraw a voucher (like a "
2588  "cashier's cheque)...\n";
2589 
2590  // if successful setting up the command payload...
2591 
2593  OTClient::withdrawVoucher, theMessage, *pMyNym,
2594  *pServerContract,
2595  nullptr)) // nullptr pAccount on this command.
2596  {
2597  bSendCommand = true;
2598  }
2599  else
2600  otErr << "Error processing withdraw voucher command in "
2601  "ProcessMessage: " << buf[0] << "\n";
2602 
2603  }
2604 
2605  // withdraw cash
2606  else if (buf[0] == 'w') {
2607  otOut << "(User has instructed to withdraw cash...)\n";
2608 
2609  // if successful setting up the command payload...
2610 
2612  OTClient::notarizeWithdrawal, theMessage, *pMyNym,
2613  *pServerContract,
2614  nullptr)) // nullptr pAccount on this command.
2615  {
2616  bSendCommand = true;
2617  }
2618  else
2619  otErr << "Error processing withdraw command in ProcessMessage: "
2620  << buf[0] << "\n";
2621 
2622  }
2623 
2624  // activate payment plan
2625  else if (!strcmp(buf, "activate\n")) {
2626  otOut << "User has instructed to activate a payment plan...\n";
2627 
2628  // if successful setting up the command payload...
2629 
2631  OTClient::paymentPlan, theMessage, *pMyNym,
2632  *pServerContract,
2633  nullptr)) // nullptr pAccount on this command.
2634  {
2635  bSendCommand = true;
2636  }
2637  else
2638  otErr << "Error processing payment plan command in "
2639  "ProcessMessage: " << buf[0] << "\n";
2640 
2641  }
2642 
2643  // get account
2644  else if (!strcmp(buf, "get\n")) {
2645  otOut << "(User has instructed to send a getAccount command to "
2646  "the server...)\n";
2647 
2648  // if successful setting up the command payload...
2649 
2651  OTClient::getAccount, theMessage, *pMyNym,
2652  *pServerContract,
2653  nullptr)) // nullptr pAccount on this command.
2654  {
2655  bSendCommand = true;
2656  }
2657  else
2658  otErr << "Error processing getAccount command in "
2659  "ProcessMessage: " << buf[0] << "\n";
2660 
2661  }
2662 
2663  // get contract
2664  else if (!strcmp(buf, "getcontract\n")) {
2665  otOut << "(User has instructed to send a getContract command to "
2666  "the server...)\n";
2667 
2668  // if successful setting up the command payload...
2669 
2671  OTClient::getContract, theMessage, *pMyNym,
2672  *pServerContract,
2673  nullptr)) // nullptr pAccount on this command.
2674  {
2675  bSendCommand = true;
2676  }
2677  else
2678  otErr << "Error processing getContract command in "
2679  "ProcessMessage: " << buf[0] << "\n";
2680 
2681  }
2682  else if (!strcmp(buf, "propose\n")) {
2683  otOut << "(User has instructed to propose a payment plan...)\n";
2684 
2686  OTClient::proposePaymentPlan, theMessage, *pMyNym,
2687  *pServerContract,
2688  nullptr); // User owns Merchant (recipient) account
2689  continue;
2690  }
2691  else if (!strcmp(buf, "confirm\n")) {
2692  otOut << "(User has instructed to confirm a payment plan...)\n";
2693 
2695  OTClient::confirmPaymentPlan, theMessage, *pMyNym,
2696  *pServerContract,
2697  nullptr); // the account info is already on the plan, right?
2698  continue;
2699  }
2700  else if (!strcmp(buf, "cheque\n")) {
2701  otOut << "(User has instructed to write a cheque...)\n";
2702 
2704  OTClient::writeCheque, theMessage, *pMyNym, *pServerContract,
2705  nullptr); // It will ascertain the account inside the call.
2706  continue;
2707  }
2708 
2709  // get mint
2710  else if (!strcmp(buf, "getmint\n")) {
2711  otOut << "(User has instructed to send a getMint command "
2712  "to the server...)\n";
2713 
2714  // if successful setting up the command payload...
2715 
2716  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2717  OTClient::getMint, theMessage, *pMyNym,
2718  *pServerContract,
2719  nullptr)) // nullptr pAccount on this command.
2720  {
2721  bSendCommand = true;
2722  }
2723  else
2724  otErr << "Error processing getMint command in ProcessMessage: "
2725  << buf[0] << "\n";
2726 
2727  }
2728 
2729  // notarize transfer
2730  else if (buf[0] == 't') {
2731  otOut << "(User has instructed to send a Transfer command "
2732  "(Notarize Transactions) to the server...)\n";
2733 
2734  // if successful setting up the command payload...
2735 
2736  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2737  OTClient::notarizeTransfer, theMessage, *pMyNym,
2738  *pServerContract,
2739  nullptr)) // nullptr pAccount on this command.
2740  {
2741  bSendCommand = true;
2742  }
2743  else
2744  otErr << "Error processing notarizeTransactions command in "
2745  "ProcessMessage: " << buf[0] << "\n";
2746 
2747  }
2748 
2749  // getRequest
2750  else if (buf[0] == 'g') {
2751  otOut << "(User has instructed to send a getRequest command to "
2752  "the server...)\n";
2753 
2754  // if successful setting up the command payload...
2755 
2756  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2757  OTClient::getRequest, theMessage, *pMyNym,
2758  *pServerContract,
2759  nullptr)) // nullptr pAccount on this command.
2760  {
2761  bSendCommand = true;
2762  }
2763  else
2764  otErr << "Error processing getRequest command in "
2765  "ProcessMessage: " << buf[0] << "\n";
2766 
2767  }
2768 
2769  // getTransactionNum
2770  else if (buf[0] == 'n') {
2771  // I just coded (here) for myself a secret option (for testing)...
2772  // Optionally instead of JUST 'n', I can put n <number>, (without
2773  // brackets) and
2774  // this code will add that number to my list of issued and
2775  // transaction
2776  // numbers.
2777  // I already have the ability to clear the list, so now I can add
2778  // numbers
2779  // to it as well.
2780  // (Which adds to both lists.)
2781  // I can also remove a number from the transaction list but LEAVE it
2782  // on
2783  // the issued list,
2784  // for example by writing a cheque and throwing it away.
2785  //
2786  // This code is for testing and allows me to find and patch any
2787  // problems
2788  // without
2789  // having to re-create my data each time -- speeds up debugging.
2790  //
2791  int64_t lTransactionNumber =
2792  ((strlen(buf) > 2) ? atol(&(buf[2])) : 0);
2793 
2794  if (lTransactionNumber > 0) {
2795  OTString strServerID;
2796  pServerContract->GetIdentifier(strServerID);
2797 
2798  otOut << "You are trying to mess around with your (add to "
2799  "your) transaction numbers.\n"
2800  "Enter the relevant server ID [" << strServerID
2801  << "]: ";
2802 
2803  std::string str_ServerID = OT_CLI_ReadLine();
2804 
2805  const OTString strTransNumServerID((str_ServerID.size() > 0)
2806  ? str_ServerID.c_str()
2807  : strServerID.Get());
2808 
2809  pMyNym->AddTransactionNum(*pMyNym, strTransNumServerID,
2810  lTransactionNumber,
2811  true); // bool bSave=true
2812 
2813  otOut << "Transaction number " << lTransactionNumber
2814  << " added to both lists "
2815  "(on client side.)\n";
2816  }
2817  else {
2818  otOut << "(User has instructed to send a getTransactionNum "
2819  "command to the server...)\n";
2820 
2821  // if successful setting up the command payload...
2822 
2823  if (0 < OTAPI_Wrap::OTAPI()->GetClient()->ProcessUserCommand(
2824  OTClient::getTransactionNum, theMessage, *pMyNym,
2825  *pServerContract,
2826  nullptr)) // nullptr pAccount on this command.
2827  {
2828  bSendCommand = true;
2829  }
2830  else
2831  otErr << "Error processing getTransactionNum command in "
2832  "ProcessMessage: " << buf[0] << "\n";
2833  }
2834 
2835  }
2836  else {
2837  {
2838  // gDebugLog.Write("unknown user command in ProcessMessage in
2839  // main.cpp");
2840  otOut << "\n";
2841  // otErr << "unknown user command in ProcessMessage in main.cpp:
2842  // " << buf[0] << "\n";
2843  }
2844  continue;
2845  }
2846 
2847  const OTPseudonym* pServerNym = pServerContract->GetContractPublicNym();
2848 
2849  if (bSendCommand && (nullptr != pServerNym) &&
2850  pServerNym->VerifyPseudonym()) {
2851  OTString strEnvelopeContents(theMessage);
2852  OTEnvelope theEnvelope;
2853  theEnvelope.Seal(*pServerNym, strEnvelopeContents);
2854 
2855  OTAPI_Wrap::OTAPI()->GetTransportCallback()->operator()(
2856  *pServerContract, theEnvelope);
2857 
2858  } // if bSendCommand
2859  } // for
2860 
2861  otOut << "Exiting OT prompt.\n";
2862 
2863  // NOTE: Cleanup is handled via a nested class at the top of this main
2864  // function.
2865 
2866  return 0;
2867 }
OTLOG_IMPORT OTLogStream otLog4
EXPORT bool SetFocusToServerAndNym(OTServerContract &theServerContract, OTPseudonym &theNym, TransportCallback *pCallback) const
Definition: OTClient.cpp:13747
static EXPORT bool AppCleanup()
Definition: OTAPI.cpp:189
OTClient * GetClient() const
EXPORT bool CalculateDigest(const OTData &dataInput)
EXPORT void ExecuteScript_ReturnVoid(const std::string &str_Code, std::string str_DisplayName="<BLANK>")
Definition: OT_ME.cpp:1202
EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
EXPORT OTAccount * GetAccountPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:613
EXPORT static OT_OTAPI_OT void CopyVariables()
EXPORT const OTIdentifier & GetAssetTypeID() const
Definition: OTAccount.cpp:449
EXPORT OTAssetContract * GetAssetContract(const OTIdentifier &theContractID)
Definition: OTWallet.cpp:1203
EXPORT int64_t GetBalance() const
Definition: OTAccount.cpp:664
EXPORT TransportCallback * GetTransportCallback() const
EXPORT OTWallet * GetWallet(const char *szFuncName=nullptr) const
bool SetupPointersForWalletMyNymAndServerContract(std::string &str_ServerID, std::string &str_MyNym, OTPseudonym *&pMyNym, OTWallet *&pWallet, OTServerContract *&pServerContract)
Definition: main.cpp:192
EXPORT OTPseudonym * GetNymByIDPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:291
OTLOG_IMPORT OTLogStream otOut
EXPORT void DisplayStatistics(OTString &strOutput)
Definition: OTWallet.cpp:457
EXPORT bool GetAccount(int32_t iIndex, OTIdentifier &THE_ID, OTString &THE_NAME)
Definition: OTWallet.cpp:431
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
EXPORT int32_t ProcessUserCommand(OT_CLIENT_CMD_TYPE requestedCommand, OTMessage &theMessage, OTPseudonym &theNym, const OTServerContract &theServer, const OTAccount *pAccount=nullptr, int64_t lTransactionAmount=0, OTAssetContract *pMyAssetContract=nullptr, const OTIdentifier *pHisNymID=nullptr, const OTIdentifier *pHisAcctID=nullptr)
Definition: OTClient.cpp:8905
EXPORT bool Open(const OTPseudonym &theRecipient, OTString &theOutput, const OTPasswordData *pPWData=nullptr)
Definition: OTEnvelope.cpp:581
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
EXPORT bool Seal(const OTPseudonym &theRecipient, const OTString &theInput)
Definition: OTEnvelope.cpp:521
EXPORT bool VerifyPseudonym() const
static EXPORT bool RelativeToCanonical(OTString &out_strCanonicalPath, const OTString &strBasePath, const OTString &strRelativePath)
Definition: OTPaths.cpp:1280
EXPORT bool Exists() const
Definition: OTString.cpp:1035
static EXPORT const OTString & AppDataFolder()
Definition: OTPaths.cpp:254
static EXPORT void Output(const int32_t &nLogLevel, const std::string &strOutput)
Definition: OTAPI.cpp:274
EXPORT const OTPseudonym * GetContractPublicNym() const
Definition: OTContract.cpp:413
EXPORT bool LoadWallet() const
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT bool AddTransactionNum(OTPseudonym &SIGNER_NYM, const OTString &strServerID, int64_t lTransNum, bool bSave)
EXPORT std::string OT_CLI_ReadLine()
Definition: Helpers.hpp:144
void SetRunningAsScript()
Definition: OTClient.hpp:196
EXPORT OTPseudonym * GetNymByID(const OTIdentifier &NYM_ID)
Definition: OTWallet.cpp:275
#define OT_OPTIONS_FILE_DEFAULT
Definition: main.cpp:168
void HandleCommandLineArguments(int32_t argc, char *argv[], AnyOption *opt)
Definition: main.cpp:286
EXPORT Purse * LoadPurse(const OTIdentifier &SERVER_ID, const OTIdentifier &ASSET_ID, const OTIdentifier &USER_ID, const OTString *pstrDisplay=nullptr) const
#define OT_ASSERT(x)
Definition: Assert.hpp:150
int64_t GetTotalValue() const
Definition: Purse.hpp:292
EXPORT OTAssetContract * GetAssetContractPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:1218
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
static EXPORT bool AppInit()
Definition: OTAPI.cpp:179
OTLOG_IMPORT OTLogStream otInfo
virtual EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
Definition: OTContract.cpp:317
OTLOG_IMPORT OTLogStream otWarn
EXPORT const char * Get() const
Definition: OTString.cpp:1045
OTLOG_IMPORT OTLogStream otErr
EXPORT int32_t ExecuteScript_ReturnInt(const std::string &str_Code, std::string str_DisplayName="<BLANK>")
Definition: OT_ME.cpp:1185
EXPORT void AddVariable(const std::string &str_var_name, OTVariable &theVar)
Definition: OT_ME.cpp:1131
EXPORT void RemoveReqNumbers(const OTString *pstrServerID=nullptr)
EXPORT void GetString(OTString &theStr) const
EXPORT bool IsEmpty() const
Definition: OTData.cpp:291
EXPORT OTServerContract * GetServerContractPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:685
static EXPORT OT_API * OTAPI()
Definition: OTAPI.cpp:244
static EXPORT std::string & trim(std::string &str)
Definition: OTString.cpp:398
EXPORT void RemoveAllNumbers(const OTString *pstrServerID=nullptr, bool bRemoveHighestNum=true)
EXPORT OTServerContract * GetServerContract(const OTIdentifier &SERVER_ID)
Definition: OTWallet.cpp:667
int main(int argc, char *argv[])
Definition: main.cpp:137
void CollectDefaultedCLValues(AnyOption *opt, std::string &str_ServerID, std::string &str_MyAcct, std::string &str_MyNym, std::string &str_MyPurse, std::string &str_HisAcct, std::string &str_HisNym, std::string &str_HisPurse)
Definition: main.cpp:499
EXPORT bool SaveSignedNymfile(OTPseudonym &SIGNER_NYM)