forked from soutade/libgourou
		
	Add adept_loan_mgt util
This commit is contained in:
		| @@ -1,5 +1,5 @@ | |||||||
|  |  | ||||||
| TARGETS=acsmdownloader adept_activate adept_remove | TARGETS=acsmdownloader adept_activate adept_remove adept_loan_mgt | ||||||
|  |  | ||||||
| CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/ | CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/ | ||||||
|  |  | ||||||
| @@ -18,17 +18,26 @@ else | |||||||
| CXXFLAGS += -O2 | CXXFLAGS += -O2 | ||||||
| endif | endif | ||||||
|  |  | ||||||
| COMMON_DEPS = drmprocessorclientimpl.cpp utils_common.cpp $(STATIC_DEP) | COMMON_DEPS = drmprocessorclientimpl.cpp utils_common.cpp | ||||||
|  | COMMON_OBJECTS = $(COMMON_DEPS:.cpp=.o) | ||||||
|  | COMMON_LIB  = utils.a | ||||||
|  |  | ||||||
| all: $(TARGETS) | all: $(TARGETS) | ||||||
|  |  | ||||||
| acsmdownloader: acsmdownloader.cpp $(COMMON_DEPS) | ${COMMON_LIB}: ${COMMON_DEPS} ${STATIC_DEP} | ||||||
|  | 	$(CXX) $(CXXFLAGS) ${COMMON_DEPS} $(LDFLAGS) -c | ||||||
|  | 	$(AR) crs $@ ${COMMON_OBJECTS} $(STATIC_DEP) | ||||||
|  |  | ||||||
|  | acsmdownloader: acsmdownloader.cpp ${COMMON_LIB} | ||||||
| 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||||
|  |  | ||||||
| adept_activate: adept_activate.cpp $(COMMON_DEPS) | adept_activate: adept_activate.cpp ${COMMON_LIB} | ||||||
| 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||||
|  |  | ||||||
| adept_remove: adept_remove.cpp $(COMMON_DEPS) | adept_remove: adept_remove.cpp ${COMMON_LIB} | ||||||
|  | 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||||
|  |  | ||||||
|  | adept_loan_mgt: adept_loan_mgt.cpp ${COMMON_LIB} | ||||||
| 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||||
|  |  | ||||||
| clean: | clean: | ||||||
|   | |||||||
| @@ -26,12 +26,15 @@ | |||||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
|  #include <getopt.h> | #include <getopt.h> | ||||||
|  | #include <libgen.h> | ||||||
|  |  | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
|  |  | ||||||
| #include <libgourou.h> | #include <libgourou.h> | ||||||
|  | #include <libgourou_common.h> | ||||||
|  |  | ||||||
| #include "drmprocessorclientimpl.h" | #include "drmprocessorclientimpl.h" | ||||||
| #include "utils_common.h" | #include "utils_common.h" | ||||||
|  |  | ||||||
| @@ -54,7 +57,6 @@ public: | |||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
| 	    DRMProcessorClientImpl client; |  | ||||||
| 	    gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile); | 	    gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile); | ||||||
| 	    gourou::User* user = processor.getUser(); | 	    gourou::User* user = processor.getUser(); | ||||||
| 	     | 	     | ||||||
| @@ -118,6 +120,8 @@ public: | |||||||
| 		    filename = finalName; | 		    filename = finalName; | ||||||
| 		} | 		} | ||||||
| 		std::cout << "Created " << filename << std::endl; | 		std::cout << "Created " << filename << std::endl; | ||||||
|  |  | ||||||
|  | 		serializeLoanToken(item); | ||||||
| 	    } | 	    } | ||||||
| 	} catch(std::exception& e) | 	} catch(std::exception& e) | ||||||
| 	{ | 	{ | ||||||
| @@ -127,6 +131,52 @@ public: | |||||||
|  |  | ||||||
| 	return ret; | 	return ret; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void serializeLoanToken(gourou::FulfillmentItem* item) | ||||||
|  |     { | ||||||
|  | 	gourou::LoanToken* token = item->getLoanToken(); | ||||||
|  |  | ||||||
|  | 	// No loan token available | ||||||
|  | 	if (!token) | ||||||
|  | 	    return; | ||||||
|  |  | ||||||
|  | 	pugi::xml_document doc; | ||||||
|  |  | ||||||
|  | 	pugi::xml_node decl = doc.append_child(pugi::node_declaration); | ||||||
|  | 	decl.append_attribute("version") = "1.0"; | ||||||
|  |  | ||||||
|  | 	pugi::xml_node root = doc.append_child("loanToken"); | ||||||
|  | 	gourou::appendTextElem(root, "id",          (*token)["id"]); | ||||||
|  | 	gourou::appendTextElem(root, "operatorURL", (*token)["operatorURL"]); | ||||||
|  | 	gourou::appendTextElem(root, "validity",    (*token)["validity"]); | ||||||
|  | 	gourou::appendTextElem(root, "name",        item->getMetadata("title")); | ||||||
|  |  | ||||||
|  | 	char * activationDir = strdup(deviceFile); | ||||||
|  | 	activationDir = dirname(activationDir); | ||||||
|  | 		 | ||||||
|  | 	gourou::StringXMLWriter xmlWriter; | ||||||
|  | 	doc.save(xmlWriter, "  "); | ||||||
|  | 	std::string xmlStr = xmlWriter.getResult(); | ||||||
|  |  | ||||||
|  | 	// Use first bytes of SHA1(id) as filename | ||||||
|  | 	unsigned char sha1[gourou::SHA1_LEN]; | ||||||
|  | 	client.digest("SHA1", (unsigned char*)(*token)["id"].c_str(), (*token)["id"].size(), sha1); | ||||||
|  | 	gourou::ByteArray tmp(sha1, sizeof(sha1)); | ||||||
|  | 	std::string filenameHex = tmp.toHex(); | ||||||
|  | 	std::string filename(filenameHex.c_str(), ID_HASH_SIZE); | ||||||
|  | 	std::string fullPath = std::string(activationDir); | ||||||
|  | 	fullPath += std::string ("/") + std::string(LOANS_DIR); | ||||||
|  | 	mkpath(fullPath.c_str()); | ||||||
|  | 	fullPath += filename + std::string(".xml"); | ||||||
|  | 	gourou::writeFile(fullPath, xmlStr); | ||||||
|  |  | ||||||
|  | 	std::cout << "Loan token serialized into " << fullPath << std::endl; | ||||||
|  |  | ||||||
|  | 	free(activationDir); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | private: | ||||||
|  |     DRMProcessorClientImpl client; | ||||||
| };	       | };	       | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										479
									
								
								utils/adept_loan_mgt.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										479
									
								
								utils/adept_loan_mgt.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,479 @@ | |||||||
|  | /* | ||||||
|  |   Copyright (c) 2022, Grégory Soutadé | ||||||
|  |  | ||||||
|  |   All rights reserved. | ||||||
|  |   Redistribution and use in source and binary forms, with or without | ||||||
|  |   modification, are permitted provided that the following conditions are met: | ||||||
|  |    | ||||||
|  |   * Redistributions of source code must retain the above copyright | ||||||
|  |     notice, this list of conditions and the following disclaimer. | ||||||
|  |   * Redistributions in binary form must reproduce the above copyright | ||||||
|  |     notice, this list of conditions and the following disclaimer in the | ||||||
|  |     documentation and/or other materials provided with the distribution. | ||||||
|  |   * Neither the name of the copyright holder nor the | ||||||
|  |     names of its contributors may be used to endorse or promote products | ||||||
|  |     derived from this software without specific prior written permission. | ||||||
|  |    | ||||||
|  |   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||||
|  |   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  |   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  |   DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||||
|  |   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  |   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  |   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  |   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  |   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  |   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <getopt.h> | ||||||
|  |  | ||||||
|  | #include <iostream> | ||||||
|  | #include <algorithm> | ||||||
|  |  | ||||||
|  | #define _XOPEN_SOURCE 700 | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <dirent.h> | ||||||
|  | #include <libgen.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | #include <libgourou.h> | ||||||
|  | #include <libgourou_common.h> | ||||||
|  | #include "drmprocessorclientimpl.h" | ||||||
|  | #include "utils_common.h" | ||||||
|  |  | ||||||
|  | #define MAX_SIZE_BOOK_NAME   30 | ||||||
|  |  | ||||||
|  | static       char* activationDir  = 0; | ||||||
|  | static const char* deviceFile     = "device.xml"; | ||||||
|  | static const char* activationFile = "activation.xml"; | ||||||
|  | static const char* devicekeyFile  = "devicesalt"; | ||||||
|  | static       bool  list           = false; | ||||||
|  | static const char* returnID       = 0; | ||||||
|  | static const char* deleteID       = 0; | ||||||
|  |  | ||||||
|  | struct Loan | ||||||
|  | { | ||||||
|  |     std::string id; | ||||||
|  |     std::string operatorURL; | ||||||
|  |     std::string validity; | ||||||
|  |     std::string bookName; | ||||||
|  |      | ||||||
|  |     std::string path; | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | class LoanMGT | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     ~LoanMGT() | ||||||
|  |     { | ||||||
|  | 	for (const auto& kv : loanedBooks) | ||||||
|  | 	    delete kv.second; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     int run() | ||||||
|  |     { | ||||||
|  | 	int ret = 0; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 	    DRMProcessorClientImpl client; | ||||||
|  | 	    gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile); | ||||||
|  |  | ||||||
|  | 	    loadLoanedBooks(); | ||||||
|  |  | ||||||
|  | 	    if (list) | ||||||
|  | 		displayLoanList(); | ||||||
|  | 	    else if (returnID) | ||||||
|  | 		returnBook(processor); | ||||||
|  | 	    else if (deleteID) | ||||||
|  | 		deleteLoan(); | ||||||
|  | 	} catch(std::exception& e) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << e.what() << std::endl; | ||||||
|  | 	    ret = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void loadLoanedBooks() | ||||||
|  |     { | ||||||
|  | 	DIR *dp; | ||||||
|  | 	struct dirent *ep; | ||||||
|  | 	int entryLen; | ||||||
|  | 	struct Loan* loan; | ||||||
|  | 	char * res; | ||||||
|  | 	 | ||||||
|  | 	std::string loanDir = std::string(activationDir) + std::string("/") + LOANS_DIR; | ||||||
|  |  | ||||||
|  | 	if (!fileExists(loanDir.c_str())) | ||||||
|  | 	    return; | ||||||
|  | 	 | ||||||
|  | 	dp = opendir (loanDir.c_str()); | ||||||
|  |  | ||||||
|  | 	if(!dp) | ||||||
|  | 	    EXCEPTION(gourou::USER_INVALID_INPUT, "Cannot read directory " << loanDir); | ||||||
|  |  | ||||||
|  | 	while ((ep = readdir (dp))) | ||||||
|  | 	{ | ||||||
|  | 	    if (ep->d_type != DT_LNK && | ||||||
|  | 		ep->d_type != DT_REG) | ||||||
|  | 		continue; | ||||||
|  |  | ||||||
|  | 	    entryLen = strlen(ep->d_name); | ||||||
|  |  | ||||||
|  | 	    if (entryLen <= 4 || | ||||||
|  | 		ep->d_name[entryLen-4] != '.' || | ||||||
|  | 		ep->d_name[entryLen-3] != 'x' || | ||||||
|  | 		ep->d_name[entryLen-2] != 'm' || | ||||||
|  | 		ep->d_name[entryLen-1] != 'l') | ||||||
|  | 		continue; | ||||||
|  |  | ||||||
|  | 	    std::string id = std::string(ep->d_name, entryLen-4); | ||||||
|  | 	     | ||||||
|  | 	    loan = new Loan; | ||||||
|  | 	    loan->path = loanDir + std::string("/") + ep->d_name; | ||||||
|  |  | ||||||
|  | 	    pugi::xml_document xmlDoc; | ||||||
|  | 	    pugi::xml_node node; | ||||||
|  |  | ||||||
|  | 	    if (!xmlDoc.load_file(loan->path.c_str(), pugi::parse_ws_pcdata_single|pugi::parse_escapes, pugi::encoding_utf8)) | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Invalid loan entry " << loan->path << std::endl; | ||||||
|  | 		goto error; | ||||||
|  | 	    } | ||||||
|  |  | ||||||
|  | 	    // id | ||||||
|  | 	    node = xmlDoc.select_node("//id").node(); | ||||||
|  | 	    if (!node) | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Invalid loan entry " << ep->d_name << ", no id element" << std::endl; | ||||||
|  | 		goto error; | ||||||
|  | 	    } | ||||||
|  | 	    loan->id = node.first_child().value(); | ||||||
|  |  | ||||||
|  | 	    // operatorURL | ||||||
|  | 	    node = xmlDoc.select_node("//operatorURL").node(); | ||||||
|  | 	    if (!node) | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Invalid loan entry " << ep->d_name << ", no operatorURL element" << std::endl; | ||||||
|  | 		goto error; | ||||||
|  | 	    } | ||||||
|  | 	    loan->operatorURL = node.first_child().value(); | ||||||
|  |  | ||||||
|  | 	    // validity | ||||||
|  | 	    node = xmlDoc.select_node("//validity").node(); | ||||||
|  | 	    if (!node) | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Invalid loan entry " << ep->d_name << ", no validity element" << std::endl; | ||||||
|  | 		goto error; | ||||||
|  | 	    } | ||||||
|  | 	    loan->validity = node.first_child().value(); | ||||||
|  |  | ||||||
|  | 	    // bookName | ||||||
|  | 	    node = xmlDoc.select_node("//name").node(); | ||||||
|  | 	    if (!node) | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Invalid loan entry " << ep->d_name << ", no name element" << std::endl; | ||||||
|  | 		goto error; | ||||||
|  | 	    } | ||||||
|  | 	    loan->bookName = node.first_child().value(); | ||||||
|  |  | ||||||
|  | 	    struct tm tm; | ||||||
|  | 	    res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%Z", &tm); | ||||||
|  | 	    if (*res == 0) | ||||||
|  | 	    { | ||||||
|  | 		if (mktime(&tm) <= time(NULL)) | ||||||
|  | 		    loan->validity = "     (Expired)"; | ||||||
|  | 	    } | ||||||
|  | 	    else | ||||||
|  | 	    { | ||||||
|  | 		std::cout << "Unable to parse validity timestamp :" << loan->validity << std::endl; | ||||||
|  | 		loan->validity = "     (Unknown)"; | ||||||
|  | 	    } | ||||||
|  | 	     | ||||||
|  | 	    loanedBooks[id] = loan; | ||||||
|  | 	    continue; | ||||||
|  |  | ||||||
|  | 	error: | ||||||
|  | 	    if (loan) | ||||||
|  | 		delete loan; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	closedir (dp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void displayLoanList() | ||||||
|  |     { | ||||||
|  | 	if (!loanedBooks.size()) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Any book loaned" << std::endl; | ||||||
|  | 	    return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	struct Loan* loan; | ||||||
|  | 	unsigned int maxSizeBookName=0; | ||||||
|  | 	// Compute max size | ||||||
|  | 	for (const auto& kv : loanedBooks) | ||||||
|  | 	{ | ||||||
|  | 	    loan = kv.second; | ||||||
|  | 	    if (loan->bookName.size() > maxSizeBookName) | ||||||
|  | 		maxSizeBookName = loan->bookName.size(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (maxSizeBookName > MAX_SIZE_BOOK_NAME) | ||||||
|  | 	    maxSizeBookName = MAX_SIZE_BOOK_NAME; | ||||||
|  | 	else if ((maxSizeBookName % 2)) | ||||||
|  | 	    maxSizeBookName++; | ||||||
|  |  | ||||||
|  | 	// std::cout << "  ID      Book      Expiration" << std::endl; | ||||||
|  | 	// std::cout << "------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  | 	int fillID, fillBookName, fillExpiration=(20 - 10)/2; | ||||||
|  | 	 | ||||||
|  | 	fillID = (ID_HASH_SIZE - 2) / 2; | ||||||
|  | 	fillBookName = (maxSizeBookName - 4) / 2; | ||||||
|  |  | ||||||
|  | 	std::cout.width (fillID); | ||||||
|  | 	std::cout << ""; | ||||||
|  | 	std::cout << "ID" ; | ||||||
|  | 	std::cout.width (fillID); | ||||||
|  | 	std::cout << ""; | ||||||
|  | 	std::cout << "    " ; | ||||||
|  | 	 | ||||||
|  | 	std::cout.width (fillBookName); | ||||||
|  | 	std::cout << ""; | ||||||
|  | 	std::cout << "Book" ; | ||||||
|  | 	std::cout.width (fillBookName); | ||||||
|  | 	std::cout << ""; | ||||||
|  | 	std::cout << "    " ; | ||||||
|  |  | ||||||
|  | 	std::cout.width (fillExpiration); | ||||||
|  | 	std::cout << ""; | ||||||
|  | 	std::cout << "Exipration"; | ||||||
|  | 	std::cout.width (fillExpiration); | ||||||
|  | 	std::cout << "" << std::endl; | ||||||
|  |  | ||||||
|  | 	std::cout.fill ('-'); | ||||||
|  | 	std::cout.width (ID_HASH_SIZE + 4 + maxSizeBookName + 4 + 20); | ||||||
|  | 	std::cout << "" << std::endl; | ||||||
|  | 	std::cout.fill (' '); | ||||||
|  |  | ||||||
|  | 	std::string bookName; | ||||||
|  |  | ||||||
|  | 	for (const auto& kv : loanedBooks) | ||||||
|  | 	{ | ||||||
|  | 	    loan = kv.second; | ||||||
|  |  | ||||||
|  | 	    std::cout << kv.first; | ||||||
|  | 	    std::cout << "    "; | ||||||
|  |  | ||||||
|  | 	    if (loan->bookName.size() > MAX_SIZE_BOOK_NAME) | ||||||
|  | 		bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME); | ||||||
|  | 	    else | ||||||
|  | 		bookName = loan->bookName; | ||||||
|  |  | ||||||
|  | 	    std::cout << bookName; | ||||||
|  | 	    std::cout.width (maxSizeBookName - bookName.size()); | ||||||
|  | 	    std::cout << ""; | ||||||
|  | 	    std::cout << "    "; | ||||||
|  | 	     | ||||||
|  | 	    std::cout << loan->validity << std::endl; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	std::cout << std::endl; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void returnBook(gourou::DRMProcessor& processor) | ||||||
|  |     { | ||||||
|  | 	struct Loan* loan = loanedBooks[std::string(returnID)]; | ||||||
|  |  | ||||||
|  | 	if (!loan) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Error : Loan " << returnID << " doesn't exists" << std::endl; | ||||||
|  | 	    return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	processor.returnLoan(loan->id, loan->operatorURL); | ||||||
|  | 	 | ||||||
|  | 	deleteID = returnID; | ||||||
|  | 	if (deleteLoan(false)) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Loan " << returnID << " successfully returned" << std::endl; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     bool deleteLoan(bool displayResult=true) | ||||||
|  |     { | ||||||
|  | 	struct Loan* loan = loanedBooks[std::string(deleteID)]; | ||||||
|  |  | ||||||
|  | 	if (!loan) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Error : Loan " << deleteID << " doesn't exists" << std::endl; | ||||||
|  | 	    return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (unlink(loan->path.c_str())) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Error : Cannot delete " << loan->path << std::endl; | ||||||
|  | 	    return false; | ||||||
|  | 	} | ||||||
|  | 	else if (displayResult) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Loan " << deleteID << " deleted" << std::endl; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::map<std::string, struct Loan*> loanedBooks; | ||||||
|  | };	       | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void usage(const char* cmd) | ||||||
|  | { | ||||||
|  |     std::cout << "Manage loaned books" << std::endl; | ||||||
|  |      | ||||||
|  |     std::cout << "Usage: " << cmd << " [(-d|--activation-dir) dir] (-l|--list)|(-D|--delete loanID)|(-R|--delete loanID) [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl; | ||||||
|  |      | ||||||
|  |     std::cout << "  " << "-d|--activation-dir"  << "\t"   << "Directory of device.xml/activation.xml and device key" << std::endl; | ||||||
|  |     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 << "  " << "-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; | ||||||
|  |  | ||||||
|  |     std::cout << std::endl; | ||||||
|  |     std::cout << "Activation directory is optional. If not set, it's 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}; | ||||||
|  |     int verbose = gourou::DRMProcessor::getLogLevel(); | ||||||
|  |     int actions = 0; | ||||||
|  |      | ||||||
|  |     while (1) { | ||||||
|  | 	int option_index = 0; | ||||||
|  | 	static struct option long_options[] = { | ||||||
|  | 	    {"activation-dir",   required_argument, 0,  'd' }, | ||||||
|  | 	    {"list",             no_argument,       0,  'l' }, | ||||||
|  | 	    {"return",           no_argument,       0,  'r' }, | ||||||
|  | 	    {"delete",           no_argument,       0,  'D' }, | ||||||
|  | 	    {"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:lr:D:vVh", | ||||||
|  |                         long_options, &option_index); | ||||||
|  | 	if (c == -1) | ||||||
|  | 	    break; | ||||||
|  |  | ||||||
|  | 	switch (c) { | ||||||
|  | 	case 'd': | ||||||
|  | 	    activationDir = optarg; | ||||||
|  | 	    break; | ||||||
|  | 	case 'l': | ||||||
|  | 	    list = true; | ||||||
|  | 	    actions++; | ||||||
|  | 	    break; | ||||||
|  | 	case 'r': | ||||||
|  | 	    returnID = optarg; | ||||||
|  | 	    actions++; | ||||||
|  | 	    break; | ||||||
|  | 	case 'D': | ||||||
|  | 	    deleteID = optarg; | ||||||
|  | 	    actions++; | ||||||
|  | 	    break; | ||||||
|  | 	case 'v': | ||||||
|  | 	    verbose++; | ||||||
|  | 	    break; | ||||||
|  | 	case 'V': | ||||||
|  | 	    version(); | ||||||
|  | 	    return 0; | ||||||
|  | 	case 'h': | ||||||
|  | 	    usage(argv[0]); | ||||||
|  | 	    return 0; | ||||||
|  | 	default: | ||||||
|  | 	    usage(argv[0]); | ||||||
|  | 	    return -1; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     | ||||||
|  |     gourou::DRMProcessor::setLogLevel(verbose); | ||||||
|  |  | ||||||
|  |     // By default, simply list books loaned | ||||||
|  |     if (actions == 0) | ||||||
|  | 	list = true; | ||||||
|  |     else if (actions != 1) | ||||||
|  |     { | ||||||
|  | 	usage(argv[0]); | ||||||
|  | 	return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     LoanMGT loanMGT; | ||||||
|  |  | ||||||
|  |     int i; | ||||||
|  |     bool hasErrors = false; | ||||||
|  |     const char* orig; | ||||||
|  |     char *filename; | ||||||
|  |     for (i=0; i<(int)ARRAY_SIZE(files); i++) | ||||||
|  |     { | ||||||
|  | 	orig = *files[i]; | ||||||
|  | 	 | ||||||
|  | 	if (activationDir) | ||||||
|  | 	{ | ||||||
|  | 	    std::string path = std::string(activationDir) + std::string("/") + orig; | ||||||
|  | 	    filename = strdup(path.c_str()); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	    filename = strdup(orig); | ||||||
|  | 	*files[i] = findFile(filename); | ||||||
|  | 	free(filename); | ||||||
|  | 	if (!*files[i]) | ||||||
|  | 	{ | ||||||
|  | 	    std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl; | ||||||
|  | 	    hasErrors = true; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (hasErrors) | ||||||
|  |     { | ||||||
|  | 	// In case of activation dir was provided by user | ||||||
|  | 	activationDir = 0; | ||||||
|  | 	goto end; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (activationDir) | ||||||
|  | 	activationDir = strdup(activationDir); // For below free | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  | 	activationDir = strdup(deviceFile); | ||||||
|  | 	activationDir = dirname(activationDir); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = loanMGT.run(); | ||||||
|  |      | ||||||
|  | end: | ||||||
|  |     for (i=0; i<(int)ARRAY_SIZE(files); i++) | ||||||
|  |     { | ||||||
|  | 	if (*files[i]) | ||||||
|  | 	    free((void*)*files[i]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (activationDir) | ||||||
|  | 	free(activationDir); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
| @@ -29,6 +29,9 @@ | |||||||
| #ifndef _UTILS_COMMON_H_ | #ifndef _UTILS_COMMON_H_ | ||||||
| #define _UTILS_COMMON_H_ | #define _UTILS_COMMON_H_ | ||||||
|  |  | ||||||
|  | #define LOANS_DIR            "loans/" | ||||||
|  | #define ID_HASH_SIZE         16 | ||||||
|  |  | ||||||
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) | #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user