diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index a5e44b380..346fbd37d 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -142,7 +142,8 @@ PUBLIC_HEADERS = retroshare/rsblogs.h \ retroshare/rstypes.h HEADERS += plugins/pluginmanager.h \ - plugins/dlfcn_win32.h + plugins/dlfcn_win32.h \ + serialiser/rspluginitems.h HEADERS += $$PUBLIC_HEADERS @@ -487,7 +488,8 @@ SOURCES += rsserver/p3discovery.cc \ rsserver/rstypes.cc SOURCES += plugins/pluginmanager.cc \ - plugins/dlfcn_win32.cc + plugins/dlfcn_win32.cc \ + serialiser/rspluginitems.cc SOURCES += serialiser/rsbaseitems.cc \ serialiser/rsbaseserial.cc \ diff --git a/libretroshare/src/plugins/pluginmanager.cc b/libretroshare/src/plugins/pluginmanager.cc index 932329337..013fd2492 100644 --- a/libretroshare/src/plugins/pluginmanager.cc +++ b/libretroshare/src/plugins/pluginmanager.cc @@ -2,6 +2,11 @@ #include "pluginmanager.h" #include +#include +#include +#include +#include +#include #include #include #include @@ -28,6 +33,16 @@ p3ConnectMgr *RsPluginManager::_connectmgr = NULL ; typedef RsPlugin *(*RetroSharePluginEntry)(void) ; RsPluginHandler *rsPlugins ; +RsPluginManager::RsPluginManager() : p3Config(CONFIG_TYPE_PLUGINS) +{ +} + +void RsPluginManager::loadConfiguration() +{ + std::string dummyHash = "dummyHash"; + p3Config::loadConfiguration(dummyHash); +} + void RsPluginManager::setCacheDirectories(const std::string& local_cache, const std::string& remote_cache) { _local_cache_dir = local_cache ; @@ -45,6 +60,30 @@ bool RsPluginManager::acceptablePluginName(const std::string& name) #endif } +void RsPluginManager::disablePlugin(const std::string& hash) +{ + std::set::iterator it = _accepted_hashes.find(hash) ; + + if(it != _accepted_hashes.end()) + { + std::cerr << "RsPluginManager::disablePlugin(): removing hash " << hash << " from white list" << std::endl; + + _accepted_hashes.erase(it) ; + IndicateConfigChanged() ; + } +} + +void RsPluginManager::enablePlugin(const std::string& hash) +{ + if(_accepted_hashes.find(hash) == _accepted_hashes.end()) + { + std::cerr << "RsPluginManager::enablePlugin(): inserting hash " << hash << " in white list" << std::endl; + + _accepted_hashes.insert(hash) ; + IndicateConfigChanged() ; + } +} + void RsPluginManager::loadPlugins(const std::vector& plugin_directories) { _plugin_directories = plugin_directories ; @@ -81,53 +120,99 @@ void RsPluginManager::loadPlugins(const std::vector& plugin_directo std::cerr << "Loaded a total of " << _plugins.size() << " plugins." << std::endl; } +void RsPluginManager::getPluginStatus(int i,uint32_t& status,std::string& file_name,std::string& hash,std::string& error_string) const +{ + if((uint32_t)i >= _plugins.size()) + return ; + + status = _plugins[i].status ; + error_string = _plugins[i].info_string ; + hash = _plugins[i].file_hash ; + file_name = _plugins[i].file_name ; +} + +RsSerialiser *RsPluginManager::setupSerialiser() +{ + RsSerialiser *rss = new RsSerialiser ; + rss->addSerialType(new RsPluginSerialiser()) ; + + return rss ; +} + bool RsPluginManager::loadPlugin(const std::string& plugin_name) { std::cerr << " Loading plugin " << plugin_name << std::endl; - // The following choice is somewhat dangerous since the program can stop when a symbol can - // not be resolved. However, this is the only way to bind a single .so for both the - // interface and command line executables. + PluginInfo pf ; + pf.plugin = NULL ; + pf.file_name = plugin_name ; + std::cerr << " -> hashing." << std::endl; + uint64_t size ; - int link_mode = RTLD_NOW | RTLD_GLOBAL ; // RTLD_NOW - //int link_mode = RTLD_GLOBAL ; + if(!RsDirUtil::getFileHash(plugin_name,pf.file_hash,size)) + { + std::cerr << " -> cannot hash file. Plugin read canceled." << std::endl; + return false; + } - // Warning: this temporary vector is necessary, because linking with a .so that would include BundleManager.h - // is going to call the initialization of the static members of bundleManager a second time, and therefore - // will erase whatever is already initialized. So I first open all libraries, then fill the vectors. + // This file can be loaded. Insert an entry into the list of detected plugins. // - void *handle = dlopen(plugin_name.c_str(),link_mode) ; + _plugins.push_back(pf) ; + PluginInfo& pinfo(_plugins.back()) ; - if(handle == NULL) + std::cerr << " -> hash = " << pinfo.file_hash << std::endl; + + if(_accepted_hashes.find(pinfo.file_hash) == _accepted_hashes.end()) { - std::cerr << " Cannot open plugin: " << dlerror() << std::endl ; + std::cerr << " -> hash is not in white list. Plugin is rejected. Go to config->plugins to authorise this plugin." << std::endl; + pinfo.status = PLUGIN_STATUS_UNKNOWN_HASH ; + pinfo.info_string = "" ; return false ; } - - void *pf = dlsym(handle,_plugin_entry_symbol.c_str()) ; - - if(pf == NULL) { - std::cerr << dlerror() << std::endl ; - return false ; - } - std::cerr << " Added function entry for symbol " << _plugin_entry_symbol << std::endl ; - - RsPlugin *p = ( (*(RetroSharePluginEntry)pf)() ) ; - - if(p == NULL) + else { - std::cerr << " Plugin entry function " << _plugin_entry_symbol << " returns NULL ! It should return an object of type RsPlugin* " << std::endl; - return false ; - } - _plugins.push_back(p) ; - - if(link_mode & RTLD_LAZY) - { - std::cerr << " Symbols have been linked in LAZY mode. This means that undefined symbols may" << std::endl ; - std::cerr << " crash your program any time." << std::endl ; - } + // The following choice is conservative by forcing RS to resolve all dependencies at + // the time of loading the plugin. - return true ; + int link_mode = RTLD_NOW | RTLD_GLOBAL ; + + void *handle = dlopen(plugin_name.c_str(),link_mode) ; + + if(handle == NULL) + { + std::cerr << " Cannot open plugin: " << dlerror() << std::endl ; + pinfo.status = PLUGIN_STATUS_DLOPEN_ERROR ; + pinfo.info_string = dlerror() ; + return false ; + } + + void *pf = dlsym(handle,_plugin_entry_symbol.c_str()) ; + + if(pf == NULL) + { + std::cerr << dlerror() << std::endl ; + pinfo.status = PLUGIN_STATUS_MISSING_SYMBOL ; + pinfo.info_string = "Symbol " + _plugin_entry_symbol + " is missing." ; + return false ; + } + std::cerr << " Added function entry for symbol " << _plugin_entry_symbol << std::endl ; + + RsPlugin *p = ( (*(RetroSharePluginEntry)pf)() ) ; + + if(p == NULL) + { + std::cerr << " Plugin entry function " << _plugin_entry_symbol << " returns NULL ! It should return an object of type RsPlugin* " << std::endl; + pinfo.status = PLUGIN_STATUS_NULL_PLUGIN ; + pinfo.info_string = "Plugin entry " + _plugin_entry_symbol + "() return NULL" ; + return false ; + } + + pinfo.status = PLUGIN_STATUS_LOADED ; + pinfo.plugin = p ; + pinfo.info_string = "" ; + + return true; + } } p3ConnectMgr *RsPluginManager::getConnectMgr() const @@ -153,10 +238,10 @@ const std::string& RsPluginManager::getRemoteCacheDir() const void RsPluginManager::slowTickPlugins(time_t seconds) { for(uint32_t i=0;i<_plugins.size();++i) - if(_plugins[i]->rs_cache_service() != NULL && (seconds % _plugins[i]->rs_cache_service()->tickDelay() )) + if(_plugins[i].plugin != NULL && _plugins[i].plugin->rs_cache_service() != NULL && (seconds % _plugins[i].plugin->rs_cache_service()->tickDelay() )) { - std::cerr << " ticking plugin " << _plugins[i]->getPluginName() << std::endl; - _plugins[i]->rs_cache_service()->tick() ; + std::cerr << " ticking plugin " << _plugins[i].plugin->getPluginName() << std::endl; + _plugins[i].plugin->rs_cache_service()->tick() ; } } @@ -165,10 +250,10 @@ void RsPluginManager::registerCacheServices() std::cerr << " Registering cache services." << std::endl; for(uint32_t i=0;i<_plugins.size();++i) - if(_plugins[i]->rs_cache_service() != NULL) + if(_plugins[i].plugin != NULL && _plugins[i].plugin->rs_cache_service() != NULL) { - rsFiles->getCacheStrapper()->addCachePair(CachePair(_plugins[i]->rs_cache_service(),_plugins[i]->rs_cache_service(),CacheId(_plugins[i]->rs_service_id(), 0))) ; - std::cerr << " adding new cache pair for plugin " << _plugins[i]->getPluginName() << ", with RS_ID " << _plugins[i]->rs_service_id() << std::endl ; + rsFiles->getCacheStrapper()->addCachePair(CachePair(_plugins[i].plugin->rs_cache_service(),_plugins[i].plugin->rs_cache_service(),CacheId(_plugins[i].plugin->rs_service_id(), 0))) ; + std::cerr << " adding new cache pair for plugin " << _plugins[i].plugin->getPluginName() << ", with RS_ID " << _plugins[i].plugin->rs_service_id() << std::endl ; } } @@ -177,10 +262,10 @@ void RsPluginManager::registerClientServices(p3ServiceServer *pqih) std::cerr << " Registering pqi services." << std::endl; for(uint32_t i=0;i<_plugins.size();++i) - if(_plugins[i]->rs_pqi_service() != NULL) + if(_plugins[i].plugin != NULL && _plugins[i].plugin->rs_pqi_service() != NULL) { - pqih->addService(_plugins[i]->rs_pqi_service()) ; - std::cerr << " Added pqi service for plugin " << _plugins[i]->getPluginName() << std::endl; + pqih->addService(_plugins[i].plugin->rs_pqi_service()) ; + std::cerr << " Added pqi service for plugin " << _plugins[i].plugin->getPluginName() << std::endl; } } @@ -189,13 +274,50 @@ void RsPluginManager::addConfigurations(p3ConfigMgr *ConfigMgr) std::cerr << " Registering configuration files." << std::endl; for(uint32_t i=0;i<_plugins.size();++i) - if(_plugins[i]->configurationFileName().length() > 0) + if(_plugins[i].plugin != NULL && _plugins[i].plugin->configurationFileName().length() > 0) { - ConfigMgr->addConfiguration(_plugins[i]->configurationFileName(), _plugins[i]->rs_cache_service()); - std::cerr << " Added configuration for plugin " << _plugins[i]->getPluginName() << ", with file " << _plugins[i]->configurationFileName() << std::endl; + ConfigMgr->addConfiguration(_plugins[i].plugin->configurationFileName(), _plugins[i].plugin->rs_cache_service()); + std::cerr << " Added configuration for plugin " << _plugins[i].plugin->getPluginName() << ", with file " << _plugins[i].plugin->configurationFileName() << std::endl; } } +bool RsPluginManager::loadList(std::list& list) +{ + _accepted_hashes.clear() ; + + std::cerr << "RsPluginManager::loadList(): " << std::endl; + + std::list::iterator it; + for(it = list.begin(); it != list.end(); it++) + { + RsPluginHashSetItem *vitem = dynamic_cast(*it); + + if(vitem) + for(std::list::const_iterator it(vitem->hashes.ids.begin());it!=vitem->hashes.ids.end();++it) + { + _accepted_hashes.insert(*it) ; + std::cerr << " loaded hash " << *it << std::endl; + } + + delete (*it); + } + return true; +} + +bool RsPluginManager::saveList(bool& cleanup, std::list& list) +{ + cleanup = true ; + + RsPluginHashSetItem *vitem = new RsPluginHashSetItem() ; + + for(std::set::const_iterator it(_accepted_hashes.begin());it!=_accepted_hashes.end();++it) + vitem->hashes.ids.push_back(*it) ; + + list.push_back(vitem) ; + + return true; +} + RsCacheService::RsCacheService(uint16_t service_type,uint32_t config_type,uint32_t tick_delay) : CacheSource(service_type, true, rsPlugins->getFileServer()->getCacheStrapper(), rsPlugins->getLocalCacheDir()), CacheStore (service_type, true, rsPlugins->getFileServer()->getCacheStrapper(), rsPlugins->getFileServer()->getCacheTransfer(), rsPlugins->getRemoteCacheDir()), diff --git a/libretroshare/src/plugins/pluginmanager.h b/libretroshare/src/plugins/pluginmanager.h index fdb2096b9..110067cd0 100644 --- a/libretroshare/src/plugins/pluginmanager.h +++ b/libretroshare/src/plugins/pluginmanager.h @@ -1,31 +1,56 @@ #pragma once #include +#include #include #include +#include class p3ConfigMgr ; class p3ServiceServer ; class p3ConnectMgr ; -class RsPluginManager: public RsPluginHandler +struct PluginInfo +{ + RsPlugin *plugin ; + std::string info_string ; + std::string file_hash ; + std::string file_name ; + uint32_t status ; +}; + +class RsPluginManager: public RsPluginHandler, public p3Config { public: - RsPluginManager() {} + RsPluginManager() ; virtual ~RsPluginManager() {} + // ------------ Derived from RsPluginHandler ----------------// + // virtual int nbPlugins() const { return _plugins.size() ; } - virtual RsPlugin *plugin(int i) { return _plugins[i] ; } + virtual RsPlugin *plugin(int i) { return _plugins[i].plugin ; } virtual const std::vector& getPluginDirectories() const { return _plugin_directories ; } - + virtual void getPluginStatus(int i, uint32_t& status,std::string& file_name, std::string& hash,std::string& error_string) const ; + virtual void enablePlugin(const std::string& hash) ; + virtual void disablePlugin(const std::string& hash) ; virtual void slowTickPlugins(time_t sec) ; - virtual void addConfigurations(p3ConfigMgr *cfgMgr) ; virtual const std::string& getLocalCacheDir() const ; virtual const std::string& getRemoteCacheDir() const ; virtual ftServer *getFileServer() const ; virtual p3ConnectMgr *getConnectMgr() const ; + // ---------------- Derived from p3Config -------------------// + // + bool saveList(bool& cleanup, std::list& list) ; + bool loadList(std::list& list) ; + virtual RsSerialiser* setupSerialiser() ; + + // -------------------- Own members -------------------------// + // + virtual void addConfigurations(p3ConfigMgr *cfgMgr) ; + virtual void loadConfiguration() ; + static void setPluginEntrySymbol(const std::string& s) { _plugin_entry_symbol = s ; } static bool acceptablePluginName(const std::string& s) ; static void setCacheDirectories(const std::string& local,const std::string& remote) ; @@ -38,8 +63,10 @@ class RsPluginManager: public RsPluginHandler void registerClientServices(p3ServiceServer *pqih) ; private: bool loadPlugin(const std::string& shared_library_name) ; + std::string hashPlugin(const std::string& shared_library_name) ; - std::vector _plugins ; + std::vector _plugins ; + std::set _accepted_hashes ; static std::string _plugin_entry_symbol ; static std::string _remote_cache_dir ; diff --git a/libretroshare/src/pqi/p3cfgmgr.h b/libretroshare/src/pqi/p3cfgmgr.h index 5ddcf7f9b..b96e5053d 100644 --- a/libretroshare/src/pqi/p3cfgmgr.h +++ b/libretroshare/src/pqi/p3cfgmgr.h @@ -64,11 +64,7 @@ const uint32_t CONFIG_TYPE_PEERS = 0x0002; const uint32_t CONFIG_TYPE_FSERVER = 0x0003; const uint32_t CONFIG_TYPE_MSGS = 0x0004; const uint32_t CONFIG_TYPE_CACHE_OLDID = 0x0005; -const uint32_t CONFIG_TYPE_AUTHGPG = 0x006; - -const uint32_t CONFIG_TYPE_P3DISC = 0x00B; -const uint32_t CONFIG_TYPE_AUTHSSL = 0x00C; - +const uint32_t CONFIG_TYPE_AUTHGPG = 0x0006; /* new FileTransfer */ const uint32_t CONFIG_TYPE_FT_SHARED = 0x0007; @@ -76,19 +72,23 @@ const uint32_t CONFIG_TYPE_FT_EXTRA_LIST= 0x0008; const uint32_t CONFIG_TYPE_FT_CONTROL = 0x0009; const uint32_t CONFIG_TYPE_FT_DWLQUEUE = 0x000A; -/// turtle router -const uint32_t CONFIG_TYPE_TURTLE = 0x0020; +const uint32_t CONFIG_TYPE_P3DISC = 0x000B; +const uint32_t CONFIG_TYPE_AUTHSSL = 0x000C; /* wish these ids where higher... * may move when switch to v0.5 */ const uint32_t CONFIG_TYPE_CHAT = 0x0012; const uint32_t CONFIG_TYPE_STATUS = 0x0013; +const uint32_t CONFIG_TYPE_PLUGINS = 0x0014; + +/// turtle router +const uint32_t CONFIG_TYPE_TURTLE = 0x0020; /* standard services */ -const uint32_t CONFIG_TYPE_QBLOG = 0x0101; -const uint32_t CONFIG_TYPE_FORUMS = 0x0102; -const uint32_t CONFIG_TYPE_CHANNELS = 0x0103; +const uint32_t CONFIG_TYPE_QBLOG = 0x0101; +const uint32_t CONFIG_TYPE_FORUMS = 0x0102; +const uint32_t CONFIG_TYPE_CHANNELS = 0x0103; /* CACHE ID Must be at the END so that other configurations * are loaded First (Cache Config --> Cache Loading) diff --git a/libretroshare/src/retroshare/rsplugin.h b/libretroshare/src/retroshare/rsplugin.h index e35ef5329..02bec8dec 100644 --- a/libretroshare/src/retroshare/rsplugin.h +++ b/libretroshare/src/retroshare/rsplugin.h @@ -37,22 +37,36 @@ class p3Service ; class p3ConnectMgr ; class MainPage ; class QIcon ; +class QString ; +class QWidget ; class RsCacheService ; class ftServer ; class pqiService ; +// Used for the status of plugins. +// +#define PLUGIN_STATUS_NO_STATUS 0x0000 +#define PLUGIN_STATUS_UNKNOWN_HASH 0x0001 +#define PLUGIN_STATUS_DLOPEN_ERROR 0x0002 +#define PLUGIN_STATUS_MISSING_SYMBOL 0x0003 +#define PLUGIN_STATUS_NULL_PLUGIN 0x0004 +#define PLUGIN_STATUS_LOADED 0x0005 + class RsPlugin { public: virtual RsCacheService *rs_cache_service() const { return NULL ; } virtual pqiService *rs_pqi_service() const { return NULL ; } virtual uint16_t rs_service_id() const { return 0 ; } + virtual MainPage *qt_page() const { return NULL ; } + virtual QWidget *qt_config_panel() const { return NULL ; } virtual QIcon *qt_icon() const { return NULL ; } virtual std::string configurationFileName() const { return std::string() ; } virtual std::string getShortPluginDescription() const = 0 ; virtual std::string getPluginName() const = 0 ; + virtual void getPluginVersion(int& major,int& minor,int& svn_rev) const = 0 ; }; class RsPluginHandler @@ -63,6 +77,9 @@ class RsPluginHandler virtual int nbPlugins() const = 0 ; virtual RsPlugin *plugin(int i) = 0 ; virtual const std::vector& getPluginDirectories() const = 0; + virtual void getPluginStatus(int i,uint32_t& status,std::string& file_name,std::string& file_hash,std::string& error_string) const = 0 ; + virtual void enablePlugin(const std::string& hash) = 0; + virtual void disablePlugin(const std::string& hash) = 0; virtual void slowTickPlugins(time_t sec) = 0 ; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 9bbded580..499b5b74f 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1990,6 +1990,9 @@ int RsServer::StartupRetroShare() RsPluginManager *mPluginsManager = new RsPluginManager ; rsPlugins = mPluginsManager ; + mConfigMgr->addConfiguration("plugins.cfg", mPluginsManager); + + mPluginsManager->loadConfiguration() ; // These are needed to load plugins: plugin devs might want to know the place of // cache directories, get pointers to cache strapper, or access ownId() @@ -2095,18 +2098,17 @@ int RsServer::StartupRetroShare() //mConfigMgr->addConfiguration("ftserver.cfg", ftserver); // - mConfigMgr->addConfiguration("gpg_prefs.cfg", (AuthGPGimpl *) AuthGPG::getAuthGPG()); - mConfigMgr->loadConfiguration(); + mConfigMgr->addConfiguration("gpg_prefs.cfg", (AuthGPGimpl *) AuthGPG::getAuthGPG()); + mConfigMgr->loadConfiguration(); - //mConfigMgr->addConfiguration("sslcerts.cfg", AuthSSL::getAuthSSL()); - mConfigMgr->addConfiguration("peers.cfg", mConnMgr); + mConfigMgr->addConfiguration("peers.cfg", mConnMgr); mConfigMgr->addConfiguration("general.cfg", mGeneralConfig); mConfigMgr->addConfiguration("cache.cfg", mCacheStrapper); #ifndef MINIMAL_LIBRS mConfigMgr->addConfiguration("msgs.cfg", msgSrv); mConfigMgr->addConfiguration("chat.cfg", chatSrv); #ifdef RS_USE_BLOGS - mConfigMgr->addConfiguration("blogs.cfg", mBlogs); + mConfigMgr->addConfiguration("blogs.cfg", mBlogs); #endif mConfigMgr->addConfiguration("forums.cfg", mForums); mConfigMgr->addConfiguration("channels.cfg", mChannels); diff --git a/libretroshare/src/serialiser/rsconfigitems.h b/libretroshare/src/serialiser/rsconfigitems.h index f932602f1..525e5c5db 100644 --- a/libretroshare/src/serialiser/rsconfigitems.h +++ b/libretroshare/src/serialiser/rsconfigitems.h @@ -41,6 +41,7 @@ const uint8_t RS_PKT_TYPE_GENERAL_CONFIG = 0x01; const uint8_t RS_PKT_TYPE_PEER_CONFIG = 0x02; const uint8_t RS_PKT_TYPE_CACHE_CONFIG = 0x03; const uint8_t RS_PKT_TYPE_FILE_CONFIG = 0x04; +const uint8_t RS_PKT_TYPE_PLUGIN_CONFIG = 0x05; /* GENERAL CONFIG SUBTYPES */ const uint8_t RS_PKT_SUBTYPE_KEY_VALUE = 0x01; diff --git a/libretroshare/src/serialiser/rspluginitems.cc b/libretroshare/src/serialiser/rspluginitems.cc new file mode 100644 index 000000000..97f951028 --- /dev/null +++ b/libretroshare/src/serialiser/rspluginitems.cc @@ -0,0 +1,132 @@ +#include "rspluginitems.h" + +#ifndef WINDOWS_SYS +#include +#endif + +bool RsPluginHashSetItem::serialise(void *data,uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size(); + uint32_t offset = 0; + +#ifdef P3TURTLE_DEBUG + std::cerr << "RsPluginSerialiser::serialising HashSet packet (size=" << tlvsize << ")" << std::endl; +#endif + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize); + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + + ok &= hashes.SetTlv(data,tlvsize,&offset) ; + + if (offset != tlvsize) + { + ok = false; +#ifdef P3TURTLE_DEBUG + std::cerr << "RsPluginHashSetItem::serialise() Size Error! (offset=" << offset << ", tlvsize=" << tlvsize << ")" << std::endl; +#endif + } + + return ok ; +} + +RsPluginHashSetItem::RsPluginHashSetItem(void *data,uint32_t size) + : RsPluginItem(RS_PKT_CLASS_PLUGIN_SUBTYPE_HASHSET) +{ + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(data); + bool ok = true ; + + hashes.ids.clear() ; + + ok &= hashes.GetTlv(data,size,&offset) ; + + if (offset != rssize) + { +#ifdef TLV_DEBUG + std::cerr << "RsTlvPeerIdSet::GetTlv() Warning extra bytes at end of item"; + std::cerr << std::endl; +#endif + ok = false ; + } + +#ifdef WINDOWS_SYS // No Exceptions in Windows compile. (drbobs). + UNREFERENCED_LOCAL_VARIABLE(rssize); +#else + if (!ok) + throw std::runtime_error("Unknown error while deserializing.") ; +#endif + +} + +RsItem *RsPluginSerialiser::deserialise(void *data, uint32_t *size) +{ + // look what we have... + + /* get the type */ + uint32_t rstype = getRsItemId(data); +#ifdef P3TURTLE_DEBUG + std::cerr << "p3turtle: deserialising packet: " << std::endl ; +#endif + if ( (RS_PKT_VERSION1 != getRsItemVersion(rstype)) + || (RS_PKT_CLASS_CONFIG != getRsItemClass(rstype)) + || (RS_PKT_TYPE_PLUGIN_CONFIG != getRsItemType(rstype))) + { +#ifdef P3TURTLE_DEBUG + std::cerr << " Wrong type !!" << std::endl ; +#endif + return NULL; /* wrong type */ + } + +#ifndef WINDOWS_SYS + try + { +#endif + switch(getRsItemSubType(rstype)) + { + case RS_PKT_CLASS_PLUGIN_SUBTYPE_HASHSET : return new RsPluginHashSetItem(data,*size) ; + + default: + std::cerr << "Unknown packet type in RsPluginSerialiser. Type = " << rstype << std::endl; + return NULL ; + } +#ifndef WINDOWS_SYS + } + catch(std::exception& e) + { + std::cerr << "Exception raised: " << e.what() << std::endl ; + return NULL ; + } +#endif +} + +uint32_t RsPluginHashSetItem::serial_size() +{ + uint32_t size = 8 ; + + size += hashes.TlvSize() ; + + return size ; +} + +std::ostream& RsPluginHashSetItem::print(std::ostream& o, uint16_t) +{ + o << "Item type: RsPluginHashSetItem" << std::endl; + o << " Hash list: " << std::endl; + + for(std::list::const_iterator it(hashes.ids.begin());it!=hashes.ids.end();++it) + o << " " << *it << std::endl; + + return o ; +} + + diff --git a/libretroshare/src/serialiser/rspluginitems.h b/libretroshare/src/serialiser/rspluginitems.h new file mode 100644 index 000000000..2d77156ec --- /dev/null +++ b/libretroshare/src/serialiser/rspluginitems.h @@ -0,0 +1,80 @@ +/* + * libretroshare/src/services: p3turtle.h + * + * Services for RetroShare. + * + * Copyright 2009 by Cyril Soler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "csoler@users.sourceforge.net". + * + */ + + +#pragma once + +#include "serialiser/rsserial.h" +#include "serialiser/rstlvbase.h" +#include "serialiser/rstlvtypes.h" +#include "serialiser/rsconfigitems.h" +#include "serialiser/rsbaseserial.h" + +const uint8_t RS_PKT_CLASS_PLUGIN_SUBTYPE_HASHSET = 0x01 ; + +class RsPluginItem: public RsItem +{ + public: + RsPluginItem(uint8_t plugin_item_subtype): RsItem(RS_PKT_VERSION1,RS_PKT_CLASS_CONFIG,RS_PKT_TYPE_PLUGIN_CONFIG,plugin_item_subtype) {} + virtual ~RsPluginItem() {} + + virtual bool serialise(void *data,uint32_t& size) = 0 ; // Isn't it better that items can serialise themselves ? + virtual uint32_t serial_size() = 0 ; // deserialise is handled using a constructor + + virtual void clear() {} +}; + +class RsPluginSerialiser: public RsSerialType +{ + public: + RsPluginSerialiser() : RsSerialType(RS_PKT_VERSION1, RS_PKT_CLASS_CONFIG, RS_PKT_TYPE_PLUGIN_CONFIG) {} + + virtual uint32_t size (RsItem *item) + { + return dynamic_cast(item)->serial_size() ; + } + virtual bool serialise(RsItem *item, void *data, uint32_t *size) + { + return dynamic_cast(item)->serialise(data,*size) ; + } + virtual RsItem *deserialise (void *data, uint32_t *size) ; +}; + +class RsPluginHashSetItem: public RsPluginItem +{ + public: + RsPluginHashSetItem() : RsPluginItem(RS_PKT_CLASS_PLUGIN_SUBTYPE_HASHSET) {} + RsPluginHashSetItem(void *data,uint32_t size) ; + + RsTlvHashSet hashes ; + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + protected: + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + + diff --git a/plugins/LinksCloud/LinksCloudPlugin.cpp b/plugins/LinksCloud/LinksCloudPlugin.cpp index d1787ae4a..bb6ae0531 100644 --- a/plugins/LinksCloud/LinksCloudPlugin.cpp +++ b/plugins/LinksCloud/LinksCloudPlugin.cpp @@ -16,6 +16,13 @@ extern "C" { #define IMAGE_LINKS ":/images/irkick.png" +void LinksCloudPlugin::getPluginVersion(int& major,int& minor,int& svn_rev) const +{ + major = 5 ; + minor = 1 ; + svn_rev = 4350 ; +} + LinksCloudPlugin::LinksCloudPlugin() { mRanking = NULL ; diff --git a/plugins/LinksCloud/LinksCloudPlugin.h b/plugins/LinksCloud/LinksCloudPlugin.h index 35af536cb..d6dc0e49e 100644 --- a/plugins/LinksCloud/LinksCloudPlugin.h +++ b/plugins/LinksCloud/LinksCloudPlugin.h @@ -15,6 +15,8 @@ class LinksCloudPlugin: public RsPlugin virtual QIcon *qt_icon() const ; virtual uint16_t rs_service_id() const { return RS_SERVICE_TYPE_RANK ; } + virtual void getPluginVersion(int& major,int& minor,int& svn_rev) const ; + virtual std::string configurationFileName() const { return std::string() ; } virtual std::string getShortPluginDescription() const ; diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 833d34678..094d8c968 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -291,6 +291,7 @@ HEADERS += rshare.h \ gui/settings/NewTag.h \ gui/settings/ForumPage.h \ gui/settings/PluginsPage.h \ + gui/settings/PluginItem.h \ gui/settings/AppearancePage.h \ gui/settings/FileAssociationsPage.h \ gui/settings/SoundPage.h \ @@ -407,6 +408,7 @@ FORMS += gui/StartDialog.ui \ gui/settings/TransferPage.ui \ gui/settings/SoundPage.ui \ gui/settings/ChatPage.ui \ + gui/settings/PluginItem.ui \ gui/toaster/MessageToaster.ui \ gui/toaster/OnlineToaster.ui \ gui/toaster/DownloadToaster.ui \ @@ -546,6 +548,7 @@ SOURCES += main.cpp \ gui/settings/NewTag.cpp \ gui/settings/ForumPage.cpp \ gui/settings/PluginsPage.cpp \ + gui/settings/PluginItem.cpp \ gui/settings/AppearancePage.cpp \ gui/settings/FileAssociationsPage.cpp \ gui/settings/SoundPage.cpp \ diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index e873d0226..a9f380cbf 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -250,12 +250,23 @@ MainWindow::MainWindow(QWidget* parent, Qt::WFlags flags) std::cerr << "Looking for interfaces in existing plugins:" << std::endl; for(uint32_t i = 0;inbPlugins();++i) { - if(rsPlugins->plugin(i)->qt_page() != NULL && rsPlugins->plugin(i)->qt_icon() != NULL) + QIcon icon ; + + if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_page() != NULL) { + if(rsPlugins->plugin(i)->qt_icon() != NULL) + icon = *rsPlugins->plugin(i)->qt_icon() ; + else + icon = QIcon(":images/extension_48.png") ; + std::cerr << " Addign widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl; - ui.stackPages->add(rsPlugins->plugin(i)->qt_page(), createPageAction(*rsPlugins->plugin(i)->qt_icon(), QString::fromStdString(rsPlugins->plugin(i)->getPluginName()), grp)); + ui.stackPages->add(rsPlugins->plugin(i)->qt_page(), createPageAction(icon, QString::fromStdString(rsPlugins->plugin(i)->getPluginName()), grp)); } - //ui.stackPages->add(linksDialog = new LinksDialog(ui.stackPages), createPageAction(QIcon(IMAGE_LINKS), tr("Links Cloud"), grp)); + else if(rsPlugins->plugin(i) == NULL) + std::cerr << " No plugin object !" << std::endl; + else + std::cerr << " No plugin page !" << std::endl; + } #ifndef RS_RELEASE_VERSION diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index b093229a4..e2a0457e8 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -136,6 +136,7 @@ images/encrypted22.png images/encrypted32.png images/encrypted48.png + images/disabled_plugin_48.png images/evolution.png images/exit_24x24.png images/expand_frame.png diff --git a/retroshare-gui/src/gui/images/disabled_plugin_48.png b/retroshare-gui/src/gui/images/disabled_plugin_48.png new file mode 100644 index 000000000..df16d3e67 Binary files /dev/null and b/retroshare-gui/src/gui/images/disabled_plugin_48.png differ diff --git a/retroshare-gui/src/gui/settings/PluginItem.cpp b/retroshare-gui/src/gui/settings/PluginItem.cpp new file mode 100644 index 000000000..cb5a9a30e --- /dev/null +++ b/retroshare-gui/src/gui/settings/PluginItem.cpp @@ -0,0 +1,52 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011 Cyril Soler + * + * This program is 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include "PluginItem.h" + +PluginItem::PluginItem(int id, const QString& pluginTitle,const QString& pluginDescription,const QString& status, const QString& file_name, const QString& file_hash, const QString& error_string, const QIcon& icon) + :QWidget(NULL) +{ + setupUi(this) ; + + _id = id ; + _statusLabel->setText(status) ; + _hashLabel->setText(file_hash) ; + _name_LE->setText(file_name) ; + _pluginIcon->setIcon(icon) ; + _pluginIcon->setText(QString()) ; + msgLabel->setText(pluginDescription) ; + subjectLabel->setText(pluginTitle) ; + + QObject::connect(_enabled_CB,SIGNAL(toggled(bool)),this,SLOT(togglePlugin(bool))) ; + QObject::connect(_configure_PB,SIGNAL(clicked()),this,SLOT(configurePlugin())) ; +} + +void PluginItem::togglePlugin(bool b) +{ + emit( pluginEnabled(b,_hashLabel->text()) ) ; +} + +void PluginItem::configurePlugin() +{ + emit( pluginConfigure(_id) ) ; +} + + diff --git a/retroshare-gui/src/gui/settings/PluginItem.h b/retroshare-gui/src/gui/settings/PluginItem.h new file mode 100644 index 000000000..7d14f8774 --- /dev/null +++ b/retroshare-gui/src/gui/settings/PluginItem.h @@ -0,0 +1,45 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011 Cyril Soler + * + * This program is 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#pragma once + +#include "ui_PluginItem.h" + +class PluginItem: public QWidget, public Ui::PluginItem +{ + Q_OBJECT + + public: + PluginItem(int id,const QString& pluginTitle,const QString& pluginDescription,const QString& status, const QString& file_name, const QString& file_hash, const QString& error_string, const QIcon& icon) ; + + protected slots: + void togglePlugin(bool) ; + void configurePlugin() ; + + signals: + void pluginEnabled(bool,const QString&) ; + void pluginConfigure(int) ; + + private: + int _id ; +}; + + diff --git a/retroshare-gui/src/gui/settings/PluginItem.ui b/retroshare-gui/src/gui/settings/PluginItem.ui new file mode 100644 index 000000000..85cc80720 --- /dev/null +++ b/retroshare-gui/src/gui/settings/PluginItem.ui @@ -0,0 +1,251 @@ + + + PluginItem + + + + 0 + 0 + 519 + 186 + + + + Form + + + + + + true + + + + 0 + 0 + + + + QFrame#frame{border: 2px solid green; +background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, +stop: 0 #62E0B1, stop: 1 #8EFFD3); +border-radius: 0px} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 48 + 48 + + + + + 48 + 48 + + + + + 48 + 48 + + + + PushButton + + + + + + + + 0 + 0 + + + + subjectLabel + + + true + + + + + + + + + + + + + + + Status: + + + + + + + File hash: + + + + + + + File name: + + + + + + + + + + + + 0 + 0 + + + + TextLabel + + + + + + + + 0 + 0 + + + + TextLabel + + + + + + + + 0 + 0 + + + + TextLabel + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Long + message here + + + true + + + true + + + + + + + + + + + + Launch configuration panel, if provided by the plugin + + + Configure + + + + + + + Add the plugin into the white list of accepted plugins. This will be effective after you restart RetroShare, since plugins need to be loaded at startup. + + + Enabled + + + + + + + + + + + + + + + + + diff --git a/retroshare-gui/src/gui/settings/PluginsPage.cpp b/retroshare-gui/src/gui/settings/PluginsPage.cpp index 57ba2b40c..e26fac6bf 100644 --- a/retroshare-gui/src/gui/settings/PluginsPage.cpp +++ b/retroshare-gui/src/gui/settings/PluginsPage.cpp @@ -19,7 +19,10 @@ * Boston, MA 02110-1301, USA. ****************************************************************/ +#include + #include "PluginsPage.h" +#include "PluginItem.h" #include "rshare.h" #include "rsharesettings.h" @@ -35,17 +38,67 @@ PluginsPage::PluginsPage(QWidget * parent, Qt::WFlags flags) QString text ; + std::cerr << "PluginsPage: adding plugins" << std::endl; + if(rsPlugins->nbPlugins() > 0) for(int i=0;inbPlugins();++i) { - text += ""+tr("Plugin")+": \t" + QString::fromStdString(rsPlugins->plugin(i)->getPluginName()) + "
" ; - text += ""+tr("Description")+": \t" + QString::fromStdString(rsPlugins->plugin(i)->getShortPluginDescription()) + "
" ; - text += "
" ; - } - else - text = tr("

