Compare commits
No commits in common. "master" and "v0.8.2" have entirely different histories.
52
README.md
52
README.md
|
@ -1,16 +1,16 @@
|
|||
Introduction
|
||||
------------
|
||||
|
||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcomes the lack of Adobe support for Linux platforms.
|
||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcome the lacks of Adobe support for Linux platforms.
|
||||
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) have to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
||||
A reference implementation using cURL, OpenSSL and libzip is provided (in _utils_ directory).
|
||||
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) has to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
||||
A reference implementation using Qt, OpenSSL and libzip is provided (in _utils_ directory).
|
||||
|
||||
Main functions to use from gourou::DRMProcessor are:
|
||||
Main fucntions to use from gourou::DRMProcessor are :
|
||||
|
||||
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
||||
* Create a new device : _createDRMProcessor()_
|
||||
|
@ -18,32 +18,32 @@ Main functions to use from gourou::DRMProcessor are:
|
|||
* Remove DRM : _removeDRM()_
|
||||
* Return loaned book : _returnLoan()_
|
||||
|
||||
You can import configuration from (at least):
|
||||
You can import configuration from (at least) :
|
||||
|
||||
* Kobo device : .adept/device.xml, .adept/devicesalt and .adept/activation.xml
|
||||
* Bookeen device : .adobe-digital-editions/device.xml, root/devkey.bin and .adobe-digital-editions/activation.xml
|
||||
|
||||
Or create a new one. Be careful: there is a limited number of devices that can be created by one account.
|
||||
Or create a new one. Be careful : there is a limited number of devices that can be created bye one account.
|
||||
|
||||
ePub are encrypted using a shared key: one account / multiple devices, so you can create and register a device into your computer and read downloaded (and encrypted) ePub file with your eReader configured using the same AdobeID account.
|
||||
ePub are encrypted using a shared key : one account / multiple devices, so you can create and register a device into your computer and read downloaded (and encrypted) ePub file with your eReader configured using the same AdobeID account.
|
||||
|
||||
For those who want to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
||||
For those who wants to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
For libgourou:
|
||||
For libgourou :
|
||||
|
||||
_externals_ :
|
||||
|
||||
* libpugixml
|
||||
|
||||
_internals_:
|
||||
_internals_ :
|
||||
|
||||
* uPDFParser
|
||||
|
||||
For utils:
|
||||
For utils :
|
||||
|
||||
* libcurl
|
||||
* OpenSSL
|
||||
|
@ -52,7 +52,7 @@ For utils:
|
|||
|
||||
|
||||
Internal libraries are automatically fetched and statically compiled during the first run.
|
||||
When you update libgourou's repository, **don't forget to update internal libraries** with:
|
||||
When you update libgourou's repository, **don't forget to update internal libraries** with :
|
||||
|
||||
make update_lib
|
||||
|
||||
|
@ -92,31 +92,31 @@ You can optionaly specify your .adept directory
|
|||
|
||||
export ADEPT_DIR=/home/XXX
|
||||
|
||||
Then, use utils as following:
|
||||
Then, use utils as following :
|
||||
|
||||
You can import configuration from your eReader or create a new one with _utils/adept\_activate_:
|
||||
You can import configuration from your eReader or create a new one with _utils/adept\_activate_ :
|
||||
|
||||
./utils/adept_activate -u <AdobeID USERNAME>
|
||||
|
||||
Then a _/home/<user>/.config/adept_ directory is created with all configuration file
|
||||
|
||||
To download an ePub/PDF:
|
||||
To download an ePub/PDF :
|
||||
|
||||
./utils/acsmdownloader <ACSM_FILE>
|
||||
|
||||
To export your private key (for DeDRM software):
|
||||
To export your private key (for DeDRM software) :
|
||||
|
||||
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
||||
|
||||
To remove ADEPT DRM:
|
||||
To remove ADEPT DRM :
|
||||
|
||||
./utils/adept_remove <encryptedFile>
|
||||
|
||||
To list loaned books:
|
||||
To list loaned books :
|
||||
|
||||
./utils/adept_loan_mgt [-l]
|
||||
|
||||
To return a loaned book:
|
||||
To return a loaned book :
|
||||
|
||||
./utils/adept_loan_mgt -r <id>
|
||||
|
||||
|
@ -150,17 +150,3 @@ Special thanks
|
|||
* _Jens_ for all test samples and utils testing
|
||||
* _Milian_ for debug & code
|
||||
* _Berwyn H_ for all test samples, feedbacks, patches and kind donation
|
||||
|
||||
|
||||
Donation
|
||||
--------
|
||||
|
||||
https://www.paypal.com/donate/?hosted_button_id=JD3U6XMZCPHKN
|
||||
|
||||
|
||||
Donators
|
||||
--------
|
||||
|
||||
* _Berwyn H_
|
||||
* _bwitt_
|
||||
* _Ismail_
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||
#endif
|
||||
|
||||
#define LIBGOUROU_VERSION "0.8.6"
|
||||
#define LIBGOUROU_VERSION "0.8.2"
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
|
@ -67,11 +67,10 @@ namespace gourou
|
|||
* @brief Fulfill ACSM file to server in order to retrieve ePub fulfillment item
|
||||
*
|
||||
* @param ACSMFile Path of ACSMFile
|
||||
* @param notify Notify server if requested by response
|
||||
*
|
||||
* @return a FulfillmentItem if all is OK
|
||||
*/
|
||||
FulfillmentItem* fulfill(const std::string& ACSMFile, bool notify=true);
|
||||
FulfillmentItem* fulfill(const std::string& ACSMFile);
|
||||
|
||||
/**
|
||||
* @brief Once fulfilled, ePub file needs to be downloaded.
|
||||
|
@ -103,9 +102,8 @@ namespace gourou
|
|||
*
|
||||
* @param loanID Loan ID received during fulfill
|
||||
* @param operatorURL URL of operator that loans this book
|
||||
* @param notify Notify server if requested by response
|
||||
*/
|
||||
void returnLoan(const std::string& loanID, const std::string& operatorURL, bool notify=true);
|
||||
void returnLoan(const std::string& loanID, const std::string& operatorURL);
|
||||
|
||||
/**
|
||||
* @brief Return default ADEPT directory (ie /home/<user>/.config/adept)
|
||||
|
@ -158,7 +156,7 @@ namespace gourou
|
|||
* @brief Send HTTP POST request to URL with document as POSTData
|
||||
*/
|
||||
ByteArray sendRequest(const pugi::xml_document& document, const std::string& url);
|
||||
|
||||
|
||||
/**
|
||||
* @brief In place encrypt data with private device key
|
||||
*/
|
||||
|
@ -235,9 +233,6 @@ namespace gourou
|
|||
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
|
||||
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
||||
const std::string& operatorURL);
|
||||
void buildNotifyReq(pugi::xml_document& returnReq, pugi::xml_node& body);
|
||||
void notifyServer(pugi::xml_node& notifyRoot);
|
||||
void notifyServer(pugi::xml_document& fulfillReply);
|
||||
std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType);
|
||||
void decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
|
||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||
|
|
|
@ -120,7 +120,6 @@ namespace gourou
|
|||
CLIENT_OSSL_ERROR,
|
||||
CLIENT_CRYPT_ERROR,
|
||||
CLIENT_DIGEST_ERROR,
|
||||
CLIENT_HTTP_ERROR
|
||||
};
|
||||
|
||||
enum DRM_REMOVAL_ERROR {
|
||||
|
@ -236,7 +235,12 @@ namespace gourou
|
|||
return ltrim(rtrim(s, t), t);
|
||||
}
|
||||
|
||||
static inline pugi::xml_node getNode(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||
/**
|
||||
* @brief Extract text node from tag in document
|
||||
* It can throw an exception if tag does not exists
|
||||
* or just return an empty value
|
||||
*/
|
||||
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||
{
|
||||
pugi::xpath_node xpath_node = root.select_node(tagName);
|
||||
|
||||
|
@ -245,23 +249,10 @@ namespace gourou
|
|||
if (throwOnNull)
|
||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||
|
||||
return pugi::xml_node();
|
||||
return "";
|
||||
}
|
||||
|
||||
return xpath_node.node();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extract text node from tag in document
|
||||
* It can throw an exception if tag does not exists
|
||||
* or just return an empty value
|
||||
*/
|
||||
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||
{
|
||||
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||
|
||||
node = node.first_child();
|
||||
pugi::xml_node node = xpath_node.node().first_child();
|
||||
|
||||
if (!node)
|
||||
{
|
||||
|
@ -275,30 +266,6 @@ namespace gourou
|
|||
return trim(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set text node of a tag in document
|
||||
* It can throw an exception if tag does not exists
|
||||
*/
|
||||
static inline void setTextElem(const pugi::xml_node& root, const char* tagName,
|
||||
const std::string& value, bool throwOnNull=true)
|
||||
{
|
||||
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
if (throwOnNull)
|
||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Text element for tag " << tagName << " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
node = node.first_child();
|
||||
|
||||
if (!node)
|
||||
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
||||
else
|
||||
node.set_value(value.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extract text attribute from tag in document
|
||||
* It can throw an exception if attribute does not exists
|
||||
|
@ -306,9 +273,17 @@ namespace gourou
|
|||
*/
|
||||
static inline std::string extractTextAttribute(const pugi::xml_node& root, const char* tagName, const char* attributeName, bool throwOnNull=true)
|
||||
{
|
||||
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||
pugi::xpath_node xpath_node = root.select_node(tagName);
|
||||
|
||||
pugi::xml_attribute attr = node.attribute(attributeName);
|
||||
if (!xpath_node)
|
||||
{
|
||||
if (throwOnNull)
|
||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
pugi::xml_attribute attr = xpath_node.node().attribute(attributeName);
|
||||
|
||||
if (!attr)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
if [ ! -d lib/updfparser ] ; then
|
||||
echo "Some libraries are missing"
|
||||
echo "You must run this script at the top of libgourou working direcotry."
|
||||
echo "./scripts/setup.sh must be called first (make all)"
|
||||
echo "./lib/setup.sh must be called first (make all)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
@ -398,7 +398,31 @@ namespace gourou
|
|||
}
|
||||
}
|
||||
|
||||
doOperatorAuth(operatorURL);
|
||||
doOperatorAuth(operatorURL);
|
||||
|
||||
// Add new operatorURL to list
|
||||
pugi::xml_document activationDoc;
|
||||
user->readActivation(activationDoc);
|
||||
|
||||
pugi::xml_node root;
|
||||
pugi::xpath_node xpathRes = activationDoc.select_node("//adept:operatorURLList");
|
||||
|
||||
// Create adept:operatorURLList if it doesn't exists
|
||||
if (!xpathRes)
|
||||
{
|
||||
xpathRes = activationDoc.select_node("/activationInfo");
|
||||
root = xpathRes.node();
|
||||
root = root.append_child("adept:operatorURLList");
|
||||
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||
|
||||
appendTextElem(root, "adept:user", user->getUUID());
|
||||
}
|
||||
else
|
||||
root = xpathRes.node();
|
||||
|
||||
appendTextElem(root, "adept:operatorURL", operatorURL);
|
||||
|
||||
user->updateActivationFile(activationDoc);
|
||||
}
|
||||
|
||||
void DRMProcessor::buildFulfillRequest(pugi::xml_document& acsmDoc, pugi::xml_document& fulfillReq)
|
||||
|
@ -468,28 +492,10 @@ namespace gourou
|
|||
appendTextElem(root, "adept:licenseURL", licenseURL);
|
||||
appendTextElem(root, "adept:certificate", certificate);
|
||||
|
||||
// Add new operatorURL to list
|
||||
xpathRes = activationDoc.select_node("//adept:operatorURLList");
|
||||
|
||||
// Create adept:operatorURLList if it doesn't exists
|
||||
if (!xpathRes)
|
||||
{
|
||||
xpathRes = activationDoc.select_node("/activationInfo");
|
||||
root = xpathRes.node();
|
||||
root = root.append_child("adept:operatorURLList");
|
||||
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||
|
||||
appendTextElem(root, "adept:user", user->getUUID());
|
||||
}
|
||||
else
|
||||
root = xpathRes.node();
|
||||
|
||||
appendTextElem(root, "adept:operatorURL", operatorURL);
|
||||
|
||||
user->updateActivationFile(activationDoc);
|
||||
}
|
||||
|
||||
FulfillmentItem* DRMProcessor::fulfill(const std::string& ACSMFile, bool notify)
|
||||
FulfillmentItem* DRMProcessor::fulfill(const std::string& ACSMFile)
|
||||
{
|
||||
if (!user->getPKCS12().length())
|
||||
EXCEPTION(FF_NOT_ACTIVATED, "Device not activated");
|
||||
|
@ -574,12 +580,7 @@ namespace gourou
|
|||
|
||||
fetchLicenseServiceCertificate(licenseURL, operatorURL);
|
||||
|
||||
FulfillmentItem* item = new FulfillmentItem(fulfillReply, user);
|
||||
|
||||
if (notify)
|
||||
notifyServer(fulfillReply);
|
||||
|
||||
return item;
|
||||
return new FulfillmentItem(fulfillReply, user);
|
||||
}
|
||||
|
||||
DRMProcessor::ITEM_TYPE DRMProcessor::download(FulfillmentItem* item, std::string path, bool resume)
|
||||
|
@ -859,28 +860,20 @@ namespace gourou
|
|||
std::string DRMProcessor::getDefaultAdeptDir(void)
|
||||
{
|
||||
#ifndef DEFAULT_ADEPT_DIR
|
||||
const char* home = getenv("HOME");
|
||||
|
||||
if (home)
|
||||
return home + std::string("/.config/adept/");
|
||||
else
|
||||
{
|
||||
const char* user = getenv("USER");
|
||||
const char* user = getenv("USER");
|
||||
|
||||
if (user && user[0])
|
||||
{
|
||||
return std::string("/home/") + user + std::string("/.config/adept/");
|
||||
}
|
||||
else
|
||||
return LOCAL_ADEPT_DIR;
|
||||
}
|
||||
if (user && user[0])
|
||||
{
|
||||
return std::string("/home/") + user + std::string("/.config/adept/");
|
||||
}
|
||||
else
|
||||
return LOCAL_ADEPT_DIR;
|
||||
#else
|
||||
return DEFAULT_ADEPT_DIR "/";
|
||||
#endif
|
||||
}
|
||||
|
||||
void DRMProcessor::returnLoan(const std::string& loanID, const std::string& operatorURL,
|
||||
bool notify)
|
||||
void DRMProcessor::returnLoan(const std::string& loanID, const std::string& operatorURL)
|
||||
{
|
||||
pugi::xml_document returnReq;
|
||||
|
||||
|
@ -888,73 +881,9 @@ namespace gourou
|
|||
|
||||
buildReturnReq(returnReq, loanID, operatorURL);
|
||||
|
||||
ByteArray replyData = sendRequest(returnReq, operatorURL + "/LoanReturn");
|
||||
|
||||
pugi::xml_document fulfillReply;
|
||||
|
||||
fulfillReply.load_string((const char*)replyData.data());
|
||||
|
||||
if (notify)
|
||||
notifyServer(fulfillReply);
|
||||
sendRequest(returnReq, operatorURL + "/LoanReturn");
|
||||
}
|
||||
|
||||
void DRMProcessor::buildNotifyReq(pugi::xml_document& returnReq, pugi::xml_node& body)
|
||||
{
|
||||
pugi::xml_node decl = returnReq.append_child(pugi::node_declaration);
|
||||
decl.append_attribute("version") = "1.0";
|
||||
|
||||
pugi::xml_node root = returnReq.append_child("adept:notification");
|
||||
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||
|
||||
appendTextElem(root, "adept:user", user->getUUID());
|
||||
appendTextElem(root, "adept:device", user->getDeviceUUID());
|
||||
body = root.append_copy(body);
|
||||
body.append_attribute("xmlns") = ADOBE_ADEPT_NS;
|
||||
|
||||
addNonce(root);
|
||||
signNode(root);
|
||||
}
|
||||
|
||||
void DRMProcessor::notifyServer(pugi::xml_node& notifyRoot)
|
||||
{
|
||||
std::string notifyUrl = extractTextElem(notifyRoot, "//notifyURL", false);
|
||||
pugi::xml_node notifyBody = getNode(notifyRoot, "//body", false);
|
||||
|
||||
if (notifyUrl == "")
|
||||
{
|
||||
GOUROU_LOG(INFO, "No notify URL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!notifyBody)
|
||||
{
|
||||
GOUROU_LOG(INFO, "No notify body");
|
||||
return;
|
||||
}
|
||||
|
||||
pugi::xml_document notifyReq;
|
||||
buildNotifyReq(notifyReq, notifyBody);
|
||||
|
||||
sendRequest(notifyReq, notifyUrl);
|
||||
}
|
||||
|
||||
void DRMProcessor::notifyServer(pugi::xml_document& fulfillReply)
|
||||
{
|
||||
pugi::xpath_node_set notifySet = fulfillReply.select_nodes("//notify");
|
||||
|
||||
if (notifySet.empty())
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "No notify request");
|
||||
return;
|
||||
}
|
||||
|
||||
for (pugi::xpath_node_set::const_iterator it = notifySet.begin(); it != notifySet.end(); ++it)
|
||||
{
|
||||
pugi::xml_node notifyRoot = it->node();
|
||||
notifyServer(notifyRoot);
|
||||
}
|
||||
}
|
||||
|
||||
ByteArray DRMProcessor::encryptWithDeviceKey(const unsigned char* data, unsigned int len)
|
||||
{
|
||||
const unsigned char* deviceKey = device->getDeviceKey();
|
||||
|
@ -1324,7 +1253,6 @@ namespace gourou
|
|||
std::vector<uPDFParser::Object*> objects = parser.objects();
|
||||
std::vector<uPDFParser::Object*>::iterator it;
|
||||
std::vector<uPDFParser::Object*>::reverse_iterator rIt;
|
||||
std::vector<uPDFParser::Object*> ebxObjects;
|
||||
unsigned char decryptedKey[16];
|
||||
int ebxId;
|
||||
|
||||
|
@ -1335,7 +1263,7 @@ namespace gourou
|
|||
{
|
||||
EBXHandlerFound = true;
|
||||
uPDFParser::Object* ebx = *rIt;
|
||||
|
||||
|
||||
ebxVersion = (uPDFParser::Integer*)(*ebx)["V"];
|
||||
if (ebxVersion->value() != 4)
|
||||
{
|
||||
|
@ -1346,7 +1274,7 @@ namespace gourou
|
|||
{
|
||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "No ADEPT_LICENSE found");
|
||||
}
|
||||
|
||||
|
||||
uPDFParser::String* licenseObject = (uPDFParser::String*)(*ebx)["ADEPT_LICENSE"];
|
||||
|
||||
std::string value = licenseObject->value();
|
||||
|
@ -1383,7 +1311,7 @@ namespace gourou
|
|||
|
||||
if (object->objectId() == ebxId)
|
||||
{
|
||||
ebxObjects.push_back(object);
|
||||
// object->deleteKey("Filter");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1493,9 +1421,6 @@ namespace gourou
|
|||
}
|
||||
}
|
||||
|
||||
for(it = ebxObjects.begin(); it != ebxObjects.end(); it++)
|
||||
parser.removeObject(*it);
|
||||
|
||||
uPDFParser::Object& trailer = parser.getTrailer();
|
||||
trailer.deleteKey("Encrypt");
|
||||
|
||||
|
|
|
@ -29,13 +29,24 @@ namespace gourou
|
|||
if (!node)
|
||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken element in document");
|
||||
|
||||
node = doc.select_node("/envelope/fulfillmentResult/fulfillment").node();
|
||||
node = doc.select_node("/envelope/loanToken/loan").node();
|
||||
|
||||
if (node)
|
||||
properties["id"] = node.first_child().value();
|
||||
else
|
||||
{
|
||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No fulfillment element in document");
|
||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/loan").node();
|
||||
|
||||
if (node)
|
||||
properties["id"] = node.first_child().value();
|
||||
else
|
||||
{
|
||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/loan").node();
|
||||
if (node)
|
||||
properties["id"] = node.first_child().value();
|
||||
else
|
||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/loan element in document");
|
||||
}
|
||||
}
|
||||
|
||||
node = doc.select_node("/envelope/loanToken/operatorURL").node();
|
||||
|
|
|
@ -46,7 +46,6 @@ static bool exportPrivateKey = false;
|
|||
static const char* outputFile = 0;
|
||||
static const char* outputDir = 0;
|
||||
static bool resume = false;
|
||||
static bool notify = true;
|
||||
|
||||
|
||||
class ACSMDownloader
|
||||
|
@ -83,7 +82,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
gourou::FulfillmentItem* item = processor.fulfill(acsmFile, notify);
|
||||
gourou::FulfillmentItem* item = processor.fulfill(acsmFile);
|
||||
|
||||
std::string filename;
|
||||
if (!outputFile)
|
||||
|
@ -191,7 +190,6 @@ static void usage(const char* cmd)
|
|||
std::cout << " " << "-f|--acsm-file" << "\t" << "Backward compatibility: ACSM request file for epub download" << std::endl;
|
||||
std::cout << " " << "-e|--export-private-key"<< "\t" << "Export private key in DER format" << std::endl;
|
||||
std::cout << " " << "-r|--resume" << "\t\t" << "Try to resume download (in case of previous failure)" << std::endl;
|
||||
std::cout << " " << "-N|--no-notify" << "\t\t" << "Don't notify server, even if requested" << std::endl;
|
||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
||||
|
@ -234,14 +232,13 @@ int main(int argc, char** argv)
|
|||
{"acsm-file", required_argument, 0, 'f' },
|
||||
{"export-private-key",no_argument, 0, 'e' },
|
||||
{"resume", no_argument, 0, 'r' },
|
||||
{"no-notify", no_argument, 0, 'N' },
|
||||
{"verbose", no_argument, 0, 'v' },
|
||||
{"version", no_argument, 0, 'V' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "D:d:a:k:O:o:f:erNvVh",
|
||||
c = getopt_long(argc, argv, "D:d:a:k:O:o:f:ervVh",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -279,9 +276,6 @@ int main(int argc, char** argv)
|
|||
case 'r':
|
||||
resume = true;
|
||||
break;
|
||||
case 'N':
|
||||
notify = false;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
|
|
@ -52,7 +52,6 @@ static const char* devicekeyFile = "devicesalt";
|
|||
static bool list = false;
|
||||
static const char* returnID = 0;
|
||||
static const char* deleteID = 0;
|
||||
static bool notify = true;
|
||||
|
||||
struct Loan
|
||||
{
|
||||
|
@ -183,13 +182,8 @@ private:
|
|||
loan->bookName = node.first_child().value();
|
||||
|
||||
struct tm tm;
|
||||
#ifdef __ANDROID__
|
||||
res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%z", &tm);
|
||||
#else
|
||||
res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%Z", &tm);
|
||||
#endif
|
||||
|
||||
if (res != NULL && *res == 0)
|
||||
if (*res == 0)
|
||||
{
|
||||
if (mktime(&tm) <= time(NULL))
|
||||
loan->validity = " (Expired)";
|
||||
|
@ -229,12 +223,7 @@ private:
|
|||
maxSizeBookName = loan->bookName.size();
|
||||
}
|
||||
|
||||
/* Manage empty names */
|
||||
if (maxSizeBookName == 0)
|
||||
maxSizeBookName = sizeof("No name ")-1;
|
||||
else if (maxSizeBookName < 4)
|
||||
maxSizeBookName = 4;
|
||||
else if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
||||
if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
||||
maxSizeBookName = MAX_SIZE_BOOK_NAME;
|
||||
else if ((maxSizeBookName % 2))
|
||||
maxSizeBookName++;
|
||||
|
@ -281,9 +270,7 @@ private:
|
|||
std::cout << kv.first;
|
||||
std::cout << " ";
|
||||
|
||||
if (loan->bookName.size() == 0)
|
||||
bookName = std::string("No name ");
|
||||
else if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
||||
if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
||||
bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME);
|
||||
else
|
||||
bookName = loan->bookName;
|
||||
|
@ -309,7 +296,7 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
processor.returnLoan(loan->id, loan->operatorURL, notify);
|
||||
processor.returnLoan(loan->id, loan->operatorURL);
|
||||
|
||||
deleteID = returnID;
|
||||
if (deleteLoan(false))
|
||||
|
@ -355,7 +342,6 @@ static void usage(const char* cmd)
|
|||
std::cout << " " << "-l|--list" << "\t\t" << "List all loaned books" << std::endl;
|
||||
std::cout << " " << "-r|--return" << "\t\t" << "Return a loaned book" << std::endl;
|
||||
std::cout << " " << "-d|--delete" << "\t\t" << "Delete a loan entry without returning it" << std::endl;
|
||||
std::cout << " " << "-N|--no-notify" << "\t\t" << "Don't notify server, even if requested" << std::endl;
|
||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
||||
|
@ -389,7 +375,6 @@ int main(int argc, char** argv)
|
|||
{"list", no_argument, 0, 'l' },
|
||||
{"return", no_argument, 0, 'r' },
|
||||
{"delete", no_argument, 0, 'd' },
|
||||
{"no-notify", no_argument, 0, 'N' },
|
||||
{"verbose", no_argument, 0, 'v' },
|
||||
{"version", no_argument, 0, 'V' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
|
@ -417,9 +402,6 @@ int main(int argc, char** argv)
|
|||
deleteID = optarg;
|
||||
actions++;
|
||||
break;
|
||||
case 'N':
|
||||
notify = false;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define OPENSSL_NO_DEPRECATED 1
|
||||
|
||||
|
@ -61,14 +60,6 @@ DRMProcessorClientImpl::DRMProcessorClientImpl():
|
|||
if (!deflt)
|
||||
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL default provider not available");
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
strcpy(cookiejar, "C:\\temp\\libgourou_cookie_jar_XXXXXX");
|
||||
#else
|
||||
strcpy(cookiejar, "/tmp/libgourou_cookie_jar_XXXXXX");
|
||||
#endif
|
||||
|
||||
mkstemp(cookiejar);
|
||||
}
|
||||
|
||||
DRMProcessorClientImpl::~DRMProcessorClientImpl()
|
||||
|
@ -80,8 +71,6 @@ DRMProcessorClientImpl::~DRMProcessorClientImpl()
|
|||
if (deflt)
|
||||
OSSL_PROVIDER_unload(deflt);
|
||||
#endif
|
||||
|
||||
unlink(cookiejar);
|
||||
}
|
||||
|
||||
/* Digest interface */
|
||||
|
@ -238,7 +227,6 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookiejar);
|
||||
|
||||
if (POSTData.size())
|
||||
{
|
||||
|
@ -298,18 +286,11 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||
}
|
||||
|
||||
curl_slist_free_all(list);
|
||||
|
||||
long http_code = 400;
|
||||
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (res != CURLE_OK)
|
||||
EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
|
||||
|
||||
if (http_code >= 400)
|
||||
EXCEPTION(gourou::CLIENT_HTTP_ERROR, "HTTP Error code " << http_code);
|
||||
|
||||
|
||||
if ((downloadedBytes >= DISPLAY_THRESHOLD || replyData.size() >= DISPLAY_THRESHOLD) &&
|
||||
gourou::logLevel >= gourou::LG_LOG_WARN)
|
||||
std::cout << std::endl;
|
||||
|
|
|
@ -136,8 +136,6 @@ private:
|
|||
#else
|
||||
void *legacy, *deflt;
|
||||
#endif
|
||||
|
||||
char cookiejar[64];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user