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/ | ||||
|  | ||||
| @@ -18,17 +18,26 @@ else | ||||
| CXXFLAGS += -O2 | ||||
| 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) | ||||
|  | ||||
| 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 $@ | ||||
|  | ||||
| adept_activate: adept_activate.cpp $(COMMON_DEPS) | ||||
| adept_activate: adept_activate.cpp ${COMMON_LIB} | ||||
| 	$(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 $@ | ||||
|  | ||||
| clean: | ||||
|   | ||||
| @@ -26,12 +26,15 @@ | ||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
|  | ||||
|  #include <getopt.h> | ||||
| #include <getopt.h> | ||||
| #include <libgen.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
|  | ||||
| #include <libgourou.h> | ||||
| #include <libgourou_common.h> | ||||
|  | ||||
| #include "drmprocessorclientimpl.h" | ||||
| #include "utils_common.h" | ||||
|  | ||||
| @@ -54,7 +57,6 @@ public: | ||||
| 	int ret = 0; | ||||
| 	try | ||||
| 	{ | ||||
| 	    DRMProcessorClientImpl client; | ||||
| 	    gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile); | ||||
| 	    gourou::User* user = processor.getUser(); | ||||
| 	     | ||||
| @@ -118,6 +120,8 @@ public: | ||||
| 		    filename = finalName; | ||||
| 		} | ||||
| 		std::cout << "Created " << filename << std::endl; | ||||
|  | ||||
| 		serializeLoanToken(item); | ||||
| 	    } | ||||
| 	} catch(std::exception& e) | ||||
| 	{ | ||||
| @@ -127,6 +131,52 @@ public: | ||||
|  | ||||
| 	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_ | ||||
| #define _UTILS_COMMON_H_ | ||||
|  | ||||
| #define LOANS_DIR            "loans/" | ||||
| #define ID_HASH_SIZE         16 | ||||
|  | ||||
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) | ||||
|  | ||||
| /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user