// Sends a push message to a Gotify server #include "helpers.hpp" #include #include #include #include #include #include #include #include #include #include #include struct message { std::string base_url; std::string token; std::string title; std::string body; std::int16_t priority{5}; } __attribute__((aligned(128))) message; void read_options(int argc, char *argv[]) { namespace po = boost::program_options; po::options_description options("Options"); // clang-format off options.add_options() ("help,h", "Display this help and exit.") ("baseurl", po::value()->required(), "Example: https://push.example.org") ("token", po::value()->required(), "Application token.") ("title", po::value(), "Title of the message.") ("message", po::value()->required(), "Message body.") ("priority", po::value(), "Priority of the message. Default is 5. " "0 = hidden notification, 1-3 = silent, 4-7 = sound, 8-10 = popup."); // clang-format on po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(options).run(), vm); std::ifstream configfile(helpers::get_config_file_path("pushmsg.cfg")); po::store(po::parse_config_file(configfile, options, true), vm); configfile.close(); if (vm.count("help") != 0) { std::cout << options; std::exit(0); // NOLINT(concurrency-mt-unsafe) } po::notify(vm); message.base_url = vm["baseurl"].as(); message.token = vm["token"].as(); if (vm.count("title") != 0) { message.title = vm["title"].as(); } message.body = vm["message"].as(); if (vm.count("priority") != 0) { message.priority = vm["priority"].as(); } } int main(int argc, char *argv[]) { using std::cerr; try { read_options(argc, argv); RestClient::init(); RestClient::Connection conn(message.base_url); conn.FollowRedirects(true, 5); conn.SetTimeout(30); conn.SetHeaders({{"Content-Type", "application/json; charset=utf-8"}}); const nlohmann::json json{{"title", message.title}, {"message", message.body}, {"priority", message.priority}}; const auto response{ conn.post("/message?token=" + message.token, json.dump())}; RestClient::disable(); switch (response.code) { case 200: { return 0; break; } case 400: { cerr << "HTTP status 400: Bad Request.\n"; break; } case 401: { cerr << "HTTP status 401: Unauthorized (invalid token).\n"; break; } case 403: { cerr << "HTTP status 403: Forbidden.\n"; break; } case 404: { cerr << "HTTP status 404: Not Found.\n"; break; } case 502: { cerr << "HTTP status 502: Bad Gateway (server down).\n"; break; } default: { cerr << "HTTP status " << response.code << ".\n"; break; } } } catch (const std::exception &e) { cerr << e.what() << '\n'; } return 1; }