No plugins loaded.

") ; + std::cerr << " Adding new page." << std::endl; - ui._loadedPlugins_TB->setHtml(text) ; + std::string file_name, file_hash, error_string ; + uint32_t status ; + + rsPlugins->getPluginStatus(i,status,file_name,file_hash,error_string) ; + + QString status_string ; + + switch(status) + { + case PLUGIN_STATUS_UNKNOWN_HASH: status_string = tr("Hash rejected. Add to white list.") ; + break ; + case PLUGIN_STATUS_DLOPEN_ERROR: status_string = tr("Loading error.") ; + break ; + case PLUGIN_STATUS_MISSING_SYMBOL: status_string = tr("Missing symbol. Wrong version?") ; + break ; + case PLUGIN_STATUS_NULL_PLUGIN: status_string = tr("No plugin object") ; + break ; + case PLUGIN_STATUS_LOADED: status_string = tr("Plugins is loaded.") ; + break ; + default: + status_string = tr("Unknown status.") ; + } + + QIcon plugin_icon(":images/disabled_plugin_48.png") ; + RsPlugin *plugin = rsPlugins->plugin(i) ; + QString pluginTitle = tr("Title unavailable") ; + QString pluginDescription = tr("Description unavailable") ; + + if(plugin!=NULL) + { + if(plugin->qt_icon() != NULL) + plugin_icon = *plugin->qt_icon() ; + + pluginTitle = QString::fromStdString(plugin->getPluginName()) ; + pluginDescription = QString::fromStdString(plugin->getShortPluginDescription()) ; + } + + PluginItem *item = new PluginItem(i,pluginTitle,pluginDescription,status_string, + QString::fromStdString(file_name), + QString::fromStdString(file_hash),QString::fromStdString(error_string), + plugin_icon) ; + + ui._pluginsLayout->insertWidget(0,item) ; + + if(plugin == NULL || plugin->qt_config_panel() == NULL) + item->_configure_PB->setEnabled(false) ; + + if(plugin != NULL) + item->_enabled_CB->setChecked(true) ; + + QObject::connect(item,SIGNAL(pluginEnabled(bool,const QString&)),this,SLOT(togglePlugin(bool,const QString&))) ; + QObject::connect(item,SIGNAL(pluginConfigure(int)),this,SLOT(configurePlugin(int))) ; + } + ui._pluginsLayout->update() ; const std::vector& dirs(rsPlugins->getPluginDirectories()) ; text = "" ; @@ -55,6 +108,22 @@ PluginsPage::PluginsPage(QWidget * parent, Qt::WFlags flags) ui._lookupDirectories_TB->setHtml(text) ; } +void PluginsPage::configurePlugin(int i) +{ + std::cerr << "Launching configuration window for plugin " << i << std::endl; + + if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_config_panel() != NULL) + rsPlugins->plugin(i)->qt_config_panel()->show() ; +} +void PluginsPage::togglePlugin(bool b,const QString& hash) +{ + std::cerr << "Switching status of plugin " << hash.toStdString() << " to " << b << std::endl; + + if(b) + rsPlugins->enablePlugin(hash.toStdString()) ; + else + rsPlugins->disablePlugin(hash.toStdString()) ; +} PluginsPage::~PluginsPage() { diff --git a/retroshare-gui/src/gui/settings/PluginsPage.h b/retroshare-gui/src/gui/settings/PluginsPage.h index f0f32e649..faee8f0d7 100644 --- a/retroshare-gui/src/gui/settings/PluginsPage.h +++ b/retroshare-gui/src/gui/settings/PluginsPage.h @@ -26,18 +26,22 @@ class PluginsPage : public ConfigPage { - Q_OBJECT + Q_OBJECT -public: - PluginsPage(QWidget * parent = 0, Qt::WFlags flags = 0); - ~PluginsPage(); + public: + PluginsPage(QWidget * parent = 0, Qt::WFlags flags = 0); + ~PluginsPage(); - /** Saves the changes on this page */ - bool save(QString &errmsg); - /** Loads the settings for this page */ - void load(); + /** Saves the changes on this page */ + bool save(QString &errmsg); + /** Loads the settings for this page */ + void load(); -private: - Ui::PluginsPage ui; + public slots: + void togglePlugin(bool b,const QString&) ; + void configurePlugin(int i) ; + + private: + Ui::PluginsPage ui; }; diff --git a/retroshare-gui/src/gui/settings/PluginsPage.ui b/retroshare-gui/src/gui/settings/PluginsPage.ui index 909d8f19d..e9f70eb7d 100644 --- a/retroshare-gui/src/gui/settings/PluginsPage.ui +++ b/retroshare-gui/src/gui/settings/PluginsPage.ui @@ -500,19 +500,7 @@ Qt::NoContextMenu - - - - Loaded plugins - - - - - - - - - + Qt::Vertical @@ -525,14 +513,60 @@ + + + + Loaded plugins + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Authorize all plugins + + + + Plugin look-up directories - + + + + 0 + 0 + + + + + 16777215 + 50 + + +