/* Copyright 2021 Grégory Soutadé This is a 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, either version 3 of the License, or (at your option) any later version. It 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 it. If not, see . */ #include #include #include #include #include #include #include #include #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) int verbose = INFO; static const char* deviceFile = "device.xml"; static const char* activationFile = "activation.xml"; static const char* devicekeyFile = "devicesalt"; static const char* acsmFile = 0; static const char* outputFile = 0; static const char* outputDir = 0; static const char* defaultDirs[] = { ".adept/", "./adobe-digital-editions/", "./.adobe-digital-editions/" }; class ACSMDownloader { public: ACSMDownloader(QCoreApplication* app): app(app) { } static void* run(void* param) { ACSMDownloader* _this; LOG_FUNC(); int ret = dp::platformInit(0xFFFFFFFF); if (ret) { LOG(ERROR, "Error platform init " << ret); _this->app->exit(ret); return 0; } dp::cryptRegisterOpenSSL(); dp::documentRegisterEPUB(); dp::documentRegisterPDF(); LOG(DEBUG, "Create Adobe objects"); try { MockDRMProcessorClient processorClient(outputDir, outputFile); MockDevice device(&processorClient, deviceFile, activationFile, devicekeyFile); MockProvider provider(&device); device.setProvider(&provider); dpdev::DeviceProvider::addProvider(&provider); MockNetProvider netProvider; dpnet::NetProvider::setProvider(&netProvider); adept::DRMProviderImpl* _prov = rmsdk::getProvider(); LOG(DEBUG, "Create DRM Processor"); adept::DRMProcessorImpl* drmprocessor = _prov->createDRMProcessor(&processorClient, &device); processorClient.setProcessor(drmprocessor); unsigned char* buffer; int buffer_size; MockDevice::readFile(acsmFile, &buffer, &buffer_size, true); LOG(DEBUG, "Init workflow "); drmprocessor->initWorkflows(WORKFLOW_AUTH_SIGN_IN|WORKFLOW_FULFILLMENT|WORKFLOW_DOWNLOAD|WORKFLOW_NOTIFICATION, dp::Data(buffer, buffer_size)); LOG(DEBUG, "Start work"); drmprocessor->startWorkflows(WORKFLOW_AUTH_SIGN_IN|WORKFLOW_FULFILLMENT|WORKFLOW_DOWNLOAD|WORKFLOW_NOTIFICATION); delete[] buffer; LOG(DEBUG, "Bye bye"); ret = (int)processorClient.getErrors(); } catch(std::exception& e) { LOG(ERROR, e.what()); ret = 1; } _this->app->exit(ret); return 0; } private: QCoreApplication* app; }; static const char* findFile(const char* filename, bool inDefaultDirs=true) { QFile file(filename); if (file.exists()) return strdup(filename); if (!inDefaultDirs) return 0; for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++) { uft::String path = uft::String(defaultDirs[i]) + filename; file.setFileName(path.c_str()); if (file.exists()) return strdup(path.c_str()); } return 0; } static void usage(void) { std::cout << "Download EPUB file from ACSM request file" << std::endl; std::cout << "Usage: ./acsmdownloader [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-s|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output.epub] [(-v|--verbose)] [(-h|--help)] (-f|--acsm-file) file.acsm" << std::endl << std::endl; std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl; std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl; std::cout << " " << "-k|--device-key-file" << "\t" << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl; std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./)" << std::endl; std::cout << " " << "-o|--output-file" << "\t" << "Optional output epub filename (default )" << std::endl; std::cout << " " << "-f|--acsm-file" << "\t" << "ACSM request file for epub download" << std::endl; std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl; std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl; std::cout << std::endl; std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl; std::cout << " * Current directory" << std::endl; std::cout << " * .adept" << std::endl; std::cout << " * adobe-digital-editions directory" << std::endl; std::cout << " * .adobe-digital-editions directory" << std::endl; } int main(int argc, char** argv) { int c, ret = -1; const char** files[] = {&devicekeyFile, &deviceFile, &activationFile}; while (1) { int option_index = 0; static struct option long_options[] = { {"device-file", required_argument, 0, 'd' }, {"activation-file", required_argument, 0, 'a' }, {"device-key-file", required_argument, 0, 'k' }, {"output-dir", required_argument, 0, 'O' }, {"output-file", required_argument, 0, 'o' }, {"acsm-file", required_argument, 0, 'f' }, {"verbose", no_argument, 0, 'v' }, {"help", no_argument, 0, 'h' }, {0, 0, 0, 0 } }; c = getopt_long(argc, argv, "d:a:k:O:o:f:vh", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': deviceFile = optarg; break; case 'a': activationFile = optarg; break; case 'k': devicekeyFile = optarg; break; case 'f': acsmFile = optarg; break; case 'O': outputDir = optarg; break; case 'o': outputFile = optarg; break; case 'v': verbose++; break; case 'h': usage(); return 0; break; default: usage(); return -1; } } if (!acsmFile || (outputDir && !outputDir[0]) || (outputFile && !outputFile[0])) { usage(); return -1; } int i; for (i=0; i<(int)ARRAY_SIZE(files); i++) { *files[i] = findFile(*files[i]); if (!*files[i]) { LOG(ERROR, "Error : " << *files[i] << " doesn't exists"); return -1; } } QFile file(acsmFile); if (!file.exists()) { LOG(ERROR, "Error : " << acsmFile << " doesn't exists"); return -1; } LOG(INFO, "RMSDK Version " << dp::getVersionInfo("hobbes").utf8()); QCoreApplication app(argc, argv); ACSMDownloader downloader(&app); pthread_t thread; pthread_create(&thread, NULL, ACSMDownloader::run, (void*)&downloader); ret = app.exec(); for (i=0; i<(int)ARRAY_SIZE(files); i++) free((void*)*files[i]); return ret; }