diff options
author | methodus <methodus@web.de> | 2012-10-29 02:42:08 +0100 |
---|---|---|
committer | methodus <methodus@web.de> | 2012-10-29 02:42:08 +0100 |
commit | 2d082611ac1f51f3a0ce86d29b8e3d674ad6e3b0 (patch) | |
tree | 541397a1493ff46bffef7c64b2e39fc56ab43148 | |
parent | 0deea38705627533ab074d51247d37b7a783606a (diff) | |
download | vdr-plugin-upnp-2d082611ac1f51f3a0ce86d29b8e3d674ad6e3b0.tar.gz vdr-plugin-upnp-2d082611ac1f51f3a0ce86d29b8e3d674ad6e3b0.tar.bz2 |
Added CLI parameter for setting the database directory. Also fixed segfault, if databse file can't be opened
-rw-r--r-- | common/setup.cpp | 19 | ||||
-rw-r--r-- | include/config.h | 4 | ||||
-rw-r--r-- | include/media/mediaManager.h | 2 | ||||
-rw-r--r-- | include/setup.h | 4 | ||||
-rw-r--r-- | media/mediaManager.cpp | 216 | ||||
-rw-r--r-- | server/server.cpp | 4 | ||||
-rw-r--r-- | upnp.cpp | 36 |
7 files changed, 166 insertions, 119 deletions
diff --git a/common/setup.cpp b/common/setup.cpp index b4704f3..ed6e929 100644 --- a/common/setup.cpp +++ b/common/setup.cpp @@ -71,7 +71,7 @@ void cMenuSetupUPnP::Update(){ dbCat->SetSelectable(false); Add(dbCat); - Add(new cMenuEditStrItem(tr("Path to database file"), databaseFile, STRING_SIZE)); + Add(new cMenuEditStrItem(tr("Path to database file"), databaseDir, STRING_SIZE)); } SetCurrent(Get(current)); @@ -134,7 +134,7 @@ void cMenuSetupUPnP::Load(){ strn0cpy(webserverRoot, config.webServerRoot.c_str(), STRING_SIZE); strn0cpy(address, config.address.c_str(), 16); strn0cpy(interface, config.interface.c_str(), 16); - strn0cpy(databaseFile, config.databaseFile.c_str(), STRING_SIZE); + strn0cpy(databaseDir, config.databaseDir.c_str(), STRING_SIZE); strn0cpy(presentationUrl, config.presentationURL.c_str(), STRING_SIZE); strn0cpy(deviceUUID, config.deviceUUID.c_str(), STRING_SIZE); } @@ -145,7 +145,7 @@ void cMenuSetupUPnP::Store(){ config.webServerRoot = webserverRoot; config.address = address; config.interface = interface; - config.databaseFile = databaseFile; + config.databaseDir = databaseDir; config.presentationURL = presentationUrl; config.bindToAddress = switchBindAddress?true:false; @@ -171,12 +171,19 @@ void cMenuSetupUPnP::Store(){ SetupStore("address", config.address.c_str()); SetupStore("interface", config.interface.c_str()); SetupStore("port", config.port); - SetupStore("databaseFile", config.databaseFile.c_str()); + SetupStore("databaseDir", config.databaseDir.c_str()); } +std::string cMenuSetupUPnP::parsedArgs; + bool cMenuSetupUPnP::SetupParse(const char *name, const char *value, upnp::cConfig& config) { + if(parsedArgs.find(name) != std::string::npos){ + dsyslog("UPnP\tSkipping %s=%s, was overridden in command line.", name, value); + return true; + } + if (strcasecmp(name, "enabled")==0) config.enabled = atoi(value)?true:false; else if (strcasecmp(name, "expertSettings")==0) config.expertSettings = atoi(value)?true:false; else if (strcasecmp(name, "webServerRoot")==0) config.webServerRoot = value; @@ -191,9 +198,11 @@ bool cMenuSetupUPnP::SetupParse(const char *name, const char *value, upnp::cConf else if (strcasecmp(name, "address")==0) config.address = value; else if (strcasecmp(name, "interface")==0) config.interface = value; else if (strcasecmp(name, "port")==0) config.port = (uint16_t)atoi(value); - else if (strcasecmp(name, "databaseFile")==0) config.databaseFile = value; + else if (strcasecmp(name, "databaseDir")==0) config.databaseDir = value; else return false; + parsedArgs += name; + return true; } diff --git a/include/config.h b/include/config.h index 187e46f..f36491c 100644 --- a/include/config.h +++ b/include/config.h @@ -104,9 +104,9 @@ struct cConfig { /** * The sqlite database file * - * This is the path to the database file. + * This is the path where the database file shall be located. */ - string databaseFile; + string databaseDir; }; } diff --git a/include/media/mediaManager.h b/include/media/mediaManager.h index 265e024..f7d803c 100644 --- a/include/media/mediaManager.h +++ b/include/media/mediaManager.h @@ -58,7 +58,7 @@ public: virtual ~cMediaManager(); void SetPluginDirectory(const string& directory); - void SetDatabaseFile(const string& file); + void SetDatabaseDir(const string& file); bool Initialise(); diff --git a/include/setup.h b/include/setup.h index 6ff0961..392c246 100644 --- a/include/setup.h +++ b/include/setup.h @@ -92,7 +92,7 @@ private: char presentationUrl[STRING_SIZE]; char address[16]; char interface[16]; - char databaseFile[STRING_SIZE]; + char databaseDir[STRING_SIZE]; char deviceUUID[STRING_SIZE]; upnp::cConfig config; @@ -104,6 +104,8 @@ private: int ifaceCount; upnp::StringVector ifaceVector; + static std::string parsedArgs; + }; #endif /* SETUP_H_ */ diff --git a/media/mediaManager.cpp b/media/mediaManager.cpp index 9649cdc..1c9eaf2 100644 --- a/media/mediaManager.cpp +++ b/media/mediaManager.cpp @@ -110,7 +110,7 @@ cMediaManager::cMediaManager() , pluginDirectory(DEFAULTPLUGINDIR) , pluginManager(NULL) { - SetDatabaseFile(string()); + SetDatabaseDir(string()); } cMediaManager::~cMediaManager(){ @@ -478,112 +478,116 @@ bool cMediaManager::Initialise(){ dsyslog("UPNP\tPreparing database structure..."); if(!CheckIntegrity()){ - connection.beginTransaction(); - - ss.str(string()); - - ss << "CREATE TABLE " << db::Metadata - << "(" - << "`" << property::object::KEY_OBJECTID << "` TEXT PRIMARY KEY," - << "`" << property::object::KEY_PARENTID << "` TEXT NOT NULL," - << "`" << property::object::KEY_TITLE << "` TEXT NOT NULL," - << "`" << property::object::KEY_CLASS << "` TEXT NOT NULL," - << "`" << property::object::KEY_RESTRICTED << "` INTEGER NOT NULL," - << "`" << property::object::KEY_CREATOR << "` TEXT," - << "`" << property::object::KEY_DESCRIPTION << "` TEXT," - << "`" << property::object::KEY_LONG_DESCRIPTION << "` TEXT," - << "`" << property::object::KEY_DATE << "` TEXT," - << "`" << property::object::KEY_LANGUAGE << "` TEXT," - << "`" << property::object::KEY_CHANNEL_NR << "` INTEGER," - << "`" << property::object::KEY_CHANNEL_NAME << "` TEXT," - << "`" << property::object::KEY_SCHEDULED_START << "` TEXT," - << "`" << property::object::KEY_SCHEDULED_END << "` TEXT," - << "`" << property::object::KEY_OBJECT_UPDATE_ID << "` INTEGER" - << ")"; - - tntdb::Statement objectTable = connection.prepare(ss.str()); - - objectTable.execute(); - - ss.str(string()); - - ss << "CREATE TABLE " << db::Details - << "(" - << " `propertyID` INTEGER PRIMARY KEY," - << " `" << property::object::KEY_OBJECTID << "` TEXT " - << " REFERENCES metadata (`"<< property::object::KEY_OBJECTID <<"`) ON DELETE CASCADE ON UPDATE CASCADE," - << " `property` TEXT," - << " `value` TEXT" - << ")"; - - tntdb::Statement detailsTable = connection.prepare(ss.str()); - - detailsTable.execute(); - - ss.str(string()); - - ss << "CREATE TABLE " << db::Resources - << "(" - << "`" << property::object::KEY_OBJECTID << "` TEXT " - << "REFERENCES metadata (`"<< property::object::KEY_OBJECTID <<"`) ON DELETE CASCADE ON UPDATE CASCADE," - << "`" << property::resource::KEY_RESOURCE << "` TEXT," - << "`" << property::resource::KEY_PROTOCOL_INFO << "` TEXT NOT NULL," - << "`" << property::resource::KEY_SIZE << "` INTEGER," - << "`" << property::resource::KEY_DURATION << "` TEXT," - << "`" << property::resource::KEY_RESOLUTION << "` TEXT," - << "`" << property::resource::KEY_BITRATE << "` INTEGER," - << "`" << property::resource::KEY_SAMPLE_FREQUENCY << "` INTEGER," - << "`" << property::resource::KEY_BITS_PER_SAMPLE << "` INTEGER," - << "`" << property::resource::KEY_NR_AUDIO_CHANNELS << "` INTEGER," - << "`" << property::resource::KEY_COLOR_DEPTH << "` INTEGER," - << "PRIMARY KEY (" - << "`" << property::object::KEY_OBJECTID << "`," - << "`" << property::resource::KEY_RESOURCE << "`" - << ")" - << ")"; - - tntdb::Statement resourcesTable = connection.prepare(ss.str()); - - resourcesTable.execute(); - - ss.str(string()); - - ss << "INSERT INTO " << db::Metadata << " (" - << "`" << property::object::KEY_OBJECTID << "`, " - << "`" << property::object::KEY_PARENTID << "`, " - << "`" << property::object::KEY_TITLE << "`, " - << "`" << property::object::KEY_CLASS << "`, " - << "`" << property::object::KEY_RESTRICTED << "`, " - << "`" << property::object::KEY_CREATOR << "`, " - << "`" << property::object::KEY_DESCRIPTION << "`, " - << "`" << property::object::KEY_LONG_DESCRIPTION << "`) " - << " VALUES (:objectID, :parentID, :title, :class, :restricted, :creator, :description, :longDescription)"; - - tntdb::Statement rootContainer = connection.prepare(ss.str()); - - const cMediaServer::Description desc = cMediaServer::GetInstance()->GetServerDescription(); - - rootContainer.setString("objectID", "0") - .setString("parentID", "-1") - .setString("title", desc.friendlyName) - .setString("creator", desc.manufacturer) - .setString("class", "object.container") - .setBool("restricted", true) - .setString("description", desc.modelName) - .setString("longDescription", desc.modelDescription) - .execute(); + try { + + connection.beginTransaction(); + + ss.str(string()); + + ss << "CREATE TABLE " << db::Metadata + << "(" + << "`" << property::object::KEY_OBJECTID << "` TEXT PRIMARY KEY," + << "`" << property::object::KEY_PARENTID << "` TEXT NOT NULL," + << "`" << property::object::KEY_TITLE << "` TEXT NOT NULL," + << "`" << property::object::KEY_CLASS << "` TEXT NOT NULL," + << "`" << property::object::KEY_RESTRICTED << "` INTEGER NOT NULL," + << "`" << property::object::KEY_CREATOR << "` TEXT," + << "`" << property::object::KEY_DESCRIPTION << "` TEXT," + << "`" << property::object::KEY_LONG_DESCRIPTION << "` TEXT," + << "`" << property::object::KEY_DATE << "` TEXT," + << "`" << property::object::KEY_LANGUAGE << "` TEXT," + << "`" << property::object::KEY_CHANNEL_NR << "` INTEGER," + << "`" << property::object::KEY_CHANNEL_NAME << "` TEXT," + << "`" << property::object::KEY_SCHEDULED_START << "` TEXT," + << "`" << property::object::KEY_SCHEDULED_END << "` TEXT," + << "`" << property::object::KEY_OBJECT_UPDATE_ID << "` INTEGER" + << ")"; + + tntdb::Statement objectTable = connection.prepare(ss.str()); + + objectTable.execute(); + + ss.str(string()); + + ss << "CREATE TABLE " << db::Details + << "(" + << " `propertyID` INTEGER PRIMARY KEY," + << " `" << property::object::KEY_OBJECTID << "` TEXT " + << " REFERENCES metadata (`"<< property::object::KEY_OBJECTID <<"`) ON DELETE CASCADE ON UPDATE CASCADE," + << " `property` TEXT," + << " `value` TEXT" + << ")"; + + tntdb::Statement detailsTable = connection.prepare(ss.str()); + + detailsTable.execute(); + + ss.str(string()); + + ss << "CREATE TABLE " << db::Resources + << "(" + << "`" << property::object::KEY_OBJECTID << "` TEXT " + << "REFERENCES metadata (`"<< property::object::KEY_OBJECTID <<"`) ON DELETE CASCADE ON UPDATE CASCADE," + << "`" << property::resource::KEY_RESOURCE << "` TEXT," + << "`" << property::resource::KEY_PROTOCOL_INFO << "` TEXT NOT NULL," + << "`" << property::resource::KEY_SIZE << "` INTEGER," + << "`" << property::resource::KEY_DURATION << "` TEXT," + << "`" << property::resource::KEY_RESOLUTION << "` TEXT," + << "`" << property::resource::KEY_BITRATE << "` INTEGER," + << "`" << property::resource::KEY_SAMPLE_FREQUENCY << "` INTEGER," + << "`" << property::resource::KEY_BITS_PER_SAMPLE << "` INTEGER," + << "`" << property::resource::KEY_NR_AUDIO_CHANNELS << "` INTEGER," + << "`" << property::resource::KEY_COLOR_DEPTH << "` INTEGER," + << "PRIMARY KEY (" + << "`" << property::object::KEY_OBJECTID << "`," + << "`" << property::resource::KEY_RESOURCE << "`" + << ")" + << ")"; + + tntdb::Statement resourcesTable = connection.prepare(ss.str()); + + resourcesTable.execute(); + + ss.str(string()); + + ss << "INSERT INTO " << db::Metadata << " (" + << "`" << property::object::KEY_OBJECTID << "`, " + << "`" << property::object::KEY_PARENTID << "`, " + << "`" << property::object::KEY_TITLE << "`, " + << "`" << property::object::KEY_CLASS << "`, " + << "`" << property::object::KEY_RESTRICTED << "`, " + << "`" << property::object::KEY_CREATOR << "`, " + << "`" << property::object::KEY_DESCRIPTION << "`, " + << "`" << property::object::KEY_LONG_DESCRIPTION << "`) " + << " VALUES (:objectID, :parentID, :title, :class, :restricted, :creator, :description, :longDescription)"; + + tntdb::Statement rootContainer = connection.prepare(ss.str()); + + const cMediaServer::Description desc = cMediaServer::GetInstance()->GetServerDescription(); + + rootContainer.setString("objectID", "0") + .setString("parentID", "-1") + .setString("title", desc.friendlyName) + .setString("creator", desc.manufacturer) + .setString("class", "object.container") + .setBool("restricted", true) + .setString("description", desc.modelName) + .setString("longDescription", desc.modelDescription) + .execute(); + + connection.commitTransaction(); + + } catch (const std::exception& e) { + esyslog("UPnP\tException occurred while initializing database '%s': %s", databaseFile.c_str(), e.what()); + connection.rollbackTransaction(); + + return false; + } - connection.commitTransaction(); } } catch (const std::exception& e) { - - if(!connection){ - esyslog("UPnP\tException occurred while connecting to database '%s': %s", databaseFile.c_str(), e.what()); - } else { - esyslog("UPnP\tException occurred while initializing database '%s': %s", databaseFile.c_str(), e.what()); - connection.rollbackTransaction(); - } + esyslog("UPnP\tException occurred while connecting to database '%s': %s", databaseFile.c_str(), e.what()); return false; } @@ -707,10 +711,12 @@ cUPnPResourceProvider* cMediaManager::CreateResourceProvider(const string& uri){ return pluginManager->CreateProvider(uri.substr(0, uri.find_first_of(':',0))); } -void cMediaManager::SetDatabaseFile(const string& file){ +void cMediaManager::SetDatabaseDir(const string& file){ if(file.empty()) - databaseFile = string(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N)) + "/metadata.db"; + databaseFile = cPlugin::ConfigDirectory(PLUGIN_NAME_I18N); else databaseFile = file; + + databaseFile += "/metadata.db"; } void cMediaManager::SetPluginDirectory(const string& directory){ diff --git a/server/server.cpp b/server/server.cpp index c8c5619..4577fa1 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -209,8 +209,8 @@ bool cMediaServer::Initialize(){ if(mCurrentConfiguration.webServerPort) mWebserver->SetListenerPort(mCurrentConfiguration.webServerPort); - if(!mCurrentConfiguration.databaseFile.empty()) - mMediaManager->SetDatabaseFile(mCurrentConfiguration.databaseFile); + if(!mCurrentConfiguration.databaseDir.empty()) + mMediaManager->SetDatabaseDir(mCurrentConfiguration.databaseDir); } ret = UpnpSetMaxContentLength(GetMaxContentLength()); @@ -6,7 +6,8 @@ * $Id$ */ -#include <iostream> +#include <sstream> +#include <getopt.h> #include "upnp.h" #include "include/setup.h" @@ -26,12 +27,41 @@ cPluginUpnp::~cPluginUpnp() const char *cPluginUpnp::CommandLineHelp(void) { // Return a string that describes all known command line options. - return NULL; + std::stringstream ss; + + ss << " The UPnP/DLNA server is designed to detect everything automatically.\n" + << " Therefore the user is not required to change most of the settings.\n" + << " \n" + << " -d <DB directory> --db-dir=<DB directory> Specifies the directory\n" + << " where the the database\n" + << " file shall be located.\n"; + + return ss.str().c_str(); } bool cPluginUpnp::ProcessArgs(int argc, char *argv[]) { - // Implement command line argument processing here if applicable. + static struct option long_options[] = { + {"db-dir", required_argument, NULL, 'd'}, + {0, 0, 0, 0} + }; + + // Parse your own setup parameters and store their values. + upnp::cConfig config = mMediaServer->GetConfiguration(); + + int c = 0; int index = -1; + while((c = getopt_long(argc, argv, "d:",long_options, &index)) != -1){ + switch(c){ + case 'd': + if(!cMenuSetupUPnP::SetupParse("databaseDir", optarg, config)) return false; + break; + default: + return false; + } + } + + mMediaServer->SetConfiguration(config); + return true; } |