/* This file is part of libravatarserv. * Copyright © 2018, 2019 tastytea * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "version.hpp" #include "libravatarserv.hpp" using std::cout; using std::cerr; using std::endl; // Global variables std::map hash::table; fs::path settings::avatar_dir; settings::Settings settings::settings; int main() { cout << "Server: libravatarserv/" << global::version << endl; const char *request = std::getenv("REQUEST_URI"); if (request == nullptr) { cout << "Status: 400 Bad Request\n\n"; cerr << "Error: ${REQUEST_URI} is empty.\n"; return 1; } http::Request avatar = http::parse_request(request); if (!hash::is_valid(avatar.digest)) { cout << "Status: 400 Bad Request\n\n"; cerr << "Error: Hash is invalid\n"; return 1; } if (!settings::find_avatar_dir()) { cout << "Status: 503 Service Unavailable\n\n"; cerr << "Error: No avatars found.\n"; return 3; } hash::fill_table(); settings::read_settings(); image::Image image = image::get(avatar.digest, avatar.size); if (image.error == 0) { image::write(image); } else { cerr << "Warning " << std::to_string(image.error) << ": Could not open file.\n"; if (settings::settings.redirect_nouser) { http::send_redirect(avatar); return 0; } if (avatar.fallback.empty()) { avatar.fallback = settings::settings.default_fallback; } if (avatar.fallback.substr(0, 3) == "404") { cout << "Status: 404 Not Found\n\n"; } else if (avatar.fallback.substr(0, 4) == "http") { cout << "Status: 307 Temporary Redirect\n"; cout << "Location: " << avatar.fallback << endl << endl; } else if (avatar.fallback.substr(0, 2) == "mp" || avatar.fallback.substr(0, 2) == "mm") { // MD5 hash of 'mp' image = image::get("1f2dfa567dcf95833eddf7aec167fec7", avatar.size); if (image.error == 0) { image::write(image); } else { cerr << "Error: Mystery person not found.\n"; // Jump to last else goto not_implemented; } } else if (avatar.fallback.substr(0, 9) == "identicon" || avatar.fallback.substr(0, 5) == "retro") { try { uint8_t padwidth = avatar.size / 10; if (avatar.size < 60) { padwidth = 0; } else if (padwidth < 10) { padwidth = 10; } Identiconpp identicon(5, 5, Identiconpp::algorithm::sigil, "fefefeff", { // The same colors ivatar uses. "2d4fffff", // Blue "feb42cff", // Yellow "e279eaff", // Bright pink "1eb3fdff", // Cyan "E84D41ff", // Red "31CB73ff", // Green "8D45AAff" // Dark pink }, { padwidth, padwidth }); image.image = identicon.generate(avatar.digest, avatar.size); image.image.magick("PNG"); image::write(image); } catch (const std::exception &e) { cout << "Status: 500 Internal Server Error\n\n"; cerr << "Error: Couldn't generate identicon (" << e.what() << ").\n"; } } else { not_implemented: if (settings::settings.redirect_nofallback) { http::send_redirect(avatar); } else { cout << "Status: 501 Not Implemented\n\n"; } } } return 0; }