#include "../include/userioman.h" #include #include #include UserIoMan::UserIoMan(bool usessl, const char *certfile, bool beverbose) : IoMan(usessl, certfile) { /* setup json stuff */ Json::CharReaderBuilder rbuilder; wbuilder.settings_["indentation"] = ""; reader = rbuilder.newCharReader(); verbose = beverbose; /* initialize print command map */ printmap["error"] = &UserIoMan::printError; printmap["connectionerror"] = &UserIoMan::printError; printmap["connect"] = &UserIoMan::printConnect; printmap["help"] = &UserIoMan::printHelp; printmap["extendedstatus"] = &UserIoMan::printExtendedstatus; printmap["status"] = &UserIoMan::printStatus; printmap["disconnect"] = &UserIoMan::printDisconnect; printmap["put"] = &UserIoMan::printPut; printmap["get"] = &UserIoMan::printGet; printmap["list"] = &UserIoMan::printList; printmap["extendedlist"] = &UserIoMan::printExtendedlist; printmap["version"] = &UserIoMan::printVersion; printmap["login"] = &UserIoMan::printLogin; printmap["signup"] = &UserIoMan::printSignup; //~ printmap["putdata"] = &UserIoMan::printPutdata; //~ printmap["getdata"] = &UserIoMan::printGetdata; printmap["head"] = &UserIoMan::printHead; printmap["deletefile"] = &UserIoMan::printDeletefile; printmap["deleteme"] = &UserIoMan::printDeleteme; printmap["queue"] = &UserIoMan::printQueue; printmap["dequeue"] = &UserIoMan::printDequeue; printmap["keyfile"] = &UserIoMan::printKeyfile; printmap["closekey"] = &UserIoMan::printClosekey; printmap["notifications"] = &UserIoMan::printNotifications; } UserIoMan::~UserIoMan() { delete reader; } void UserIoMan::printMessage(std::string msg, OutMsgType type) { Json::Value root; vector::const_iterator connectit; switch (type) { case normal: case error: { // this should never happen outside of development if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) { printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug); } else { printJson(root); } break; } case debug: { if (verbose) { msgmutex.lock(); char *savedline = rl_copy_text(0, rl_end); int savedpoint = rl_point; rl_set_prompt(""); rl_replace_line("", 0); rl_redisplay(); std::cerr << msg << std::endl; rl_set_prompt(getCmdPrompt().c_str()); rl_replace_line(savedline, 0); rl_point = savedpoint; rl_redisplay(); free(savedline); msgmutex.unlock(); } break; } } } void UserIoMan::printWelcomeMessage() { std::cout << std::endl << "Please connect to a server via \"connect \", then" << std::endl << "login by entering \"login \"" << std::endl << "or sign up and log in with \"signup \"." << std::endl << std::endl; } std::string UserIoMan::getCmdPrompt() { return "ccats> "; } void UserIoMan::printJson(Json::Value root) { map::iterator it = printmap.find(root["command"].asString()); if (it == printmap.end()) { // this should never happen outside of development printMessage(string(__PRETTY_FUNCTION__) + " unknown command \"" + root["command"].asString() + "\".\nEnsure code is implemented.", debug); return; } msgmutex.lock(); char *savedline = rl_copy_text(0, rl_end); int savedpoint = rl_point; rl_set_prompt(""); rl_replace_line("", 0); rl_redisplay(); (this->*(printmap[root["command"].asString()]))(root); rl_set_prompt(getCmdPrompt().c_str()); rl_replace_line(savedline, 0); rl_point = savedpoint; rl_redisplay(); free(savedline); msgmutex.unlock(); } void UserIoMan::printError(Json::Value root) { std::cout << "Error: " << root["error"].asString() << std::endl; } void UserIoMan::printConnect(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Couldnt connect to " << root["address"].asString() << ":" << root["port"].asUInt() << "." << std::endl << "Reason: " << root["error"].asString() << std::endl; } } void UserIoMan::printHelp(Json::Value root) { std::cout << "Available commands are: " << std::endl; for (Json::Value i : root["names"]) std::cout << i.asString() << std::endl; } void UserIoMan::printStatus(Json::Value root) { std::cout << root["response"].asString() << std::endl; } void UserIoMan::printExtendedstatus(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Listing transfers failed. Server reports: " << root["error"].asString() << std::endl; } else { if (!root["transfersclientserver"].empty()) { std::cout << std::endl << "Transfers between clients and server:" << std::endl; /* * EXAMPLE: * type progress file * download 99% foobar.txt * upload 1% baz.html */ std::cout << "type progress file" << std::endl; for (Json::Value val : root["transfersclientserver"]) { std::string type = val["upload"].asBool() ? "upload" : "download"; std::string progress = std::to_string(val["progress"].asInt()); std::string file = val["file"].asString(); char output[21]; std::snprintf(output, 21, "%-8s %7.7s%% ", type.c_str(), progress.c_str()); std::cout << output << file << std::endl; } } if (!root["transfersserverserver"].empty()) { std::cout << std::endl << "Transfers between different servers:" << std::endl; /* * EXAMPLE: * type progress method bytes/sec file * download 99% method0000001 9000.01 foobar.txt * queued 1% urgent field 42.00 baz.html * * Too long method strings get truncated, unexpectedly high speeds are shown (with less pretty format), e.g.: * * download 95% too long stri 340282346638528859811704183484516925440.00 filename.zip */ std::cout << "type progress method bytes/sec file" << std::endl; for (Json::Value val : root["transfersserverserver"]) { std::string type = val["type"].asString(); std::string progress = std::to_string(val["progress"].asInt()); std::string method = val["method"].asString(); float speed = val["speed"].asFloat(); std::string file = val["file"].asString(); // size of 80 is just enough for maximum possible float value to fit as string char output[80]; std::snprintf(output, 80, "%-8s %7.7s%% %-13.13s %15.2f ", type.c_str(), progress.c_str(), method.c_str(), speed); std::cout << output << file << std::endl; } } if (root["transfersclientserver"].empty() && root["transfersserverserver"].empty()) { std::cout << "No transfers running." << std::endl; } else { std::cout << std::endl; } } } void UserIoMan::printDisconnect(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Disconnect failed." << std::endl; } else { std::cout << "Disconnect successful." << std::endl; } } void UserIoMan::printPut(Json::Value root) { if (!root["accept"].asBool()) { if (root.isMember("file")) { std::cout << "Upload request for file " << root["file"].asString() << " failed: " << root["error"].asString() << std::endl; } else { std::cout << "Upload request failed: " << root["error"].asString() << std::endl; } } else std::cout << "Begin uploading file " << root["file"].asString() << std::endl; } void UserIoMan::printGet(Json::Value root) { if (!root["accept"].asBool()) { if (root.isMember("file")) { std::cout << "Download request for file " << root["file"].asString() << " failed: " << root["error"].asString() << std::endl; } else { std::cout << "Download request failed: " << root["error"].asString() << std::endl; } } else std::cout << "Begin downloading file " << root["file"].asString() << "." << std::endl; } void UserIoMan::printList(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Listing files failed: " << root["error"].asString() << std::endl; } else { std::cout << "Listing files stored on server: " << std::endl; for (Json::Value i : root["names"]) std::cout << i.asString() << std::endl; std::cout << "End of list." << std::endl; } } void UserIoMan::printExtendedlist(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Listing files failed: " << root["error"].asString() << std::endl; } else { if (!root["files"].empty()) { std::cout << "Files stored on server: " << std::endl; /* * EXAMPLE: * size (kBytes) decryptable file * 9000.01 yes foo.txt * 42.00 no baz.html * 0.02 plaintext bar.zip */ std::cout << "size (kBytes) decryptable file" << std::endl; for (Json::Value val : root["files"]) { float size = val["size"].asFloat(); std::string encrypted = val["encrypted"].asString(); std::string decryptable; if (encrypted == "decryptable") { decryptable = "\033[32myes\033[0m "; // "yes" in green } else if (encrypted == "undecryptable") { decryptable = "\033[31mno\033[0m "; // "no" in red } else if (encrypted == "unknown") { decryptable = "unknown "; } else { decryptable = "plaintext "; } std::string progress = std::to_string(val["progress"].asInt()); std::string file = val["name"].asString(); char sizeString[44]; std::snprintf(sizeString, 44, "%13.2f ", size); std::cout << sizeString << decryptable << file << std::endl; } } else { std::cout << "No files stored on server." << std::endl; } } } void UserIoMan::printVersion(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Version check failed. Server reports version " << root["serverversion"].asString() << " but client is " << root["clientversion"].asString() << "." << std::endl; } else std::cout << "Version check ok." << std::endl; } void UserIoMan::printLogin(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Login failed: " << root["error"].asString() << std::endl; } else std::cout << "Login ok." << std::endl; } void UserIoMan::printSignup(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Signup failed: " << root["error"].asString() << std::endl; } else std::cout << "Signup ok. You are now logged in." << std::endl; } void UserIoMan::printDeleteme(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "User deletion failed: " << root["error"].asString() << std::endl; } else std::cout << "User deletion ok. You are now disconnected from the server." << std::endl; } void UserIoMan::printPutdata(Json::Value root) {} void UserIoMan::printGetdata(Json::Value root) {} void UserIoMan::printListdata(Json::Value root) {} void UserIoMan::printHead(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Request of the first few bytes failed. " << root["error"].asString() << std::endl; else std::cout << "First few bytes of file " << root["file"].asString() << " are: " << root["data"].asString() << std::endl; } void UserIoMan::printDeletefile(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Deletion of file " << root["file"] << " failed: " << root["error"].asString() << std::endl; else std::cout << "File " << root["file"] << " deleted succesfully." << std::endl; } void UserIoMan::printKeyfile(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Couldnt select keyfile " << root["file"].asString() << ": " << root["error"].asString() << std::endl; else std::cout << "Using keyfile " << root["file"].asString() << "." << std::endl; } void UserIoMan::printClosekey(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Failed to close key: " << root["error"].asString() << std::endl; else std::cout << "Key closed." << std::endl; } void UserIoMan::printQueue(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Queueing of file " << root["file"] << " failed: " << root["error"].asString() << std::endl; else std::cout << "File " << root["file"] << " queued succesfully." << std::endl; } void UserIoMan::printDequeue(Json::Value root) { if (!root["accept"].asBool()) std::cout << "Dequeueing of file " << root["file"] << " failed: " << root["error"].asString() << std::endl; else std::cout << "File " << root["file"] << " dequeued succesfully." << std::endl; } void UserIoMan::printNotifications(Json::Value root) { if (!root["accept"].asBool()) { std::cout << "Failed to get notifications: " << root["error"].asString() << std::endl; } else { std::cout << "New notifications:" << std::endl; for (Json::Value i : root["messages"]) std::cout << "\033[94m" << i.asString() << std::endl; std::cout << "\033[0m " << std::endl; } }