userioman.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. #include "../include/userioman.h"
  2. #include <iostream>
  3. #include <readline/readline.h>
  4. #include <vector>
  5. UserIoMan::UserIoMan(bool usessl, const char *certfile, bool beverbose) : IoMan(usessl, certfile) {
  6. /* setup json stuff */
  7. Json::CharReaderBuilder rbuilder;
  8. wbuilder.settings_["indentation"] = "";
  9. reader = rbuilder.newCharReader();
  10. verbose = beverbose;
  11. /* initialize print command map */
  12. printmap["error"] = &UserIoMan::printError;
  13. printmap["connectionerror"] = &UserIoMan::printError;
  14. printmap["connect"] = &UserIoMan::printConnect;
  15. printmap["help"] = &UserIoMan::printHelp;
  16. printmap["extendedstatus"] = &UserIoMan::printExtendedstatus;
  17. printmap["status"] = &UserIoMan::printStatus;
  18. printmap["disconnect"] = &UserIoMan::printDisconnect;
  19. printmap["put"] = &UserIoMan::printPut;
  20. printmap["get"] = &UserIoMan::printGet;
  21. printmap["list"] = &UserIoMan::printList;
  22. printmap["extendedlist"] = &UserIoMan::printExtendedlist;
  23. printmap["version"] = &UserIoMan::printVersion;
  24. printmap["login"] = &UserIoMan::printLogin;
  25. printmap["signup"] = &UserIoMan::printSignup;
  26. //~ printmap["putdata"] = &UserIoMan::printPutdata;
  27. //~ printmap["getdata"] = &UserIoMan::printGetdata;
  28. printmap["head"] = &UserIoMan::printHead;
  29. printmap["deletefile"] = &UserIoMan::printDeletefile;
  30. printmap["deleteme"] = &UserIoMan::printDeleteme;
  31. printmap["queue"] = &UserIoMan::printQueue;
  32. printmap["dequeue"] = &UserIoMan::printDequeue;
  33. printmap["keyfile"] = &UserIoMan::printKeyfile;
  34. printmap["closekey"] = &UserIoMan::printClosekey;
  35. printmap["notifications"] = &UserIoMan::printNotifications;
  36. }
  37. UserIoMan::~UserIoMan() { delete reader; }
  38. void UserIoMan::printMessage(std::string msg, OutMsgType type) {
  39. Json::Value root;
  40. vector<string>::const_iterator connectit;
  41. switch (type) {
  42. case normal:
  43. case error: {
  44. // this should never happen outside of development
  45. if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) {
  46. printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug);
  47. } else {
  48. printJson(root);
  49. }
  50. break;
  51. }
  52. case debug: {
  53. if (verbose) {
  54. msgmutex.lock();
  55. char *savedline = rl_copy_text(0, rl_end);
  56. int savedpoint = rl_point;
  57. rl_set_prompt("");
  58. rl_replace_line("", 0);
  59. rl_redisplay();
  60. std::cerr << msg << std::endl;
  61. rl_set_prompt(getCmdPrompt().c_str());
  62. rl_replace_line(savedline, 0);
  63. rl_point = savedpoint;
  64. rl_redisplay();
  65. free(savedline);
  66. msgmutex.unlock();
  67. }
  68. break;
  69. }
  70. }
  71. }
  72. void UserIoMan::printWelcomeMessage() {
  73. std::cout << std::endl
  74. << "Please connect to a server via \"connect <ip> <port>\", then" << std::endl
  75. << "login by entering \"login <username> <password>\"" << std::endl
  76. << "or sign up and log in with \"signup <username> <password>\"." << std::endl
  77. << std::endl;
  78. }
  79. std::string UserIoMan::getCmdPrompt() { return "ccats> "; }
  80. void UserIoMan::printJson(Json::Value root) {
  81. map<string, void (UserIoMan::*)(Json::Value)>::iterator it = printmap.find(root["command"].asString());
  82. if (it == printmap.end()) {
  83. // this should never happen outside of development
  84. printMessage(string(__PRETTY_FUNCTION__) + " unknown command \"" + root["command"].asString() + "\".\nEnsure code is implemented.", debug);
  85. return;
  86. }
  87. msgmutex.lock();
  88. char *savedline = rl_copy_text(0, rl_end);
  89. int savedpoint = rl_point;
  90. rl_set_prompt("");
  91. rl_replace_line("", 0);
  92. rl_redisplay();
  93. (this->*(printmap[root["command"].asString()]))(root);
  94. rl_set_prompt(getCmdPrompt().c_str());
  95. rl_replace_line(savedline, 0);
  96. rl_point = savedpoint;
  97. rl_redisplay();
  98. free(savedline);
  99. msgmutex.unlock();
  100. }
  101. void UserIoMan::printError(Json::Value root) { std::cout << "Error: " << root["error"].asString() << std::endl; }
  102. void UserIoMan::printConnect(Json::Value root) {
  103. if (!root["accept"].asBool()) {
  104. std::cout << "Couldnt connect to " << root["address"].asString() << ":" << root["port"].asUInt() << "." << std::endl
  105. << "Reason: " << root["error"].asString() << std::endl;
  106. }
  107. }
  108. void UserIoMan::printHelp(Json::Value root) {
  109. std::cout << "Available commands are: " << std::endl;
  110. for (Json::Value i : root["names"])
  111. std::cout << i.asString() << std::endl;
  112. }
  113. void UserIoMan::printStatus(Json::Value root) { std::cout << root["response"].asString() << std::endl; }
  114. void UserIoMan::printExtendedstatus(Json::Value root) {
  115. if (!root["accept"].asBool()) {
  116. std::cout << "Listing transfers failed. Server reports: " << root["error"].asString() << std::endl;
  117. } else {
  118. if (!root["transfersclientserver"].empty()) {
  119. std::cout << std::endl << "Transfers between clients and server:" << std::endl;
  120. /*
  121. * EXAMPLE:
  122. * type progress file
  123. * download 99% foobar.txt
  124. * upload 1% baz.html
  125. */
  126. std::cout << "type progress file" << std::endl;
  127. for (Json::Value val : root["transfersclientserver"]) {
  128. std::string type = val["upload"].asBool() ? "upload" : "download";
  129. std::string progress = std::to_string(val["progress"].asInt());
  130. std::string file = val["file"].asString();
  131. char output[21];
  132. std::snprintf(output, 21, "%-8s %7.7s%% ", type.c_str(), progress.c_str());
  133. std::cout << output << file << std::endl;
  134. }
  135. }
  136. if (!root["transfersserverserver"].empty()) {
  137. std::cout << std::endl << "Transfers between different servers:" << std::endl;
  138. /*
  139. * EXAMPLE:
  140. * type progress method bytes/sec file
  141. * download 99% method0000001 9000.01 foobar.txt
  142. * queued 1% urgent field 42.00 baz.html
  143. *
  144. * Too long method strings get truncated, unexpectedly high speeds are shown (with less pretty format), e.g.:
  145. *
  146. * download 95% too long stri 340282346638528859811704183484516925440.00 filename.zip
  147. */
  148. std::cout << "type progress method bytes/sec file" << std::endl;
  149. for (Json::Value val : root["transfersserverserver"]) {
  150. std::string type = val["type"].asString();
  151. std::string progress = std::to_string(val["progress"].asInt());
  152. std::string method = val["method"].asString();
  153. float speed = val["speed"].asFloat();
  154. std::string file = val["file"].asString();
  155. // size of 80 is just enough for maximum possible float value to fit as string
  156. char output[80];
  157. std::snprintf(output, 80, "%-8s %7.7s%% %-13.13s %15.2f ", type.c_str(), progress.c_str(), method.c_str(), speed);
  158. std::cout << output << file << std::endl;
  159. }
  160. }
  161. if (root["transfersclientserver"].empty() && root["transfersserverserver"].empty()) {
  162. std::cout << "No transfers running." << std::endl;
  163. } else {
  164. std::cout << std::endl;
  165. }
  166. }
  167. }
  168. void UserIoMan::printDisconnect(Json::Value root) {
  169. if (!root["accept"].asBool()) {
  170. std::cout << "Disconnect failed." << std::endl;
  171. } else {
  172. std::cout << "Disconnect successful." << std::endl;
  173. }
  174. }
  175. void UserIoMan::printPut(Json::Value root) {
  176. if (!root["accept"].asBool()) {
  177. if (root.isMember("file")) {
  178. std::cout << "Upload request for file " << root["file"].asString() << " failed: " << root["error"].asString() << std::endl;
  179. } else {
  180. std::cout << "Upload request failed: " << root["error"].asString() << std::endl;
  181. }
  182. } else
  183. std::cout << "Begin uploading file " << root["file"].asString() << std::endl;
  184. }
  185. void UserIoMan::printGet(Json::Value root) {
  186. if (!root["accept"].asBool()) {
  187. if (root.isMember("file")) {
  188. std::cout << "Download request for file " << root["file"].asString() << " failed: " << root["error"].asString() << std::endl;
  189. } else {
  190. std::cout << "Download request failed: " << root["error"].asString() << std::endl;
  191. }
  192. } else
  193. std::cout << "Begin downloading file " << root["file"].asString() << "." << std::endl;
  194. }
  195. void UserIoMan::printList(Json::Value root) {
  196. if (!root["accept"].asBool()) {
  197. std::cout << "Listing files failed: " << root["error"].asString() << std::endl;
  198. } else {
  199. std::cout << "Listing files stored on server: " << std::endl;
  200. for (Json::Value i : root["names"])
  201. std::cout << i.asString() << std::endl;
  202. std::cout << "End of list." << std::endl;
  203. }
  204. }
  205. void UserIoMan::printExtendedlist(Json::Value root) {
  206. if (!root["accept"].asBool()) {
  207. std::cout << "Listing files failed: " << root["error"].asString() << std::endl;
  208. } else {
  209. if (!root["files"].empty()) {
  210. std::cout << "Files stored on server: " << std::endl;
  211. /*
  212. * EXAMPLE:
  213. * size (kBytes) decryptable file
  214. * 9000.01 yes foo.txt
  215. * 42.00 no baz.html
  216. * 0.02 plaintext bar.zip
  217. */
  218. std::cout << "size (kBytes) decryptable file" << std::endl;
  219. for (Json::Value val : root["files"]) {
  220. float size = val["size"].asFloat();
  221. std::string encrypted = val["encrypted"].asString();
  222. std::string decryptable;
  223. if (encrypted == "decryptable") {
  224. decryptable = "\033[32myes\033[0m "; // "yes" in green
  225. } else if (encrypted == "undecryptable") {
  226. decryptable = "\033[31mno\033[0m "; // "no" in red
  227. } else if (encrypted == "unknown") {
  228. decryptable = "unknown ";
  229. } else {
  230. decryptable = "plaintext ";
  231. }
  232. std::string progress = std::to_string(val["progress"].asInt());
  233. std::string file = val["name"].asString();
  234. char sizeString[44];
  235. std::snprintf(sizeString, 44, "%13.2f ", size);
  236. std::cout << sizeString << decryptable << file << std::endl;
  237. }
  238. } else {
  239. std::cout << "No files stored on server." << std::endl;
  240. }
  241. }
  242. }
  243. void UserIoMan::printVersion(Json::Value root) {
  244. if (!root["accept"].asBool()) {
  245. std::cout << "Version check failed. Server reports version " << root["serverversion"].asString() << " but client is "
  246. << root["clientversion"].asString() << "." << std::endl;
  247. } else
  248. std::cout << "Version check ok." << std::endl;
  249. }
  250. void UserIoMan::printLogin(Json::Value root) {
  251. if (!root["accept"].asBool()) {
  252. std::cout << "Login failed: " << root["error"].asString() << std::endl;
  253. } else
  254. std::cout << "Login ok." << std::endl;
  255. }
  256. void UserIoMan::printSignup(Json::Value root) {
  257. if (!root["accept"].asBool()) {
  258. std::cout << "Signup failed: " << root["error"].asString() << std::endl;
  259. } else
  260. std::cout << "Signup ok. You are now logged in." << std::endl;
  261. }
  262. void UserIoMan::printDeleteme(Json::Value root) {
  263. if (!root["accept"].asBool()) {
  264. std::cout << "User deletion failed: " << root["error"].asString() << std::endl;
  265. } else
  266. std::cout << "User deletion ok. You are now disconnected from the server." << std::endl;
  267. }
  268. void UserIoMan::printPutdata(Json::Value root) {}
  269. void UserIoMan::printGetdata(Json::Value root) {}
  270. void UserIoMan::printListdata(Json::Value root) {}
  271. void UserIoMan::printHead(Json::Value root) {
  272. if (!root["accept"].asBool())
  273. std::cout << "Request of the first few bytes failed. " << root["error"].asString() << std::endl;
  274. else
  275. std::cout << "First few bytes of file " << root["file"].asString() << " are: " << root["data"].asString() << std::endl;
  276. }
  277. void UserIoMan::printDeletefile(Json::Value root) {
  278. if (!root["accept"].asBool())
  279. std::cout << "Deletion of file " << root["file"] << " failed: " << root["error"].asString() << std::endl;
  280. else
  281. std::cout << "File " << root["file"] << " deleted succesfully." << std::endl;
  282. }
  283. void UserIoMan::printKeyfile(Json::Value root) {
  284. if (!root["accept"].asBool())
  285. std::cout << "Couldnt select keyfile " << root["file"].asString() << ": " << root["error"].asString() << std::endl;
  286. else
  287. std::cout << "Using keyfile " << root["file"].asString() << "." << std::endl;
  288. }
  289. void UserIoMan::printClosekey(Json::Value root) {
  290. if (!root["accept"].asBool())
  291. std::cout << "Failed to close key: " << root["error"].asString() << std::endl;
  292. else
  293. std::cout << "Key closed." << std::endl;
  294. }
  295. void UserIoMan::printQueue(Json::Value root) {
  296. if (!root["accept"].asBool())
  297. std::cout << "Queueing of file " << root["file"] << " failed: " << root["error"].asString() << std::endl;
  298. else
  299. std::cout << "File " << root["file"] << " queued succesfully." << std::endl;
  300. }
  301. void UserIoMan::printDequeue(Json::Value root) {
  302. if (!root["accept"].asBool())
  303. std::cout << "Dequeueing of file " << root["file"] << " failed: " << root["error"].asString() << std::endl;
  304. else
  305. std::cout << "File " << root["file"] << " dequeued succesfully." << std::endl;
  306. }
  307. void UserIoMan::printNotifications(Json::Value root) {
  308. if (!root["accept"].asBool()) {
  309. std::cout << "Failed to get notifications: " << root["error"].asString() << std::endl;
  310. } else {
  311. std::cout << "New notifications:" << std::endl;
  312. for (Json::Value i : root["messages"])
  313. std::cout << "\033[94m" << i.asString() << std::endl;
  314. std::cout << "\033[0m " << std::endl;
  315. }
  316. }