diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d295d41..0fc181c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,15 @@ project(tox_ngc_ft1_tool C CXX) add_executable(tox_ngc_ft1_tool ./main.cpp + + ./command_line.hpp + ./command_line.cpp + + ./tox_utils.hpp + ./tox_utils.cpp + + ./tox_client.hpp + ./tox_client.cpp ) target_compile_features(tox_ngc_ft1_tool PUBLIC cxx_std_17) diff --git a/src/command_line.cpp b/src/command_line.cpp new file mode 100644 index 0000000..ff1a29f --- /dev/null +++ b/src/command_line.cpp @@ -0,0 +1,94 @@ +#include "./command_line.hpp" + +#include +#include + +CommandLine::CommandLine(int argc, char** argv) { + assert(argc > 0); + + exe = argv[0]; + + for (int i = 1; i < argc; i++) { + std::string_view arg_sv{argv[i]}; + + if (arg_sv == "-v") { + version = true; + _should_exit = true; + } else if (arg_sv == "-V") { + verbose = true; + } else if (arg_sv == "-h") { + help = true; + printHelp(); + _should_exit = true; + } else if (arg_sv == "-G") { + if (i+1 >= argc) { + std::cerr << "-G missing parameter!\n\n"; + printHelp(); + _should_exit = true; + return; + } + chat_id = argv[++i]; + } else if (arg_sv == "-F") { + if (i+1 >= argc) { + std::cerr << "-F missing parameter!\n\n"; + printHelp(); + _should_exit = true; + return; + } + profile_path = argv[++i]; + } else if (arg_sv == "-a") { + } else if (arg_sv == "-f") { + if (i+1 >= argc) { + std::cerr << "-f missing parameter!\n\n"; + printHelp(); + _should_exit = true; + return; + } + send_path = argv[++i]; + } else if (arg_sv == "-d") { + if (i+1 >= argc) { + std::cerr << "-d missing parameter!\n\n"; + printHelp(); + _should_exit = true; + return; + } + receive_dump_dir = argv[++i]; + } else if (arg_sv == "-D") { + if (i+1 >= argc) { + std::cerr << "-D missing parameter!\n\n"; + printHelp(); + _should_exit = true; + return; + } + receive_id = argv[++i]; + } + } +} + +void CommandLine::printHelp(void) { + std::cout + << "meta:\n" + << " -v version info\n" + << " -V verbose\n" + << " -h help\n" + << "\n" + << " connectivity:\n" + << " -G \n" + << " -F profile.tox\n" + << " will print friend id at startup\n" + << " will autoaccept any invite\n" + << " if no -F give, will not save profile.\n" + << " if profile exists load, otherwise create new\n" + << "\n" + << " transfer variant:\n" + << " -a id1/sha128_single/sha128_info/sha256_single/sha256_info\n" + << "\n" + << " send:\n" + << " -f send_this_file.zip\n" + << "\n" + << " receive:\n" + << " -d dump/everything/in/this/dir\n" + << " -D (what to dl)\n" + ; +} + diff --git a/src/command_line.hpp b/src/command_line.hpp new file mode 100644 index 0000000..952a77d --- /dev/null +++ b/src/command_line.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +// meta: +// -v version info +// -V verbose +// -h help +// +// connectivity: +// -G +// -F profile.tox +// will print friend id at startup +// will autoaccept any invite +// if no -F give, will not save profile. +// if profile exists load, otherwise create new +// +// transfer variant: +// -a id1/sha128_single/sha128_info/sha256_single/sha256_info +// +// send: +// -f send_this_file.zip +// +// receive: +// -d dump/everything/in/this/dir +// -D (what to dl) + +struct CommandLine { + std::string exe; + + // meta: + // -v + bool version {false}; + // -V + bool verbose {false}; + // -h + bool help {false}; + + // connectivity: + // -G + std::string chat_id; + // -F profile.tox + std::string profile_path; + + // transfer variant: + // -a id1/sha128_single/sha128_info/sha256_single/sha256_info + // some enum? + + // send: + // -f send_this_file.zip + std::string send_path; + + // receive: + // -d dump/everything/in/this/dir + std::string receive_dump_dir; + // -D (what to dl) + std::string receive_id; + + CommandLine(int argc, char** argv); + + void printHelp(void); + + bool _should_exit {false}; +}; + diff --git a/src/main.cpp b/src/main.cpp index 462ba71..6a706ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,29 @@ -#include +#include "./tox_client.hpp" + +#include "./command_line.hpp" + +#include +#include +#include int main(int argc, char** argv) { + CommandLine cl(argc, argv); + + if (cl.version) { + std::cout << "tox_ngc_ft1_tool v0.0.1\n"; + } + + if (cl._should_exit) { + return 0; + } + + ToxClient client(cl); + + std::cout << "tox id: " << client.getOwnAddress() << "\n"; + + while (true) { + client.iterate(); + } return 0; } diff --git a/src/tox_client.cpp b/src/tox_client.cpp new file mode 100644 index 0000000..4cadb46 --- /dev/null +++ b/src/tox_client.cpp @@ -0,0 +1,98 @@ +#include "./tox_client.hpp" + +#include "./tox_utils.hpp" + +#include +#include +#include +#include +#include + +ToxClient::ToxClient(const CommandLine& cl) : + _tox_profile_path(cl.profile_path) +{ + TOX_ERR_OPTIONS_NEW err_opt_new; + Tox_Options* options = tox_options_new(&err_opt_new); + assert(err_opt_new == TOX_ERR_OPTIONS_NEW::TOX_ERR_OPTIONS_NEW_OK); + + // use cl for options + //tox_options_set_log_callback(options, log_cb); + tox_options_set_local_discovery_enabled(options, false); + tox_options_set_udp_enabled(options, true); + tox_options_set_hole_punching_enabled(options, true); + + std::vector profile_data{}; + if (!_tox_profile_path.empty()) { + std::ifstream ifile{_tox_profile_path, std::ios::binary}; + + if (ifile.is_open()) { + std::cout << "TOX loading save " << _tox_profile_path << "\n"; + // fill savedata + while (ifile.good()) { + auto ch = ifile.get(); + if (ch == EOF) { + break; + } else { + profile_data.push_back(ch); + } + } + + if (profile_data.empty()) { + std::cerr << "empty tox save\n"; + } else { + // set options + tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); + tox_options_set_savedata_data(options, profile_data.data(), profile_data.size()); + } + + ifile.close(); // do i need this? + } + } + + TOX_ERR_NEW err_new; + _tox = tox_new(options, &err_new); + tox_options_free(options); + if (err_new != TOX_ERR_NEW_OK) { + std::cerr << "tox_new failed with error code " << err_new << "\n"; + throw std::runtime_error{"tox failed"}; + } + + _tox_profile_dirty = true; +} + +void ToxClient::iterate(void) { + tox_iterate(_tox, this); + + if (_tox_profile_dirty) { + saveToxProfile(); + } +} + +std::string ToxClient::getOwnAddress(void) const { + std::vector self_addr{}; + self_addr.resize(TOX_ADDRESS_SIZE); + + tox_self_get_address(_tox, self_addr.data()); + + return bin2hex(self_addr); +} + +void ToxClient::saveToxProfile(void) { + if (_tox_profile_path.empty()) { + return; + } + + std::vector data{}; + data.resize(tox_get_savedata_size(_tox)); + tox_get_savedata(_tox, data.data()); + + std::ofstream ofile{_tox_profile_path, std::ios::binary}; + // TODO: improve + for (const auto& ch : data) { + ofile.put(ch); + } + ofile.close(); // TODO: do i need this + + _tox_profile_dirty = false; +} + diff --git a/src/tox_client.hpp b/src/tox_client.hpp new file mode 100644 index 0000000..ad5c736 --- /dev/null +++ b/src/tox_client.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "./command_line.hpp" + +#include +#include +#include + +#include + +struct ToxClient final { + ToxClient(const CommandLine& cl); + + void iterate(void); + + void setToxProfilePath(const std::string& new_path) { _tox_profile_path = new_path; } + + std::string getOwnAddress(void) const; + + private: + void saveToxProfile(void); + + private: + Tox* _tox {nullptr}; + NGC_EXT_CTX* _ext_ctx {nullptr}; + NGC_FT1* _ft1_ctx {nullptr}; + + std::string _tox_profile_path; + bool _tox_profile_dirty {false}; // set in callbacks +}; + diff --git a/src/tox_utils.cpp b/src/tox_utils.cpp new file mode 100644 index 0000000..e8ddb11 --- /dev/null +++ b/src/tox_utils.cpp @@ -0,0 +1,23 @@ +#include "./tox_utils.hpp" + +#include + +std::vector hex2bin(const std::string& str) { + std::vector bin{}; + bin.resize(str.size()/2, 0); + + sodium_hex2bin(bin.data(), bin.size(), str.c_str(), str.length(), nullptr, nullptr, nullptr); + + return bin; +} + +std::string bin2hex(const std::vector& bin) { + std::string str{}; + str.resize(bin.size()*2, '?'); + + // HECK, std is 1 larger than size returns ('\0') + sodium_bin2hex(str.data(), str.size()+1, bin.data(), bin.size()); + + return str; +} + diff --git a/src/tox_utils.hpp b/src/tox_utils.hpp new file mode 100644 index 0000000..21e62cd --- /dev/null +++ b/src/tox_utils.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +std::vector hex2bin(const std::string& str); +std::string bin2hex(const std::vector& bin); +