//////////////////////////////////////////////////////////////////////////// // Copyright KAZ 2021 // // // // contact (at) kaz.bzh // // // // This software is a filter to shrink email by attachment extraction. // // // // This software is governed by the CeCILL-B license under French law and // // abiding by the rules of distribution of free software. You can use, // // modify and/or redistribute the software under the terms of the // // CeCILL-B license as circulated by CEA, CNRS and INRIA at the following // // URL "http://www.cecill.info". // // // // As a counterpart to the access to the source code and rights to copy, // // modify and redistribute granted by the license, users are provided // // only with a limited warranty and the software's author, the holder of // // the economic rights, and the successive licensors have only limited // // liability. // // // // In this respect, the user's attention is drawn to the risks associated // // with loading, using, modifying and/or developing or reproducing the // // software by the user in light of its specific status of free software, // // that may mean that it is complicated to manipulate, and that also // // therefore means that it is reserved for developers and experienced // // professionals having in-depth computer knowledge. Users are therefore // // encouraged to load and test the software's suitability as regards // // their requirements in conditions enabling the security of their // // systems and/or data to be ensured and, more generally, to use and // // operate it in the same conditions as regards security. // // // // The fact that you are presently reading this means that you have had // // knowledge of the CeCILL-B license and that you accept its terms. // //////////////////////////////////////////////////////////////////////////// #define LAST_VERSION "1.1 2022-10-30 jirafeauAPI" #include #include #include #include #include #include #include "kazDebug.hpp" #include "kazMisc.hpp" #include "SizeArg.hpp" using namespace std; using namespace boost; using namespace boost::program_options; using namespace kaz; namespace bfs = boost::filesystem; // ================================================================================ static options_description mainDescription ("Main options", getCols ()); static options_description hide ("Hidded options", getCols ()); static char *prog = NULL; // ================================================================================ void usage (const string &msg = "", const bool &hidden = false) { if (!msg.empty ()) { cout << msg << endl; exit (1); } cout << endl << "Usage: " << endl << " A) " << prog << " [-s size] [-t period] [-c content-type] [-n attachName] [-f server] send file [password] > url,delCode" << endl << " B) " << prog << " [-t period] [-f server] update ref > dealine" << endl << endl << " store ficle" << endl << endl << " A: send file (options : s, t)" << endl << " B: update deadline (options : t) " << endl << endl << mainDescription << endl; if (hidden) cout << hide << endl; exit (0); } void version () { cout << LAST_VERSION << " KAZ team production (https://kaz.bzh/)" << endl; exit (0); } static auto startPrg = std::chrono::high_resolution_clock::now (); void showTime (string msg) { using namespace std::chrono; static auto stopPrg = high_resolution_clock::now (); cerr << msg << " done in " << ns2string (duration_cast > (stopPrg-startPrg).count ()) << endl; } // ================================================================================ static size_t WriteCallback (void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*) userp)->append ((char*) contents, size * nmemb); return size * nmemb; } // ================================================================================ static const string inputFile = "input-file"; static const char *const inputFileC = inputFile.c_str (); int main (int argc, char** argv) { // XXX debug before parse options // Log::debug = true; DEF_LOG ("main:", ""); prog = argv [0]; bool debugFlag (false), helpFlag (false), versionFlag (false), useTheForceLuke (false); enum JirCmd { SEND, UPDATE } jirCmd; string inputFileName, password, contentType, attachName, urlBase ("http://file.kaz.bzh"), uploadPage ("/a.php"), updatePage ("/a.php"), minimumAvailability ("month"), proxy; SizeArg maxUploadSize ("100 Mi"); try { mainDescription.add_options () ("help,h", bool_switch (&helpFlag), "produce this help message") ("version,v", bool_switch (&versionFlag), "display version information") ("contentType,c", value (&contentType)->default_value (contentType), "content-type of the sended file") ("attachName,n", value (&attachName)->default_value (attachName), "force attachment name") ("minimumAvailability,t", value (&minimumAvailability)->default_value (minimumAvailability), "minimum period of available download") ("maxUploadSize,s", value (&maxUploadSize)->default_value (maxUploadSize), "maximum upload size") ("file server registery,f", value (&urlBase)->default_value (urlBase), "server where file are temporary stored") ; hide.add_options () ("useTheForceLuke", bool_switch (&useTheForceLuke), "display hidded options") ("debug,g", bool_switch (&debugFlag), "debug mode") ("proxy,p", value (&proxy)->default_value (proxy), "set proxy (proxy-host.org:8080)") ("uploadPage,u", value (&uploadPage)->default_value (uploadPage), "upload page") ("updatePage,v", value (&updatePage)->default_value (updatePage), "update page") ; options_description cmd ("All options"); cmd.add (mainDescription).add (hide).add_options () (inputFileC, value > (), "input") ; positional_options_description p; p.add (inputFileC, -1); variables_map vm; basic_parsed_options parsed = command_line_parser (argc, argv).options (cmd).positional (p).run (); store (parsed, vm); notify (vm); if (debugFlag) { #ifdef DISABLE_LOG cerr << "No debug option available (was compiled with -DDISABLE_LOG)" << endl; #endif } Log::debug = debugFlag; if (useTheForceLuke) usage ("", true); if (versionFlag) version (); if (helpFlag) usage (); if (vm.count (inputFileC)) { vector var = vm[inputFileC].as > (); int nbArgs = vm[inputFileC].as > ().size (); if (!nbArgs) usage ("No command"); if (var [0].compare ("send") == 0) jirCmd = SEND; else if (var [0].compare ("update") == 0) jirCmd = UPDATE; else usage ("Unknown command ("+var [0]+")"); if (nbArgs < 2) usage ("no input file"); inputFileName = var [1]; if (nbArgs == 3) password = var [2]; if (nbArgs > 3) usage ("Too much arguments"); } } catch (std::exception &e) { cerr << "error: " << e.what() << endl; usage (); return 1; } catch (...) { cerr << "Exception of unknown type!" << endl; return 1; } if (inputFileName.empty ()) usage ("no input"); CURL *easyhandle = curl_easy_init (); if (! easyhandle) { cerr << "no curl" << endl; return 1; } string readBuffer; if (proxy.length ()) curl_easy_setopt(easyhandle, CURLOPT_PROXY, proxy.c_str ()); curl_easy_setopt (easyhandle, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt (easyhandle, CURLOPT_WRITEDATA, &readBuffer); curl_mime *multipart = curl_mime_init (easyhandle); curl_mimepart *part = nullptr; switch (jirCmd) { case SEND: { LOG ("SEND: " << (urlBase+uploadPage)); curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+uploadPage).c_str ()); LOG ("maxUploadSize: " << maxUploadSize); long uploadsize = (size_t) maxUploadSize; curl_easy_setopt (easyhandle, CURLOPT_INFILESIZE, uploadsize); LOG ("time: " << minimumAvailability); part = curl_mime_addpart (multipart); curl_mime_name (part, "time"); curl_mime_data (part, minimumAvailability.c_str (), CURL_ZERO_TERMINATED); if (password.size ()) { LOG ("key: " << password); part = curl_mime_addpart (multipart); curl_mime_name (part, "key"); curl_mime_data (part, password.c_str (), CURL_ZERO_TERMINATED); } LOG ("inputFileName: " << bfs::path (inputFileName).filename ()); part = curl_mime_addpart (multipart); curl_mime_name (part, "file"); if (contentType.length ()) { LOG ("contentType: " << contentType); curl_mime_type (part, contentType.c_str ()); } if (attachName.empty ()) { attachName = bfs::path (inputFileName).filename ().c_str (); LOG ("attachName: " << attachName); } curl_mime_filename (part, attachName.c_str ()); FILE *fp = fopen (inputFileName.c_str (), "r"); fseek (fp, 0L, SEEK_END); long int fsize (ftell (fp)); fseek (fp, 0L, SEEK_SET); curl_mime_data_cb (part, fsize, (curl_read_callback) fread, (curl_seek_callback) fseek, NULL, //(curl_seek_callback) fclose, fp); } break; case UPDATE: { LOG ("UPDATE: " << (urlBase+updatePage)); curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+updatePage).c_str ()); LOG ("h: " << inputFileName); part = curl_mime_addpart (multipart); curl_mime_name (part, "h"); curl_mime_data (part, inputFileName.c_str (), CURL_ZERO_TERMINATED); LOG ("u: " << minimumAvailability); part = curl_mime_addpart (multipart); curl_mime_name (part, "u"); curl_mime_data (part, minimumAvailability.c_str (), CURL_ZERO_TERMINATED); } break; } curl_easy_setopt (easyhandle, CURLOPT_MIMEPOST, multipart); CURLcode res (curl_easy_perform (easyhandle)); curl_easy_cleanup (easyhandle); cout << readBuffer << endl; showTime ("Upload"); if (res != CURLE_OK) cerr << prog << " failed: " << curl_easy_strerror (res) << endl; return 0; } // ================================================================================