2021-05-06 09:58:16 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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.0 2021-02-21 jirafeauAPI"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
#include <curl/curl.h>
|
|
|
|
#include <chrono>
|
|
|
|
#include <boost/program_options.hpp>
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
|
|
|
|
#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<duration<double> > (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"),
|
|
|
|
apiPage ("/script.php"),
|
|
|
|
downloadPage ("/f.php"),
|
2022-02-15 17:38:01 +01:00
|
|
|
updatePage ("/a.php"),
|
2021-05-06 09:58:16 +02:00
|
|
|
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<string> (&contentType)->default_value (contentType), "content-type of the sended file")
|
|
|
|
("attachName,n", value<string> (&attachName)->default_value (attachName), "force attachment name")
|
|
|
|
("minimumAvailability,t", value<string> (&minimumAvailability)->default_value (minimumAvailability), "minimum period of available download")
|
|
|
|
("maxUploadSize,s", value<SizeArg> (&maxUploadSize)->default_value (maxUploadSize), "maximum upload size")
|
|
|
|
("file server registery,f", value<string> (&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<string> (&proxy)->default_value (proxy), "set proxy (proxy-host.org:8080)")
|
|
|
|
("uploadPage,u", value<string> (&apiPage)->default_value (apiPage), "upload page")
|
|
|
|
("downloadPage,d", value<string> (&downloadPage)->default_value (downloadPage), "download page")
|
|
|
|
;
|
|
|
|
|
|
|
|
options_description cmd ("All options");
|
|
|
|
cmd.add (mainDescription).add (hide).add_options ()
|
|
|
|
(inputFileC, value<vector<string> > (), "input")
|
|
|
|
;
|
|
|
|
positional_options_description p;
|
|
|
|
p.add (inputFileC, -1);
|
|
|
|
variables_map vm;
|
|
|
|
basic_parsed_options<char> 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<string> var = vm[inputFileC].as<vector<string> > ();
|
|
|
|
int nbArgs = vm[inputFileC].as<vector<string> > ().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+apiPage));
|
|
|
|
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+apiPage).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: {
|
2022-02-15 17:38:01 +01:00
|
|
|
LOG ("UPDATE: " << (urlBase+updatePage));
|
|
|
|
curl_easy_setopt (easyhandle, CURLOPT_URL, (urlBase+updatePage).c_str ());
|
2021-05-06 09:58:16 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
curl_easy_perform (easyhandle);
|
|
|
|
curl_easy_cleanup (easyhandle);
|
|
|
|
cout << readBuffer << endl;
|
|
|
|
|
|
|
|
showTime ("Upload");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ================================================================================
|