From a2c91a79240f62a87900c30680c4f61f59c16e67 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 16 Jun 2011 21:59:26 +0000 Subject: [PATCH] - Added basic infrastructure to plugin system in libretroshare and retroshare-gui. - ported LinksCloud to a new plugin, and removed it from main sources Next moves: - add gui for managing plugins - handle windows compilation git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4275 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/ft/ftserver.h | 5 +- libretroshare/src/libretroshare.pro | 14 +- libretroshare/src/plugins/pluginclasses.h | 25 + libretroshare/src/plugins/pluginmanager.cc | 205 +++ libretroshare/src/plugins/pluginmanager.h | 48 + libretroshare/src/pqi/p3cfgmgr.h | 1 - libretroshare/src/retroshare/rsfiles.h | 5 +- libretroshare/src/rsserver/p3face-server.cc | 275 ++-- libretroshare/src/rsserver/p3face.h | 2 - libretroshare/src/rsserver/rsinit.cc | 89 +- libretroshare/src/serialiser/rsserviceids.h | 1 - plugins/LinksCloud/AddLinksDialog.cpp | 124 ++ plugins/LinksCloud/AddLinksDialog.h | 48 + plugins/LinksCloud/AddLinksDialog.ui | 288 ++++ plugins/LinksCloud/LinksCloud.pro | 11 + plugins/LinksCloud/LinksDialog.cpp | 1060 +++++++++++++++ plugins/LinksCloud/LinksDialog.h | 92 ++ plugins/LinksCloud/LinksDialog.ui | 587 ++++++++ plugins/LinksCloud/images.qrc | 5 + plugins/LinksCloud/images/irkick.png | Bin 0 -> 2231 bytes plugins/LinksCloud/p3ranking.cc | 1354 +++++++++++++++++++ plugins/LinksCloud/p3ranking.h | 165 +++ plugins/LinksCloud/rsrank.h | 96 ++ plugins/LinksCloud/rsrankitems.cc | 253 ++++ plugins/LinksCloud/rsrankitems.h | 110 ++ retroshare-gui/src/RetroShare.pro | 26 +- retroshare-gui/src/gui/MainWindow.cpp | 27 +- retroshare-gui/src/gui/images.qrc | 3 +- 28 files changed, 4676 insertions(+), 243 deletions(-) create mode 100644 libretroshare/src/plugins/pluginclasses.h create mode 100644 libretroshare/src/plugins/pluginmanager.cc create mode 100644 libretroshare/src/plugins/pluginmanager.h create mode 100644 plugins/LinksCloud/AddLinksDialog.cpp create mode 100644 plugins/LinksCloud/AddLinksDialog.h create mode 100644 plugins/LinksCloud/AddLinksDialog.ui create mode 100644 plugins/LinksCloud/LinksCloud.pro create mode 100644 plugins/LinksCloud/LinksDialog.cpp create mode 100644 plugins/LinksCloud/LinksDialog.h create mode 100644 plugins/LinksCloud/LinksDialog.ui create mode 100644 plugins/LinksCloud/images.qrc create mode 100644 plugins/LinksCloud/images/irkick.png create mode 100644 plugins/LinksCloud/p3ranking.cc create mode 100644 plugins/LinksCloud/p3ranking.h create mode 100644 plugins/LinksCloud/rsrank.h create mode 100644 plugins/LinksCloud/rsrankitems.cc create mode 100644 plugins/LinksCloud/rsrankitems.h diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 065f04315..12ee36caf 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -88,8 +88,9 @@ void setP3Interface(P3Interface *pqi); /* add Config Items (Extra, Controller) */ void addConfigComponents(p3ConfigMgr *mgr); -CacheStrapper *getCacheStrapper(); -CacheTransfer *getCacheTransfer(); +virtual CacheStrapper *getCacheStrapper(); +virtual CacheTransfer *getCacheTransfer(); + std::string OwnId(); /* Final Setup (once everything is assigned) */ diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 978f6f52c..335eb7915 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -128,6 +128,7 @@ PUBLIC_HEADERS = retroshare/rsblogs.h \ retroshare/rsforums.h \ retroshare/rsiface.h \ retroshare/rsinit.h \ + retroshare/rsplugin.h \ retroshare/rsloginhandler.h \ retroshare/rsmsgs.h \ retroshare/rsnotify.h \ @@ -137,6 +138,8 @@ PUBLIC_HEADERS = retroshare/rsblogs.h \ retroshare/rsturtle.h \ retroshare/rstypes.h +HEADERS += plugins/pluginmanager.h + HEADERS += $$PUBLIC_HEADERS # public headers to be... @@ -359,7 +362,6 @@ HEADERS += rsserver/p3discovery.h \ rsserver/p3msgs.h \ rsserver/p3peers.h \ rsserver/p3photo.h \ - rsserver/p3rank.h \ rsserver/p3status.h HEADERS += serialiser/rsbaseitems.h \ @@ -373,7 +375,6 @@ HEADERS += serialiser/rsbaseitems.h \ serialiser/rsgameitems.h \ serialiser/rsmsgitems.h \ serialiser/rsphotoitems.h \ - serialiser/rsrankitems.h \ serialiser/rsserial.h \ serialiser/rsserviceids.h \ serialiser/rsserviceitems.h \ @@ -396,7 +397,6 @@ HEADERS += services/p3channels.h \ services/p3msgservice.h \ services/p3photoservice.h \ services/p3portservice.h \ - services/p3ranking.h \ services/p3service.h \ services/p3statusservice.h \ services/p3tunnel.h @@ -477,13 +477,14 @@ SOURCES += rsserver/p3discovery.cc \ rsserver/p3msgs.cc \ rsserver/p3peers.cc \ rsserver/p3photo.cc \ - rsserver/p3rank.cc \ rsserver/p3status.cc \ rsserver/rsiface.cc \ rsserver/rsinit.cc \ rsserver/rsloginhandler.cc \ rsserver/rstypes.cc +SOURCES += plugins/pluginmanager.cc + SOURCES += serialiser/rsbaseitems.cc \ serialiser/rsbaseserial.cc \ serialiser/rsblogitems.cc \ @@ -495,7 +496,6 @@ SOURCES += serialiser/rsbaseitems.cc \ serialiser/rsgameitems.cc \ serialiser/rsmsgitems.cc \ serialiser/rsphotoitems.cc \ - serialiser/rsrankitems.cc \ serialiser/rsserial.cc \ serialiser/rsstatusitems.cc \ serialiser/rstlvaddrs.cc \ @@ -517,7 +517,6 @@ SOURCES += services/p3channels.cc \ services/p3msgservice.cc \ services/p3photoservice.cc \ services/p3portservice.cc \ - services/p3ranking.cc \ services/p3service.cc \ services/p3statusservice.cc # removed because getPeer() doesn t exist services/p3tunnel.cc @@ -548,13 +547,11 @@ SOURCES += util/folderiterator.cc \ minimal { SOURCES -= rsserver/p3msgs.cc \ - rsserver/p3rank.cc \ rsserver/p3status.cc \ rsserver/p3photo.cc SOURCES -= serialiser/rsforumitems.cc \ serialiser/rsstatusitems.cc \ - serialiser/rsrankitems.cc \ serialiser/rschannelitems.cc \ serialiser/rsgameitems.cc \ serialiser/rsphotoitems.cc @@ -562,7 +559,6 @@ minimal { SOURCES -= services/p3forums.cc \ services/p3msgservice.cc \ services/p3statusservice.cc \ - services/p3ranking.cc \ services/p3channels.cc \ services/p3gamelauncher.cc \ services/p3photoservice.cc diff --git a/libretroshare/src/plugins/pluginclasses.h b/libretroshare/src/plugins/pluginclasses.h new file mode 100644 index 000000000..889d49abe --- /dev/null +++ b/libretroshare/src/plugins/pluginclasses.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +// The following class abstracts the construction of a cache service. The user only has to +// supply RS with a type ID. If the ID is already in use, RS will complain. +// +class RsCacheService: public CacheSource, public CacheStore, public p3Config +{ + public: + RsCacheService(uint16_t type,uint32_t config_type,uint32_t tick_delay_in_seconds) ; + + uint32_t tickDelay() const { return _tick_delay_in_seconds ; } + virtual void tick() {} + + // Functions from p3config + // + virtual RsSerialiser *setupSerialiser() { return NULL ; } + virtual bool saveList(bool&, std::list&) { return false ;} + virtual bool loadList(std::list&) { return false ;} + + private: + uint32_t _tick_delay_in_seconds ; +}; + diff --git a/libretroshare/src/plugins/pluginmanager.cc b/libretroshare/src/plugins/pluginmanager.cc new file mode 100644 index 000000000..3629368ce --- /dev/null +++ b/libretroshare/src/plugins/pluginmanager.cc @@ -0,0 +1,205 @@ +#include + +#include "pluginmanager.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// lets disable the plugin system for now, as it's unfinished. +#define WINDOWS_SYS +#ifndef WINDOWS_SYS +#include +#endif + +std::string RsPluginManager::_plugin_entry_symbol ; +std::string RsPluginManager::_local_cache_dir ; +std::string RsPluginManager::_remote_cache_dir ; +ftServer *RsPluginManager::_ftserver = NULL ; +p3ConnectMgr *RsPluginManager::_connectmgr = NULL ; + +typedef RsPlugin *(*RetroSharePluginEntry)(void) ; +RsPluginHandler *rsPlugins ; + +void RsPluginManager::setCacheDirectories(const std::string& local_cache, const std::string& remote_cache) +{ + _local_cache_dir = local_cache ; + _remote_cache_dir = remote_cache ; +} + +bool RsPluginManager::acceptablePluginName(const std::string& name) +{ + // Needs some windows specific code here + // +#ifdef WINDOWS_SYS + return name.size() > 4 && !strcmp(name.c_str()+name.size()-3,".dll") ; +#else + return name.size() > 3 && !strcmp(name.c_str()+name.size()-3,".so") ; +#endif +} + +void RsPluginManager::loadPlugins(const std::vector& plugin_directories) +{ + _plugin_entry_symbol = "RETROSHARE_PLUGIN_provide" ; + + // 0 - get the list of files to read + + for(uint32_t i=0;irs_cache_service() != NULL && (seconds % _plugins[i]->rs_cache_service()->tickDelay() )) + { + std::cerr << " ticking plugin " << _plugins[i]->getPluginName() << std::endl; + _plugins[i]->rs_cache_service()->tick() ; + } +} + +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) + { + 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 ; + } +} + +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) + { + pqih->addService(_plugins[i]->rs_pqi_service()) ; + std::cerr << " Added pqi service for plugin " << _plugins[i]->getPluginName() << std::endl; + } +} + +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) + { + 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; + } +} + +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()), + p3Config(config_type), // CONFIG_TYPE_RANK_LINK + _tick_delay_in_seconds(tick_delay) +{ +} + diff --git a/libretroshare/src/plugins/pluginmanager.h b/libretroshare/src/plugins/pluginmanager.h new file mode 100644 index 000000000..8f01e21d3 --- /dev/null +++ b/libretroshare/src/plugins/pluginmanager.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +class p3ConfigMgr ; +class p3ServiceServer ; +class p3ConnectMgr ; + +class RsPluginManager: public RsPluginHandler +{ + public: + RsPluginManager() {} + virtual ~RsPluginManager() {} + + virtual int nbPlugins() const { return _plugins.size() ; } + virtual RsPlugin *plugin(int i) { return _plugins[i] ; } + + 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 ; + + 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) ; + static void setFileServer(ftServer *ft) { _ftserver = ft ; } + static void setConnectMgr(p3ConnectMgr *cm) { _connectmgr = cm ; } + + void loadPlugins(const std::vector& plugin_directories) ; + + void registerCacheServices() ; + void registerClientServices(p3ServiceServer *pqih) ; + private: + bool loadPlugin(const std::string& shared_library_name) ; + + std::vector _plugins ; + + static std::string _plugin_entry_symbol ; + static std::string _remote_cache_dir ; + static std::string _local_cache_dir ; + static ftServer *_ftserver ; + static p3ConnectMgr *_connectmgr ; +}; + diff --git a/libretroshare/src/pqi/p3cfgmgr.h b/libretroshare/src/pqi/p3cfgmgr.h index 3ebee1a01..5ddcf7f9b 100644 --- a/libretroshare/src/pqi/p3cfgmgr.h +++ b/libretroshare/src/pqi/p3cfgmgr.h @@ -82,7 +82,6 @@ const uint32_t CONFIG_TYPE_TURTLE = 0x0020; /* wish these ids where higher... * may move when switch to v0.5 */ -const uint32_t CONFIG_TYPE_RANK_LINK = 0x0011; const uint32_t CONFIG_TYPE_CHAT = 0x0012; const uint32_t CONFIG_TYPE_STATUS = 0x0013; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index a53df6e22..9f3a7e362 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -37,6 +37,8 @@ class RsFiles; extern RsFiles *rsFiles; class Expression; +class CacheStrapper ; +class CacheTransfer; /* These are used mainly by ftController at the moment */ const uint32_t RS_FILE_CTRL_PAUSE = 0x00000100; @@ -194,7 +196,8 @@ class RsFiles virtual void setWatchPeriod(int minutes) =0; virtual int watchPeriod() const =0; - + virtual CacheStrapper *getCacheStrapper() =0; + virtual CacheTransfer *getCacheTransfer() =0; virtual bool getShareDownloadDirectory() = 0; virtual bool shareDownloadDirectory(bool share) = 0; diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 34e3cb448..a856a87e0 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -26,6 +26,7 @@ #include "rsserver/p3face.h" +#include "retroshare/rsplugin.h" #include "tcponudp/tou.h" #include @@ -55,7 +56,6 @@ RsServer::RsServer(RsIface &i, NotifyBase &callback) mChannels = NULL; mForums = NULL; /* caches (that need ticking) */ - mRanking = NULL; /* Config */ mConfigMgr = NULL; @@ -96,185 +96,148 @@ static double getCurrentTS() void RsServer::run() { - double timeDelta = 0.25; - double minTimeDelta = 0.1; // 25; - double maxTimeDelta = 0.5; - double kickLimit = 0.15; + double timeDelta = 0.25; + double minTimeDelta = 0.1; // 25; + double maxTimeDelta = 0.5; + double kickLimit = 0.15; - double avgTickRate = timeDelta; + double avgTickRate = timeDelta; - double lastts, ts; - lastts = ts = getCurrentTS(); + double lastts, ts; + lastts = ts = getCurrentTS(); - long lastSec = 0; /* for the slower ticked stuff */ + long lastSec = 0; /* for the slower ticked stuff */ - int min = 0; - int loop = 0; + int min = 0; + int loop = 0; - while(isRunning()) - { -#ifndef WINDOWS_SYS - usleep((int) (timeDelta * 1000000)); -#else - Sleep((int) (timeDelta * 1000)); -#endif - - ts = getCurrentTS(); - double delta = ts - lastts; - - /* for the fast ticked stuff */ - if (delta > timeDelta) + while(isRunning()) { -#ifdef DEBUG_TICK - std::cerr << "Delta: " << delta << std::endl; - std::cerr << "Time Delta: " << timeDelta << std::endl; - std::cerr << "Avg Tick Rate: " << avgTickRate << std::endl; +#ifndef WINDOWS_SYS + usleep((int) (timeDelta * 1000000)); +#else + Sleep((int) (timeDelta * 1000)); #endif - lastts = ts; + ts = getCurrentTS(); + double delta = ts - lastts; -/******************************** RUN SERVER *****************/ - lockRsCore(); - - int moreToTick = ftserver -> tick(); - -#ifdef DEBUG_TICK - std::cerr << "RsServer::run() ftserver->tick(): moreToTick: " << moreToTick << std::endl; -#endif - - unlockRsCore(); - - /* tick the connection Manager */ - mConnMgr->tick(); -/******************************** RUN SERVER *****************/ - - /* adjust tick rate depending on whether there is more. - */ - - avgTickRate = 0.2 * timeDelta + 0.8 * avgTickRate; - - if (1 == moreToTick) + /* for the fast ticked stuff */ + if (delta > timeDelta) { - timeDelta = 0.9 * avgTickRate; - if (timeDelta > kickLimit) +#ifdef DEBUG_TICK + std::cerr << "Delta: " << delta << std::endl; + std::cerr << "Time Delta: " << timeDelta << std::endl; + std::cerr << "Avg Tick Rate: " << avgTickRate << std::endl; +#endif + + lastts = ts; + + /******************************** RUN SERVER *****************/ + lockRsCore(); + + int moreToTick = ftserver -> tick(); + +#ifdef DEBUG_TICK + std::cerr << "RsServer::run() ftserver->tick(): moreToTick: " << moreToTick << std::endl; +#endif + + unlockRsCore(); + + /* tick the connection Manager */ + mConnMgr->tick(); + /******************************** RUN SERVER *****************/ + + /* adjust tick rate depending on whether there is more. + */ + + avgTickRate = 0.2 * timeDelta + 0.8 * avgTickRate; + + if (1 == moreToTick) { - /* force next tick in one sec - * if we are reading data. - */ - timeDelta = kickLimit; - avgTickRate = kickLimit; + timeDelta = 0.9 * avgTickRate; + if (timeDelta > kickLimit) + { + /* force next tick in one sec + * if we are reading data. + */ + timeDelta = kickLimit; + avgTickRate = kickLimit; + } } - } - else - { - timeDelta = 1.1 * avgTickRate; - } - - /* limiter */ - if (timeDelta < minTimeDelta) - { - timeDelta = minTimeDelta; - } - else if (timeDelta > maxTimeDelta) - { - timeDelta = maxTimeDelta; - } - - /* Fast Updates */ - - - /* now we have the slow ticking stuff */ - /* stuff ticked once a second (but can be slowed down) */ - if ((int) ts > lastSec) - { - lastSec = (int) ts; - - // Every second! (UDP keepalive). - //tou_tick_stunkeepalive(); - - // every five loops (> 5 secs) - if (loop % 5 == 0) + else { - // update_quick_stats(); + timeDelta = 1.1 * avgTickRate; + } - // Update All Every 5 Seconds. - // These Update Functions do the locking themselves. + /* limiter */ + if (timeDelta < minTimeDelta) + { + timeDelta = minTimeDelta; + } + else if (timeDelta > maxTimeDelta) + { + timeDelta = maxTimeDelta; + } + + /* Fast Updates */ + + + /* now we have the slow ticking stuff */ + /* stuff ticked once a second (but can be slowed down) */ + if ((int) ts > lastSec) + { + lastSec = (int) ts; + + // Every second! (UDP keepalive). + //tou_tick_stunkeepalive(); + + // every five loops (> 5 secs) + if (loop % 5 == 0) + { + // update_quick_stats(); + + // Update All Every 5 Seconds. + // These Update Functions do the locking themselves. #ifdef DEBUG_TICK - std::cerr << "RsServer::run() Updates()" << std::endl; + std::cerr << "RsServer::run() Updates()" << std::endl; #endif - - // These two have been completed! - //std::cerr << "RsServer::run() UpdateAllCerts()" << std::endl; - //UpdateAllCerts(); - //std::cerr << "RsServer::run() UpdateAllNetwork()" << std::endl; - //UpdateAllNetwork(); - - // currently Dummy Functions. - //std::cerr << "RsServer::run() UpdateAllTransfers()" << std::endl; - - //std::cerr << "RsServer::run() "; - //std::cerr << "UpdateRemotePeople()"<tick(); /* saves stuff */ - //std::cerr << "RsServer::run() CheckDHT()" << std::endl; - //CheckNetworking(); + } + // every 60 loops (> 1 min) + if (++loop >= 60) + { + loop = 0; + + /* force saving FileTransferStatus TODO */ + //ftserver->saveFileTransferStatus(); + + /* see if we need to resave certs */ + //AuthSSL::getAuthSSL()->CheckSaveCertificates(); + + /* hour loop */ + if (++min >= 60) + { + min = 0; + } + } /* Tick slow services */ -#ifndef MINIMAL_LIBRS - if (mRanking) - mRanking->tick(); -#endif // MINIMAL_LIBRS + if(rsPlugins) + rsPlugins->slowTickPlugins((time_t)ts); -#if 0 - std::string opt; - std::string val = "VALUE"; - { - std::ostringstream out; - out << "SEC:" << lastSec; - opt = out.str(); - } + // slow update tick as well. + // update(); + } // end of slow tick. - mGeneralConfig->setSetting(opt, val); -#endif - - mConfigMgr->tick(); /* saves stuff */ - - } - - // every 60 loops (> 1 min) - if (++loop >= 60) - { - loop = 0; - - /* force saving FileTransferStatus TODO */ - //ftserver->saveFileTransferStatus(); - - /* see if we need to resave certs */ - //AuthSSL::getAuthSSL()->CheckSaveCertificates(); - - /* hour loop */ - if (++min >= 60) - { - min = 0; - } - } - - // slow update tick as well. - // update(); - } // end of slow tick. - - } // end of only once a second. - } - return; + } // end of only once a second. + } + return; } diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index dac19ca1a..c01a6e182 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -41,7 +41,6 @@ #include "services/p3disc.h" #include "services/p3msgservice.h" #include "services/p3chatservice.h" -#include "services/p3ranking.h" #include "services/p3blogs.h" #include "services/p3statusservice.h" #include "services/p3channels.h" @@ -165,7 +164,6 @@ class RsServer: public RsControl, public RsThread p3Channels *mChannels; p3Forums *mForums; /* caches (that need ticking) */ - p3Ranking *mRanking; /* Config */ p3ConfigMgr *mConfigMgr; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 5966ebfa9..7d9ff3d05 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -38,6 +38,7 @@ #include "util/rsrandom.h" #include "util/folderiterator.h" #include "retroshare/rsinit.h" +#include "plugins/pluginmanager.h" #include "rsserver/rsloginhandler.h" #include @@ -1703,7 +1704,6 @@ RsTurtle *rsTurtle = NULL ; #include "services/p3msgservice.h" #include "services/p3chatservice.h" #include "services/p3gamelauncher.h" -#include "services/p3ranking.h" #include "services/p3photoservice.h" #include "services/p3forums.h" #include "services/p3channels.h" @@ -1725,7 +1725,6 @@ RsTurtle *rsTurtle = NULL ; /* Implemented Rs Interfaces */ #include "rsserver/p3face.h" #include "rsserver/p3peers.h" -#include "rsserver/p3rank.h" #include "rsserver/p3msgs.h" #include "rsserver/p3discovery.h" #include "rsserver/p3photo.h" @@ -1916,11 +1915,39 @@ int RsServer::StartupRetroShare() rsFiles = ftserver; - mConfigMgr = new p3ConfigMgr(RsInitConfig::configDir, "rs-v0.5.cfg", "rs-v0.5.sgn"); + mConfigMgr = new p3ConfigMgr(RsInitConfig::configDir, "rs-v0.5.cfg", "rs-v0.5.sgn"); mGeneralConfig = new p3GeneralConfig(); + /* create Cache Services */ + std::string config_dir = RsInitConfig::configDir; + std::string localcachedir = config_dir + "/cache/local"; + std::string remotecachedir = config_dir + "/cache/remote"; + std::string channelsdir = config_dir + "/channels"; + std::string blogsdir = config_dir + "/blogs"; + std::string forumdir = config_dir + "/forums"; + std::string plugins_dir = "." ; + + + std::vector plugins_directories ; + plugins_directories.push_back(".") ; // this list should be saved/set to some correct value. + // possible entries include: /usr/lib/retroshare, ~/.retroshare/extensions/, etc. + + RsPluginManager *mPluginsManager = new RsPluginManager ; + rsPlugins = mPluginsManager ; + + // 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() + // + mPluginsManager->setCacheDirectories(localcachedir,remotecachedir) ; + mPluginsManager->setFileServer(ftserver) ; + mPluginsManager->setConnectMgr(mConnMgr) ; + + // Now load the plugins. This parses the available SO/DLL files for known symbols. + // + mPluginsManager->loadPlugins(plugins_directories) ; + /* create Services */ - ad = new p3disc(mConnMgr, pqih); + ad = new p3disc(mConnMgr, pqih); #ifndef MINIMAL_LIBRS msgSrv = new p3MsgService(mConnMgr); chatSrv = new p3ChatService(mConnMgr); @@ -1943,51 +1970,32 @@ int RsServer::StartupRetroShare() pqih -> addService(msgSrv); pqih -> addService(chatSrv); pqih ->addService(mStatusSrv); + #endif // MINIMAL_LIBRS - - /* create Cache Services */ - std::string config_dir = RsInitConfig::configDir; - std::string localcachedir = config_dir + "/cache/local"; - std::string remotecachedir = config_dir + "/cache/remote"; - std::string channelsdir = config_dir + "/channels"; - std::string blogsdir = config_dir + "/blogs"; - std::string forumdir = config_dir + "/forums"; - - #ifndef MINIMAL_LIBRS - mRanking = new p3Ranking(mConnMgr, RS_SERVICE_TYPE_RANK, /* declaration of cache enable service rank */ - mCacheStrapper, mCacheTransfer, - localcachedir, remotecachedir, 3600 * 24 * 30 * 6); // 6 Months - CachePair cp(mRanking, mRanking, CacheId(RS_SERVICE_TYPE_RANK, 0)); - mCacheStrapper -> addCachePair(cp); /* end of declaration */ + mForums = new p3Forums(RS_SERVICE_TYPE_FORUM, mCacheStrapper, mCacheTransfer, localcachedir, remotecachedir, forumdir); - mForums = new p3Forums(RS_SERVICE_TYPE_FORUM, - mCacheStrapper, mCacheTransfer, - localcachedir, remotecachedir, forumdir); - - CachePair cp4(mForums, mForums, CacheId(RS_SERVICE_TYPE_FORUM, 0)); - mCacheStrapper -> addCachePair(cp4); + mCacheStrapper -> addCachePair( CachePair(mForums, mForums, CacheId(RS_SERVICE_TYPE_FORUM, 0))); pqih -> addService(mForums); /* This must be also ticked as a service */ - mChannels = new p3Channels(RS_SERVICE_TYPE_CHANNEL, - mCacheStrapper, mCacheTransfer, rsFiles, - localcachedir, remotecachedir, channelsdir); + mChannels = new p3Channels(RS_SERVICE_TYPE_CHANNEL, mCacheStrapper, mCacheTransfer, rsFiles, localcachedir, remotecachedir, channelsdir); - CachePair cp5(mChannels, mChannels, CacheId(RS_SERVICE_TYPE_CHANNEL, 0)); - mCacheStrapper -> addCachePair(cp5); + mCacheStrapper -> addCachePair(CachePair(mChannels, mChannels, CacheId(RS_SERVICE_TYPE_CHANNEL, 0))); pqih -> addService(mChannels); /* This must be also ticked as a service */ #ifdef RS_USE_BLOGS - p3Blogs *mBlogs = new p3Blogs(RS_SERVICE_TYPE_QBLOG, - mCacheStrapper, mCacheTransfer, rsFiles, - localcachedir, remotecachedir, blogsdir); + p3Blogs *mBlogs = new p3Blogs(RS_SERVICE_TYPE_QBLOG, mCacheStrapper, mCacheTransfer, rsFiles, localcachedir, remotecachedir, blogsdir); - CachePair cp6(mBlogs, mBlogs, CacheId(RS_SERVICE_TYPE_QBLOG, 0)); - mCacheStrapper -> addCachePair(cp6); + mCacheStrapper -> addCachePair(CachePair(mBlogs, mBlogs, CacheId(RS_SERVICE_TYPE_QBLOG, 0))); pqih -> addService(mBlogs); /* This must be also ticked as a service */ #endif - + // now add plugin objects inside the loop: + // - client services provided by plugins. + // - cache services provided by plugins. + // + mPluginsManager->registerClientServices(pqih) ; + mPluginsManager->registerCacheServices() ; #ifndef RS_RELEASE p3GameLauncher *gameLauncher = new p3GameLauncher(mConnMgr); @@ -2044,13 +2052,14 @@ int RsServer::StartupRetroShare() #ifdef RS_USE_BLOGS mConfigMgr->addConfiguration("blogs.cfg", mBlogs); #endif - mConfigMgr->addConfiguration("ranklink.cfg", mRanking); mConfigMgr->addConfiguration("forums.cfg", mForums); mConfigMgr->addConfiguration("channels.cfg", mChannels); mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv); #endif // MINIMAL_LIBRS mConfigMgr->addConfiguration("turtle.cfg", tr); - mConfigMgr->addConfiguration("p3disc.cfg", ad); + mConfigMgr->addConfiguration("p3disc.cfg", ad); + + mPluginsManager->addConfigurations(mConfigMgr) ; ftserver->addConfiguration(mConfigMgr); @@ -2210,10 +2219,9 @@ int RsServer::StartupRetroShare() rsDisc = new p3Discovery(ad); #ifndef MINIMAL_LIBRS - rsMsgs = new p3Msgs(msgSrv, chatSrv); + rsMsgs = new p3Msgs(msgSrv, chatSrv); rsForums = mForums; rsChannels = mChannels; - rsRanks = new p3Rank(mRanking); #ifdef RS_USE_BLOGS rsBlogs = mBlogs; #endif @@ -2228,7 +2236,6 @@ int RsServer::StartupRetroShare() #endif #endif // MINIMAL_LIBRS - #ifndef MINIMAL_LIBRS /* put a welcome message in! */ if (RsInitConfig::firsttime_run) diff --git a/libretroshare/src/serialiser/rsserviceids.h b/libretroshare/src/serialiser/rsserviceids.h index 60e933f11..afcad1de8 100644 --- a/libretroshare/src/serialiser/rsserviceids.h +++ b/libretroshare/src/serialiser/rsserviceids.h @@ -39,7 +39,6 @@ /* These are Cache Only */ const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001; -const uint16_t RS_SERVICE_TYPE_RANK = 0x0002; /* These are Services only */ const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; diff --git a/plugins/LinksCloud/AddLinksDialog.cpp b/plugins/LinksCloud/AddLinksDialog.cpp new file mode 100644 index 000000000..0edee0f01 --- /dev/null +++ b/plugins/LinksCloud/AddLinksDialog.cpp @@ -0,0 +1,124 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2008 Robert Fernie + * + * 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 + +#include "AddLinksDialog.h" +#include +#include "rsrank.h" + +/* Images for context menu icons */ +#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" +#define IMAGE_GREAT ":/images/filerating5.png" +#define IMAGE_GOOD ":/images/filerating4.png" +#define IMAGE_OK ":/images/filerating3.png" +#define IMAGE_SUX ":/images/filerating2.png" +#define IMAGE_BADLINK ":/images/filerating1.png" + +/** Constructor */ +AddLinksDialog::AddLinksDialog(QString url, QWidget *parent) +: QDialog(parent) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); + + setAttribute ( Qt::WA_DeleteOnClose, true ); + + /* add button */ + connect(ui.addLinkButton, SIGNAL(clicked()), this, SLOT(addLinkComment())); + connect(ui.closepushButton, SIGNAL(clicked()), this, SLOT(close())); + + connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( load ( void ) ) ); + + ui.linkLineEdit->setText(url); + + RetroShareLink link(url); + + if(link.valid() && link.type() == RetroShareLink::TYPE_FILE) + ui.titleLineEdit->setText(link.name()); + else + ui.titleLineEdit->setText("New File"); + + load(); + + /* Hide platform specific features */ +#ifdef Q_WS_WIN + +#endif +} + +int AddLinksDialog::IndexToScore(int index) +{ + if ((index == -1) || (index > 4)) + return 0; + int score = 2 - index; + return score; +} + +void AddLinksDialog::addLinkComment() +{ + /* get the title / link / comment */ + QString title = ui.titleLineEdit->text(); + QString link = ui.linkLineEdit->text(); + QString comment = ui.linkTextEdit->toPlainText(); + int32_t score = AddLinksDialog::IndexToScore(ui.scoreBox->currentIndex()); + + if ((link == "") || (title == "")) + { + QMessageBox::warning(NULL, tr("Add Link Failure"), tr("Missing Link and/or Title"), QMessageBox::Ok); + /* can't do anything */ + return; + } + + /* add it either way */ + if (ui.anonBox->isChecked()) + { + rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); + } + else + { + rsRanks->newRankMsg(link.toStdWString(), + title.toStdWString(), + comment.toStdWString(), score); + } + + close(); +} + +void AddLinksDialog::load() +{ + if (ui.anonBox->isChecked()) + { + + /* disable comment + score */ + ui.scoreBox->setEnabled(false); + ui.linkTextEdit->setEnabled(false); + + /* done! */ + return; + } + else + { + /* enable comment + score */ + ui.scoreBox->setEnabled(true); + ui.linkTextEdit->setEnabled(true); + } +} diff --git a/plugins/LinksCloud/AddLinksDialog.h b/plugins/LinksCloud/AddLinksDialog.h new file mode 100644 index 000000000..9e4451117 --- /dev/null +++ b/plugins/LinksCloud/AddLinksDialog.h @@ -0,0 +1,48 @@ +/**************************************************************** + * RetroShare GUI is distributed under the following license: + * + * Copyright (C) 2008 Robert Fernie + * + * 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. + ****************************************************************/ + +#ifndef _ADDLINKS_DIALOG_H +#define _ADDLINKS_DIALOG_H + +#include "ui_AddLinksDialog.h" + +class AddLinksDialog : public QDialog +{ + Q_OBJECT + +public: + /** Default Constructor */ + AddLinksDialog(QString url, QWidget *parent = 0); + /** Default Destructor */ + + static int IndexToScore(int index); + +public slots: + void addLinkComment(); + + void load(); + +private: + /** Qt Designer generated object */ + Ui::AddLinksDialog ui; +}; + +#endif diff --git a/plugins/LinksCloud/AddLinksDialog.ui b/plugins/LinksCloud/AddLinksDialog.ui new file mode 100644 index 000000000..04b9363a4 --- /dev/null +++ b/plugins/LinksCloud/AddLinksDialog.ui @@ -0,0 +1,288 @@ + + + AddLinksDialog + + + + 0 + 0 + 614 + 415 + + + + Add Link + + + + :/images/rstray3.png:/images/rstray3.png + + + + 0 + + + 0 + + + + + + 16777215 + 52 + + + + QFrame#frame{background-image: url(:/images/connect/connectFriendBanner.png);} + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 32 + 32 + + + + + + + :/images/irkick.png + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans'; font-size:18pt; font-weight:600; color:#ffffff;">Add Link to Cloud</span></p></body></html> + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + Cancel + + + + + + + Add Link + + + false + + + true + + + + + + + Qt::Horizontal + + + + 375 + 20 + + + + + + + + Add a new Link + + + + 1 + + + + + + + + + Title: + + + + + + + Url: + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + 16777215 + 40 + + + + QFrame#frame_3{ +background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, +stop:0 #FEFEFE, stop:1 #E8E8E8); + +border: 1px solid #CCCCCC;} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Add Anonymous Link + + + + + + + + +2 Great! + + + + :/images/filerating5.png:/images/filerating5.png + + + + + +1 Good + + + + :/images/filerating4.png:/images/filerating4.png + + + + + 0 Okay + + + + :/images/filerating3.png:/images/filerating3.png + + + + + -1 Sux + + + + :/images/filerating2.png:/images/filerating2.png + + + + + -2 Bad Link + + + + :/images/filerating1.png:/images/filerating1.png + + + + + + + + Qt::Horizontal + + + + 299 + 20 + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + + + + + + diff --git a/plugins/LinksCloud/LinksCloud.pro b/plugins/LinksCloud/LinksCloud.pro new file mode 100644 index 000000000..fdc4f3032 --- /dev/null +++ b/plugins/LinksCloud/LinksCloud.pro @@ -0,0 +1,11 @@ +!include("../Common/retroshare_plugin.pri"): error("Could not include file ../Common/retroshare_plugin.pri") + +CONFIG *= qt uic debug resources + +SOURCES = p3ranking.cc LinksDialog.cpp rsrankitems.cc AddLinksDialog.cpp LinksCloudPlugin.cpp +HEADERS = rsrank.h p3ranking.h LinksDialog.h rsrankitems.h AddLinksDialog.h LinksCloudPlugin.h +FORMS = LinksDialog.ui AddLinksDialog.ui + +TARGET = LinksCloud + +RESOURCES = images.qrc diff --git a/plugins/LinksCloud/LinksDialog.cpp b/plugins/LinksCloud/LinksDialog.cpp new file mode 100644 index 000000000..917b97ed8 --- /dev/null +++ b/plugins/LinksCloud/LinksDialog.cpp @@ -0,0 +1,1060 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2008 Robert Fernie + * + * 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 +#include +#include +#include +#include + +#include "LinksDialog.h" +#include +#include "AddLinksDialog.h" +#include +#include +#include "rsrank.h" + +#include + + +/* Images for context menu icons */ +#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" +#define IMAGE_GREAT ":/images/filerating5.png" +#define IMAGE_GOOD ":/images/filerating4.png" +#define IMAGE_OK ":/images/filerating3.png" +#define IMAGE_SUX ":/images/filerating2.png" +#define IMAGE_BADLINK ":/images/filerating1.png" +#define IMAGE_NOCOMMENTRATING ":/images/filerating0.png" +#define IMAGE_DOWNLOAD ":/images/download16.png" + +/****** + * #define LINKS_DEBUG 1 + *****/ + +/** Constructor */ +LinksDialog::LinksDialog(QWidget *parent) +: MainPage(parent) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); + + connect( ui.linkTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( linkTreeWidgetCostumPopupMenu( QPoint ) ) ); + + + /* link combos */ + connect( ui.rankComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortRank( int ) ) ); + connect( ui.periodComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortPeriod( int ) ) ); + connect( ui.fromComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortFrom( int ) ) ); + connect( ui.topComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortTop( int ) ) ); + + /* add button */ + connect( ui.addButton, SIGNAL( clicked( void ) ), this, SLOT( addLinkComment( void ) ) ); + connect( ui.expandButton, SIGNAL( clicked( void ) ), this, SLOT( toggleWindows( void ) ) ); + + connect( ui.pushButton, SIGNAL( clicked( ) ), this, SLOT( addNewLink( ) ) ); + + connect( ui.linkTreeWidget, SIGNAL( currentItemChanged ( QTreeWidgetItem *, QTreeWidgetItem * ) ), + this, SLOT( changedItem ( QTreeWidgetItem *, QTreeWidgetItem * ) ) ); + + connect( ui.linkTreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int ) ), + this, SLOT( openLink ( QTreeWidgetItem *, int ) ) ); + + connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( checkAnon ( void ) ) ); + + connect( ui.linklabel, SIGNAL(anchorClicked(const QUrl &)), SLOT(anchorClicked(const QUrl &))); + + + mStart = 0; + + + /* Set header resize modes and initial section sizes */ + QHeaderView * _header = ui.linkTreeWidget->header () ; + _header->setResizeMode (0, QHeaderView::Interactive); + _header->setResizeMode (1, QHeaderView::Interactive); + _header->setResizeMode (2, QHeaderView::Interactive); + + _header->resizeSection ( 0, 400 ); + _header->resizeSection ( 1, 60 ); + _header->resizeSection ( 2, 150 ); + + ui.linkTreeWidget->setSortingEnabled(true); + + ui.linklabel->setMinimumWidth(20); + + + /* Set a GUI update timer - much cleaner than + * doing everything through the notify agent + */ + + QTimer *timer = new QTimer(this); + timer->connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate())); + timer->start(1000); + + /* Hide platform specific features */ +#ifdef Q_WS_WIN + +#endif + +} + +void LinksDialog::checkUpdate() +{ + std::cerr << "In linksDialog::checkUpdate()" << std::endl; + /* update */ + if (!rsRanks) + { + std::cerr << " rsRanks = 0 !!!!" << std::endl; + return; + } + + if (rsRanks->updated()) + { + std::cerr << " rsRanks was updated -> redraw()" << std::endl; + updateLinks(); + } + + return; +} + +void LinksDialog::linkTreeWidgetCostumPopupMenu( QPoint point ) +{ + + QMenu contextMnu( this ); + + QAction *voteupAct = new QAction(QIcon(IMAGE_EXPORTFRIEND), tr( "Share Link Anonymously" ), &contextMnu ); + connect( voteupAct , SIGNAL( triggered() ), this, SLOT( voteup_anon() ) ); + + + QMenu *voteMenu = new QMenu( tr("Vote on Link"), &contextMnu ); + voteMenu->setIcon(QIcon(IMAGE_EXPORTFRIEND)); + + QAction *vote_p2 = new QAction( QIcon(IMAGE_GREAT), "[+2] Great", &contextMnu ); + connect( vote_p2 , SIGNAL( triggered() ), this, SLOT( voteup_p2() ) ); + voteMenu->addAction(vote_p2); + QAction *vote_p1 = new QAction( QIcon(IMAGE_GOOD), "[+1] Good", &contextMnu ); + connect( vote_p1 , SIGNAL( triggered() ), this, SLOT( voteup_p1() ) ); + voteMenu->addAction(vote_p1); + QAction *vote_p0 = new QAction( QIcon(IMAGE_OK), "[+0] Okay", &contextMnu ); + connect( vote_p0 , SIGNAL( triggered() ), this, SLOT( voteup_p0() ) ); + voteMenu->addAction(vote_p0); + QAction *vote_m1 = new QAction( QIcon(IMAGE_SUX), "[-1] Sux", &contextMnu ); + connect( vote_m1 , SIGNAL( triggered() ), this, SLOT( voteup_m1() ) ); + voteMenu->addAction(vote_m1); + QAction *vote_m2 = new QAction( QIcon(IMAGE_BADLINK), "[-2] BAD LINK", &contextMnu ); + connect( vote_m2 , SIGNAL( triggered() ), this, SLOT( voteup_m2() ) ); + voteMenu->addAction(vote_m2); + + QAction *downloadAct = new QAction(QIcon(IMAGE_DOWNLOAD), tr("Download"), &contextMnu); + connect(downloadAct, SIGNAL(triggered()), this, SLOT(downloadSelected())); + + contextMnu.addAction(voteupAct); + contextMnu.addSeparator(); + contextMnu.addMenu(voteMenu); + contextMnu.addSeparator(); + contextMnu.addAction(downloadAct); + + contextMnu.exec(QCursor::pos()); +} + +void LinksDialog::changedSortRank( int index ) +{ + /* update */ + if (!rsRanks) + return; + + /* translate */ + uint32_t type = 0; + switch (index) + { + case 1: + type = RS_RANK_TIME; + break; + case 2: + type = RS_RANK_SCORE; + break; + default: + case 0: + type = RS_RANK_ALG; + break; + } + + if (type) + { + rsRanks->setSortMethod(type); + } + updateLinks(); +} + +void LinksDialog::changedSortPeriod( int index ) +{ + /* update */ + if (!rsRanks) + return; + + /* translate */ + uint32_t period = 0; + switch (index) + { + case 1: + period = 60 * 60 * 24 * 7; /* WEEK */ + break; + case 2: + period = 60 * 60 * 24; /* DAY */ + break; + default: + case 0: + period = 60 * 60 * 24 * 30; /* MONTH */ + break; + } + + if (period) + { + rsRanks->setSortPeriod(period); + } + updateLinks(); +} + +void LinksDialog::changedSortFrom( int index ) +{ + /* update */ + if (!rsRanks) + return; + + std::list peers; + + /* translate */ + switch (index) + { + default: + case 0: + break; + case 1: + peers.push_back(rsPeers->getOwnId()); + break; + } + + if (peers.size() < 1) + { + rsRanks->clearPeerFilter(); + } + else + { + rsRanks->setPeerFilter(peers); + } + updateLinks(); +} + +#define ENTRIES_PER_BLOCK 100 + +void LinksDialog::changedSortTop( int index ) +{ + /* update */ + if (!rsRanks) + return; + + std::list peers; + + /* translate */ + switch (index) + { + default: + case 0: + mStart = 0; + break; + case 1: + mStart = 1 * ENTRIES_PER_BLOCK; + break; + case 2: + mStart = 2 * ENTRIES_PER_BLOCK; + break; + case 3: + mStart = 3 * ENTRIES_PER_BLOCK; + break; + case 4: + mStart = 4 * ENTRIES_PER_BLOCK; + break; + case 5: + mStart = -1; + break; + } + updateLinks(); +} + + +/* get the list of Links from the RsRanks. */ +void LinksDialog::updateLinks() +{ + + std::list rids; + std::list::iterator rit; + std::list::iterator cit; + +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::updateLinks()" << std::endl; +#endif + + /* Work out the number/entries to show */ + uint32_t count = rsRanks->getRankingsCount(); + uint32_t start; + + uint32_t entries = ENTRIES_PER_BLOCK; + if (count < entries) + { + entries = count; + } + + if (mStart == -1) + { + /* backwards */ + start = count-entries; + } + else + { + start = mStart; + if (start + entries > count) + { + start = count - entries; + } + } + + /* get a link to the table */ + QTreeWidget *linkWidget = ui.linkTreeWidget; + QList items; + + rsRanks->getRankings(start, entries, rids); + float maxRank = rsRanks->getMaxRank(); + + for(rit = rids.begin(); rit != rids.end(); rit++) + { + RsRankDetails detail; + if (!rsRanks->getRankDetails(*rit, detail)) + { + continue; + } + + /* create items */ + QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); + + /* (0) Title */ + { + item -> setText(0, QString::fromStdWString(detail.title)); + item -> setSizeHint(0, QSize( 20,20 ) ); + + /* Bold and bigger */ + /*QFont font = item->font(0); + font.setBold(true); + font.setPointSize(font.pointSize() + 2); + item->setFont(0, font);*/ + } + + /* (1) Rank */ + { + std::ostringstream out; + out << 100 * (detail.rank / (maxRank + 0.01)); + item -> setText(1, QString::fromStdString(out.str())); + item -> setSizeHint(1, QSize( 20,20 ) ); + + /* Bold and bigger */ + /*QFont font = item->font(1); + font.setBold(true); + font.setPointSize(font.pointSize() + 2); + item->setFont(1, font);*/ + } + + /* (2) Link */ + { + item -> setText(2, QString::fromStdWString(detail.link)); + item -> setSizeHint(2, QSize( 20,20 ) ); + + /* Bold and bigger */ + /*QFont font = item->font(2); + font.setBold(true); + font.setPointSize(font.pointSize() + 2); + item->setFont(2, font);*/ + } + + /* (3) Date */ + /*{ + QDateTime qtime; + qtime.setTime_t(it->lastPost); + QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); + item -> setText(3, timestamp); + }*/ + + + /* (4) rid */ + item -> setText(4, QString::fromStdString(detail.rid)); + + + /* add children */ + int i = 0; + for(cit = detail.comments.begin(); + cit != detail.comments.end(); cit++, i++) + { + /* create items */ + QTreeWidgetItem *child = new QTreeWidgetItem((QTreeWidget*)0); + + QString commentText; + QString peerScore; + if (cit->score > 1) + { + peerScore = "[+2] "; + child -> setIcon(0,(QIcon(IMAGE_GREAT))); + item -> setIcon(0,(QIcon(IMAGE_GREAT))); + //peerScore = "[+2 Great Link] "; + } + else if (cit->score == 1) + { + peerScore = "[+1] "; + child -> setIcon(0,(QIcon(IMAGE_GOOD))); + item -> setIcon(0,(QIcon(IMAGE_GOOD))); + //peerScore = "[+1 Good] "; + } + else if (cit->score == 0) + { + peerScore = "[+0] "; + child -> setIcon(0,(QIcon(IMAGE_OK))); + item -> setIcon(0,(QIcon(IMAGE_OK))); + //peerScore = "[+0 Okay] "; + } + else if (cit->score == -1) + { + peerScore = "[-1] "; + child -> setIcon(0,(QIcon(IMAGE_SUX))); + item -> setIcon(0,(QIcon(IMAGE_SUX))); + //peerScore = "[-1 Not Worth It] "; + } + else //if (cit->score < -1) + { + peerScore = "[-2 BAD] "; + child -> setIcon(0,(QIcon(IMAGE_BADLINK))); + item -> setIcon(0,(QIcon(IMAGE_BADLINK))); + //peerScore = "[-2 BAD Link] "; + } + + /* (0) Comment */ + if (cit->comment != L"") + { + commentText = peerScore + QString::fromStdWString(cit->comment); + } + else + { + commentText = peerScore + "No Comment"; + } + child -> setText(0, commentText); + + /* (2) Peer / Date */ + { + QDateTime qtime; + qtime.setTime_t(cit->timestamp); + QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); + + QString peerLabel = QString::fromStdString(rsPeers->getPeerName(cit->id)); + if (peerLabel == "") + { + peerLabel = "<"; + peerLabel += QString::fromStdString(cit->id); + peerLabel += ">"; + } + peerLabel += " "; + + peerLabel += timestamp; + child -> setText(2, peerLabel); + + } + + /* (4) Id */ + child -> setText(4, QString::fromStdString(cit->id)); + + if (i % 2 == 1) + { + /* set to light gray background */ + child->setBackground(0,QBrush(Qt::lightGray)); + child->setBackground(1,QBrush(Qt::lightGray)); + child->setBackground(2,QBrush(Qt::lightGray)); + } + + /* push to items */ + item->addChild(child); + } + + /* add to the list */ + items.append(item); + } + + /* remove old items */ + linkWidget->clear(); + linkWidget->setColumnCount(3); + + /* add the items in! */ + linkWidget->insertTopLevelItems(0, items); + + linkWidget->update(); /* update display */ + + +} + +void LinksDialog::openLink ( QTreeWidgetItem * item, int ) +{ +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::openLink()" << std::endl; +#endif + + /* work out the ids */ + if (!item) + { + +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::openLink() Failed Item" << std::endl; +#endif + return; + } + + std::string rid; + std::string pid; + + QTreeWidgetItem *parent = item->parent(); + if (parent) + { + /* a child comment -> ignore double click */ +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::openLink() Failed Child" << std::endl; +#endif + return; + } + +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::openLink() " << (item->text(2)).toStdString() << std::endl; +#endif + /* open a browser */ + QUrl url(item->text(2)); + QDesktopServices::openUrl ( url ); + + /* close expansion */ + bool state = item->isExpanded(); + item->setExpanded(!state); +} + +void LinksDialog::changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *) +{ + /* work out the ids */ + if (!curr) + { + updateComments("", ""); + return; + } + + std::string rid; + std::string pid; + + QTreeWidgetItem *parent = curr->parent(); + if (parent) + { + rid = (parent->text(4)).toStdString(); + pid = (curr->text(4)).toStdString(); + +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: " << pid; + std::cerr << std::endl; +#endif + + updateComments(rid, pid); + } + else + { + rid = (curr->text(4)).toStdString(); + +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: NULL"; + std::cerr << std::endl; +#endif + + updateComments(rid, ""); + } +} + +void LinksDialog::checkAnon() +{ + changedItem(ui.linkTreeWidget->currentItem(), NULL); +} + + +int IndexToScore(int index) +{ + if ((index == -1) || (index > 4)) + return 0; + int score = 2 - index; + return score; +} + +int ScoreToIndex(int score) +{ + if ((score < -2) || (score > 2)) + return 2; + int index = 2 - score; + return index; +} + + +/* get the list of Links from the RsRanks. */ +void LinksDialog::updateComments(std::string rid, std::string ) +{ + std::list::iterator cit; + + + if (ui.anonBox->isChecked()) + { + /* empty everything */ + ui.titleLineEdit->setText(""); + ui.linkLineEdit->setText(""); + ui.linkTextEdit->setText(""); + ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); + mLinkId = rid; /* must be set for Context Menu */ + + /* disable comment + score */ + ui.scoreBox->setEnabled(false); + ui.linkTextEdit->setEnabled(false); + + /* done! */ + return; + } + else + { + /* enable comment + score */ + ui.scoreBox->setEnabled(true); + ui.linkTextEdit->setEnabled(true); + } + + + RsRankDetails detail; + if ((rid == "") || (!rsRanks->getRankDetails(rid, detail))) + { + /* clear it up */ + ui.titleLineEdit->setText(""); + ui.linkLineEdit->setText(""); + ui.linkTextEdit->setText(""); + ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); + mLinkId = rid; + return; + } + + + /* set Link details */ + ui.titleLineEdit->setText(QString::fromStdWString(detail.title)); + ui.linkLineEdit->setText(QString::fromStdWString(detail.link)); + ui.linklabel->setHtml(" " + QString::fromStdWString(detail.link) +""); + + + if (mLinkId == rid) + { + /* leave comments */ + //ui.linkTextEdit->setText(""); + return; + } + + mLinkId = rid; + + /* Add your text to the comment */ + std::string ownId = rsPeers->getOwnId(); + + for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) + { + if (cit->id == ownId) + break; + } + + if (cit != detail.comments.end()) + { + QString comment = QString::fromStdWString(cit->comment); + ui.linkTextEdit->setText(comment); + ui.scoreBox->setCurrentIndex(ScoreToIndex(cit->score)); + } + else + { + ui.linkTextEdit->setText(""); + ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); + + } + + return; +} + +void LinksDialog::addLinkComment( void ) +{ + /* get the title / link / comment */ + QString title = ui.titleLineEdit->text(); + QString link = ui.linkLineEdit->text(); + QString comment = ui.linkTextEdit->toPlainText(); + int32_t score = IndexToScore(ui.scoreBox->currentIndex()); + + if ((mLinkId == "") || (ui.anonBox->isChecked())) + { + if ((link == "") || (title == "")) + { + QMessageBox::warning ( NULL, "Add Link Failure", "Missing Link and/or Title", QMessageBox::Ok); + /* can't do anything */ + return; + } + + /* add it either way */ + if (ui.anonBox->isChecked()) + { + rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); + } + else + { + rsRanks->newRankMsg( + link.toStdWString(), + title.toStdWString(), + comment.toStdWString(), score); + } + + updateLinks(); + return; + } + + /* get existing details */ + + RsRankDetails detail; + if (!rsRanks->getRankDetails(mLinkId, detail)) + { + /* strange error! */ + QMessageBox::warning ( NULL, "Add Link Failure", "Missing Link Data", QMessageBox::Ok); + return; + } + + if (link.toStdWString() == detail.link) /* same link! - we can add a comment */ + { + if (comment == "") /* no comment! */ + { + QMessageBox::warning ( NULL, "Add Link Failure", "Missing Comment", QMessageBox::Ok); + return; + } + + rsRanks->updateComment(mLinkId, + comment.toStdWString(), + score); + } + else + { + QMessageBox::StandardButton sb = QMessageBox::Yes; + + if ((title.toStdWString() == detail.title) /* same title! - wrong */ + || (title == "")) + { + sb = QMessageBox::question ( NULL, "Link Title Not Changed", + "Do you want to continue?", + (QMessageBox::Yes | QMessageBox::No)); + } + + /* add Link! */ + if (sb == QMessageBox::Yes) + { + rsRanks->newRankMsg( + link.toStdWString(), + title.toStdWString(), + comment.toStdWString(), + score); + } + } + updateLinks(); + return; +} + +void LinksDialog::toggleWindows( void ) +{ + /* if msg header visible -> hide by changing splitter + */ + + QList sizeList = ui.msgSplitter->sizes(); + QList::iterator it; + + int listSize = 0; + int msgSize = 0; + int i = 0; + + for(it = sizeList.begin(); it != sizeList.end(); it++, i++) + { + if (i == 0) + { + listSize = (*it); + } + else if (i == 1) + { + msgSize = (*it); + } + } + + int totalSize = listSize + msgSize; + + bool toShrink = true; + if (msgSize < (int) totalSize / 10) + { + toShrink = false; + } + + QList newSizeList; + if (toShrink) + { + newSizeList.push_back(totalSize); + newSizeList.push_back(0); + ui.expandButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); + ui.expandButton->setToolTip(tr("Expand")); + } + else + { + newSizeList.push_back(totalSize * 3/4); + newSizeList.push_back(totalSize * 1/4); + ui.expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); + ui.expandButton->setToolTip(tr("Hide")); + } + + ui.msgSplitter->setSizes(newSizeList); + return; +} + + +QTreeWidgetItem *LinksDialog::getCurrentLine() +{ + /* get the current, and extract the Id */ + + /* get a link to the table */ + QTreeWidget *peerWidget = ui.linkTreeWidget; + QTreeWidgetItem *item = peerWidget -> currentItem(); + if (!item) + { +#ifdef LINKS_DEBUG + std::cerr << "Invalid Current Item" << std::endl; +#endif + return NULL; + } + +#ifdef LINKS_DEBUG + /* Display the columns of this item. */ + std::ostringstream out; + out << "CurrentPeerItem: " << std::endl; + + for(int i = 1; i < 6; i++) + { + QString txt = item -> text(i); + out << "\t" << i << ":" << txt.toStdString() << std::endl; + } + std::cerr << out.str(); +#endif + + return item; +} + +void LinksDialog::voteup_anon() +{ + //QTreeWidgetItem *c = getCurrentLine(); + + if (mLinkId == "") + { + return; + } + + RsRankDetails detail; + if (!rsRanks->getRankDetails(mLinkId, detail)) + { + /* not there! */ + return; + } + + QString link = QString::fromStdWString(detail.link); +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::voteup_anon() : " << link.toStdString() << std::endl; +#endif + // need a proper anon sharing option. + rsRanks->anonRankMsg(mLinkId, detail.link, detail.title); +} + + + + +void LinksDialog::voteup_score(int score) +{ + if (mLinkId == "") + { + return; + } + + RsRankDetails detail; + if (!rsRanks->getRankDetails(mLinkId, detail)) + { + /* not there! */ + return; + } + + QString link = QString::fromStdWString(detail.link); + std::wstring comment; +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::voteup_score() : " << link.toStdString() << std::endl; +#endif + + + std::list::iterator cit; + /* Add your text to the comment */ + std::string ownId = rsPeers->getOwnId(); + + for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) + { + if (cit->id == ownId) + break; + } + + if (cit != detail.comments.end()) + { + comment = cit->comment; + } + + rsRanks->updateComment(mLinkId, comment, score); +} + + +void LinksDialog::voteup_p2() +{ + voteup_score(2); +} + +void LinksDialog::voteup_p1() +{ + voteup_score(1); +} + +void LinksDialog::voteup_p0() +{ + voteup_score(0); +} + +void LinksDialog::voteup_m1() +{ + voteup_score(-1); +} + +void LinksDialog::voteup_m2() +{ + voteup_score(-2); +} + +void LinksDialog::downloadSelected() +{ + if (mLinkId == "") + { + return; + } + + RsRankDetails detail; + if (!rsRanks->getRankDetails(mLinkId, detail)) + { + /* not there! */ + return; + } + + QString link = QString::fromStdWString(detail.link); + std::wstring comment; +#ifdef LINKS_DEBUG + std::cerr << "LinksDialog::downloadSelected() : " << link.toStdString() << std::endl; +#endif + + RetroShareLink rslink(QString::fromStdWString(detail.link)); + + if(!rslink.valid() || rslink.type() != RetroShareLink::TYPE_FILE) + { + QMessageBox::critical(NULL,"Badly formed link","This link is badly formed. Can't parse/use it. This is a bug. Please contact the developers.") ; + return ; + } + + /* retrieve all peers id for this file */ + FileInfo info; + rsFiles->FileDetails(rslink.hash().toStdString(), 0, info); + + std::list srcIds; + std::list::iterator pit; + for (pit = info.peers.begin(); pit != info.peers.end(); pit ++) + srcIds.push_back(pit->peerId); + + rsFiles->FileRequest(rslink.name().toStdString(), rslink.hash().toStdString(), rslink.size(), "", 0, srcIds); +} + +void LinksDialog::anchorClicked (const QUrl& link ) +{ + #ifdef LINK_DEBUG + std::cerr << "LinksDialog::anchorClicked link.scheme() : " << link.scheme().toStdString() << std::endl; + #endif + + if (link.scheme() == "retroshare") + { + QStringList L = link.toString().split("|") ; + + std::string fileName = L.at(1).toStdString() ; + uint64_t fileSize = L.at(2).toULongLong(); + std::string fileHash = L.at(3).toStdString() ; + +#ifdef LINK_DEBUG + std::cerr << "LinksDialog::anchorClicked FileRequest : fileName : " << fileName << ". fileHash : " << fileHash << ". fileSize : " << fileSize << std::endl; +#endif + + if (fileName != "" && fileHash != "") + { + std::list srcIds; + + if(rsFiles->FileRequest(fileName, fileHash, fileSize, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds)) + { + QMessageBox mb(tr("File Request Confirmation"), tr("The file has been added to your download list."),QMessageBox::Information,QMessageBox::Ok,0,0,this); + mb.setWindowIcon(QIcon(QString::fromUtf8(":/images/rstray3.png"))); + mb.exec(); + } + else + { + QMessageBox mb(tr("File Request canceled"), tr("The file has not been added to your download list, because you already have it."),QMessageBox::Information,QMessageBox::Ok,0,0,this); + mb.exec(); + } + } + else + { + QMessageBox mb(tr("File Request Error"), tr("The file link is malformed."),QMessageBox::Information,QMessageBox::Ok,0,0,this); + mb.setWindowIcon(QIcon(QString::fromUtf8(":/images/rstray3.png"))); + mb.exec(); + } + } + else if (link.scheme() == "http") + { + QDesktopServices::openUrl(link); + } + else if (link.scheme() == "") + { + //it's probably a web adress, let's add http:// at the beginning of the link + QString newAddress = link.toString(); + newAddress.prepend("http://"); + QDesktopServices::openUrl(QUrl(newAddress)); + } +} + +void LinksDialog::addNewLink() +{ + + AddLinksDialog *nAddLinksDialog = new AddLinksDialog(""); + + nAddLinksDialog->show(); + + /* window will destroy itself! */ +} diff --git a/plugins/LinksCloud/LinksDialog.h b/plugins/LinksCloud/LinksDialog.h new file mode 100644 index 000000000..38a15e98f --- /dev/null +++ b/plugins/LinksCloud/LinksDialog.h @@ -0,0 +1,92 @@ +/**************************************************************** + * RetroShare GUI is distributed under the following license: + * + * Copyright (C) 2008 Robert Fernie + * + * 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. + ****************************************************************/ + +#ifndef _LINKS_DIALOG_H +#define _LINKS_DIALOG_H + +#include +#include "ui_LinksDialog.h" + + +class LinksDialog : public MainPage +{ + Q_OBJECT + +public: + /** Default Constructor */ + LinksDialog(QWidget *parent = 0); + /** Default Destructor */ + + void insertExample(); + +private slots: + /** Create the context popup menu and it's submenus */ + void linkTreeWidgetCostumPopupMenu( QPoint point ); + + void voteup_anon(); + void voteup_score(int score); + void voteup_p2(); + void voteup_p1(); + void voteup_p0(); + void voteup_m1(); + void voteup_m2(); + void downloadSelected(); + + void changedSortRank( int index ); + void changedSortPeriod( int index ); + void changedSortFrom( int index ); + void changedSortTop( int index ); + + void updateLinks(); + void addLinkComment( void ); + void toggleWindows( void ); + + void openLink ( QTreeWidgetItem * item, int column ); + void changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *prev); + void checkAnon(); + + void checkUpdate(); + + void anchorClicked (const QUrl &); + + void addNewLink(); + +private: + +void updateComments(std::string rid, std::string pid); + + int mStart; /* start of rank list */ + std::string mLinkId; + + /* Worker Functions */ + /* (1) Update Display */ + + /* (2) Utility Fns */ + QTreeWidgetItem *getCurrentLine(); + + QTreeWidget *exampletreeWidget; + + /** Qt Designer generated object */ + Ui::LinksDialog ui; +}; + +#endif + diff --git a/plugins/LinksCloud/LinksDialog.ui b/plugins/LinksCloud/LinksDialog.ui new file mode 100644 index 000000000..59055342b --- /dev/null +++ b/plugins/LinksCloud/LinksDialog.ui @@ -0,0 +1,587 @@ + + + LinksDialog + + + + 0 + 0 + 738 + 583 + + + + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + Qt::Vertical + + + + + + + + 9 + + + + Qt::CustomContextMenu + + + + Title / Comment + + + + + Score + + + + + Peer / Link + + + + + + + + + + + + :/images/edit_remove24.png:/images/edit_remove24.png + + + + + + + Qt::Horizontal + + + + 16 + 20 + + + + + + + + + 75 + true + + + + Sort by + + + + + + + + Combo + + + + + Time + + + + :/images/kalarm.png:/images/kalarm.png + + + + + Ranking + + + + :/images/records.png:/images/records.png + + + + + + + + Qt::Horizontal + + + + 16 + 20 + + + + + + + + + 75 + true + + + + In last + + + + + + + + Month + + + + :/images/view_calendar_month.png:/images/view_calendar_month.png + + + + + Week + + + + :/images/view_calendar_week.png:/images/view_calendar_week.png + + + + + Day + + + + :/images/view_calendar_day.png:/images/view_calendar_day.png + + + + + + + + Qt::Horizontal + + + + 16 + 20 + + + + + + + + + 75 + true + + + + From + + + + + + + + All Peers + + + + :/images/user/friends24.png:/images/user/friends24.png + + + + + Own Links + + + + :/images/user/identity16.png:/images/user/identity16.png + + + + + + + + Qt::Horizontal + + + + 16 + 20 + + + + + + + + + 75 + true + + + + Show + + + + + + + + Top 100 + + + + :/images/records.png:/images/records.png + + + + + 101-200 + + + + + 201-300 + + + + + 301-400 + + + + + 401-500 + + + + + Bottom 100 + + + + + + + + + 16777215 + 22 + + + + QTextBrowser{border: 2px solid #CCCCCC; +border-radius: 10px; +background: white;} + + + Qt::ScrollBarAlwaysOff + + + false + + + + + + + + 75 + true + + + + Link: + + + + + + + + + + + + + Qt::Horizontal + + + + 311 + 32 + + + + + + + + + 50 + false + + + + Add Anonymous Link + + + + + + + Add Link/Comment + + + + + + + + + + + Title: + + + + + + + QLineEdit{border: 2px solid #CCCCCC; +border-radius: 10px; +background: white;} + + + + + + + Score: + + + + + + + + +2 Great! + + + + :/images/filerating5.png:/images/filerating5.png + + + + + +1 Good + + + + :/images/filerating4.png:/images/filerating4.png + + + + + 0 Okay + + + + :/images/filerating3.png:/images/filerating3.png + + + + + -1 Sux + + + + :/images/filerating2.png:/images/filerating2.png + + + + + -2 Bad Link + + + + :/images/filerating1.png:/images/filerating1.png + + + + + + + + + + + + Url: + + + + + + + QLineEdit{border: 2px solid #CCCCCC; +border-radius: 10px; +background: white;} + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QTextEdit{border: 2px solid #CCCCCC; +border-radius: 10px; +background: white;} + + + + + + + + + + + + 16777215 + 32 + + + + QFrame#frame{ +background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, +stop:0 #FEFEFE, stop:1 #E8E8E8); + +border: 1px solid #CCCCCC;} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + + + + 24 + 24 + + + + + + + :/images/irkick.png + + + true + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><span style=" font-weight:600;">Links Cloud</span></p></body></html> + + + + + + + Qt::Horizontal + + + + 596 + 15 + + + + + + + + QPushButton:hover { +border: 1px solid #CCCCCC; +} + + + Add new link + + + + :/images/edit_add24.png:/images/edit_add24.png + + + true + + + + + + + + + + + + + diff --git a/plugins/LinksCloud/images.qrc b/plugins/LinksCloud/images.qrc new file mode 100644 index 000000000..8b2550249 --- /dev/null +++ b/plugins/LinksCloud/images.qrc @@ -0,0 +1,5 @@ + + + images/irkick.png + + diff --git a/plugins/LinksCloud/images/irkick.png b/plugins/LinksCloud/images/irkick.png new file mode 100644 index 0000000000000000000000000000000000000000..b399814ff4a9fd45cdcd7e7562ba9e43ce42fb9e GIT binary patch literal 2231 zcmV;o2uSydP)w#;t#aqsTT+_|rF{DYllx{ZZuh~Izr zyT9-Je&_qn<2!_Nj{m2La~+Q3$N(zq7M* z_xA1E=Y1IYGtWG8Wp8iq)23-Y4d4RXwx6Azp571y0b`7zt*vb}=lqfep3csGUOJt= zT2)m9L4Zo7@*CT>Un!MJ9h#;c>F(}skK=fW>$*Qb75V1Po7E#nj@;7T-hOr_lUbsw z>Ndx5GD(u$SFKk6IWseZmX;P-QIs1`5WqQKm`bHOtJNxkAaLV2zTa^iQI_Qg+S=Mu z05Cp2?#FTb=TixgB#G7Q_1#C09))FDNT<{1P)ctu7K^ody?%cbMVxbvR4Vm3$8qw< z1&E^fNz*iidc6+c_y1wr_I^UhIf|mJuq+ExQ&ZgYyiEYM1HiMn7Ikm`f(`#Vzwqq7 zesjkk=aVY{z_#r$j^mB4>;BDkU09Yy48yp|aU6>=_GAzQW4`ahFpM_N`DXxt-ulgJ z3{BIPP)ZTUF)EeHUI3t!ej%MsOTO=8W@hFvW9;5_>(;ULH+@ma2-CmMf8~NZdvCt# zlHNaRp%qy3 zA#oGmxh*X=O1j7Q{lh^JK$c~JQo0lXk|f#BIfoz!5Jj;M07O9$bO8OFb1=q|u?f=NNfH+T zXvLeZGR9^or4R%`Fio=y0HP>*D+mJUx(-!UFLoTKw?VMsZT_=;F7^#ofx|W6&f3L4 z-S{qlt0|2uRaNa$6a`@zMx65(0YDIh#gtMcNrEs84*~%F)%HiKuIoP9n5`_!mpYC^ zIp@1v*Y#ythG7^BL{S_ll}ZW#EGV3-Re=R=49p||+~Gol+;N;vRaL*Q>$(sG0jkyN z0nYg=rBbO^QIy59EW`KxI7yOMfZ1~(j^kIW)oP@wDpXZHmk@HkZQBRKFnnxkY6`8b ztuPE@Eg>K5_s&As0$oH_BY;W)7_9{W*tTt(B+K&csZ?rlCX<2Zd8}TqZ!H#!H9-)* zt|&^2rfH~DDrG{*p5p=tA%{HAdsEkSD2k#fit=5@acC4p>nA5CUkif3&*gIO0SE!W z^U;+Oq3Z&m5CBx`nJpWWBxyRI&rgqyjU`i4Q;#yn9x9beIbGLp6-ALS#^8D0AJ(s5 zKYCn1u~_sy&-+ECQem2=!8Fa)l+v}fZI9P#wbjGJ!@sOlDtDcC-g(afKt#1(jRLv| z7!t5*p_{vB!w=13v6w7cwCJIsp`k~{#>RdfMUf4F$+CQxuIt^FWnp}L+)a{XTcc#n zx8bAXlShj3g1pt;^zO+vi0aFAd0%)q( z`mGyo?goJ6%a;$8%jMhSI356Sj8eMBFpO(tSqA4E6B82;Q%c`F&fDA*ZrQTs^SNB^ z$!s<|uUsy(YPGtfR;#U@+eY2iCqM8BExOheftd(+sqfS1?m7SRE%)B{bTh70D$O$t z<3ZCjznshEq(g@ez3O@1mm29mAp-y~Ffj03xm;d9IXO9<&1Qo*j$fZk4gg9V^%@jN ziGU#hg*WzM>tp-QoQn&?utF()p|i8Ia`^D!gRbk|&`f@k005wrK0G`;d~La0b`~yN z_}t@(-qN@Y8{7Lsd&raC1s@t +#include + +#include "pqi/p3connmgr.h" +#include "pqi/pqibin.h" +#include "pqi/authssl.h" +#include "pqi/pqistore.h" + +RsRanks *rsRanks = NULL ; + +const uint32_t RANK_MAX_FWD_OFFSET = (60 * 60 * 24 * 2); /* 2 Days */ +const uint32_t RANK_STORE_PERIOD = (60 * 60 * 24 * 30 * 6); /* 6 months */ + +const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 60; /* every minute for testing */ +//const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 1800; /* every 30 minutes */ + +std::string generateRandomLinkId(); + +/***** + * TODO + * (1) Streaming. + * (2) Ranking. + * + */ + +/********* + * #define RANK_DEBUG 1 + *********/ +#define RANK_DEBUG 1 + +p3Ranking::p3Ranking() + : RsCacheService(RS_SERVICE_TYPE_RANK,CONFIG_TYPE_RANK_LINK,5), + mRepublish(false), mRepublishFriends(false), mRepublishFriendTS(0), mStorePeriod(RANK_STORE_PERIOD), mUpdated(true) +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + mOwnId = rsPlugins->getConnectMgr()->getOwnId(); + mViewPeriod = 60 * 60 * 24 * 30; /* one Month */ + mSortType = RS_RANK_ALG; +} + +bool p3Ranking::loadLocalCache(const CacheData &data) +{ + std::string filename = data.path + '/' + data.name; + std::string hash = data.hash; + //uint64_t size = data.size; + std::string source = data.pid; + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadLocalCache()"; + std::cerr << std::endl; + std::cerr << "\tSource: " << source; + std::cerr << std::endl; + std::cerr << "\tFilename: " << filename; + std::cerr << std::endl; + std::cerr << "\tHash: " << hash; + std::cerr << std::endl; + std::cerr << "\tSize: " << data.size; + std::cerr << std::endl; +#endif + + loadRankFile(filename, source); + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + mRepublish = false; + } + + if (data.size > 0) /* don't refresh zero sized caches */ + { + refreshCache(data); + } + return true; +} + +int p3Ranking::loadCache(const CacheData &data) +{ + std::string filename = data.path + '/' + data.name; + std::string hash = data.hash; + //uint64_t size = data.size; + std::string source = data.pid; + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadCache()"; + std::cerr << std::endl; + std::cerr << "\tSource: " << source; + std::cerr << std::endl; + std::cerr << "\tFilename: " << filename; + std::cerr << std::endl; + std::cerr << "\tHash: " << hash; + std::cerr << std::endl; + std::cerr << "\tSize: " << data.size; + std::cerr << std::endl; +#endif + + loadRankFile(filename, source); + + + CacheStore::lockData(); /***** LOCK ****/ + locked_storeCacheEntry(data); + CacheStore::unlockData(); /***** UNLOCK ****/ + + return 1; +} + + +void p3Ranking::loadRankFile(std::string filename, std::string src) +{ + /* create the serialiser to load info */ + RsSerialiser *rsSerialiser = new RsSerialiser(); + rsSerialiser->addSerialType(new RsRankSerialiser()); + + uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE; + BinInterface *bio = new BinFileInterface(filename.c_str(), bioflags); + pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_READABLE); + + time_t now = time(NULL); + time_t min, max; + + { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + min = now - mStorePeriod; + max = now + RANK_MAX_FWD_OFFSET; + + } /********** STACK LOCKED MTX ******/ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadRankFile()"; + std::cerr << std::endl; + std::cerr << "\tSource: " << src; + std::cerr << std::endl; + std::cerr << "\tFilename: " << filename; + std::cerr << std::endl; +#endif + + RsItem *item; + RsRankLinkMsg *newMsg; + + while(NULL != (item = store->GetItem())) + { + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadRankFile() Got Item:"; + std::cerr << std::endl; + item->print(std::cerr, 10); + std::cerr << std::endl; +#endif + + if (NULL == (newMsg = dynamic_cast(item))) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadRankFile() Item not LinkMsg (deleting):"; + std::cerr << std::endl; +#endif + + delete item; + } + /* check timestamp */ + else if (((time_t) newMsg->timestamp < min) || + ((time_t) newMsg->timestamp > max)) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadRankFile() Outside TimeRange (deleting):"; + std::cerr << std::endl; +#endif + /* if outside range -> remove */ + delete newMsg; + } + else + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadRankFile() Loading Item"; + std::cerr << std::endl; +#endif + /* correct the source (if is a message from a friend) */ + newMsg->PeerId(newMsg->pid); + addRankMsg(newMsg); + } + } + + delete store; +} + + +void p3Ranking::publishMsgs(bool own) +{ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs()"; + std::cerr << std::endl; +#endif + + std::string path = CacheSource::getCacheDir(); + std::ostringstream out; + uint16_t subid; + + + /* setup name / etc based on whether we're + * publishing own or friends... + */ + + if (own) + { + /* setup to publish own messages */ + out << "rank-links-" << time(NULL) << ".rsrl"; + subid = 1; + } + else + { + /* setup to publish friend messages */ + out << "rank-friend-links-" << time(NULL) << ".rsrl"; + subid = 2; + } + + /* determine filename */ + std::string tmpname = out.str(); + std::string fname = path + "/" + tmpname; + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() Storing to: " << fname; + std::cerr << std::endl; +#endif + + RsSerialiser *rsSerialiser = new RsSerialiser(); + rsSerialiser->addSerialType(new RsRankSerialiser()); + + uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE; + BinInterface *bio = new BinFileInterface(fname.c_str(), bioflags); + pqistore *store = new pqistore(rsSerialiser, mOwnId, bio, BIN_FLAGS_NO_DELETE | BIN_FLAGS_WRITEABLE); + + { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + /* iterate through list */ + std::map::iterator it; + std::map::iterator cit; + + for(it = mData.begin(); it != mData.end(); it++) + { + if (own) + { + if (it->second.ownTag) + { + /* write to serialiser */ + RsItem *item = it->second.comments[mOwnId]; + if (item) + { + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() Storing Item:"; + std::cerr << std::endl; + item->print(std::cerr, 10); + std::cerr << std::endl; +#endif + store->SendItem(item); + } + } + else + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() Skipping Foreign item"; + std::cerr << std::endl; +#endif + } + } + else + { + /* if we have pushed it out already - don't bother */ + if (it->second.ownTag) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() (Friends) Skipping Own Item"; + std::cerr << std::endl; +#endif + continue; + } + + /* if we have some comments ... then a friend has recommended it + * serialise a sanitized version. + */ + if (it->second.comments.size() > 0) + { + RsRankLinkMsg *origmsg = (it->second.comments.begin())->second; + RsRankLinkMsg *msg = new RsRankLinkMsg(); + + /* copy anon data */ + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ + msg->clear(); + msg->PeerId(""); + msg->pid = ""; /* Anon */ + msg->rid = origmsg->rid; + msg->link = origmsg->link; + msg->title = origmsg->title; + msg->timestamp = origmsg->timestamp; + msg->score = 0; + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() (Friends) Storing (Anon) Item:"; + std::cerr << std::endl; + msg->print(std::cerr, 10); + std::cerr << std::endl; +#endif + store->SendItem(msg); + + /* cleanup */ + delete msg; + } + } + } + + + /* now we also add our anon messages to the friends list */ + if (!own) + { + std::list::iterator ait; + for(ait=mAnon.begin(); ait != mAnon.end(); ait++) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() (Friends) Adding Own Anon Item:"; + std::cerr << std::endl; + (*ait)->print(std::cerr, 10); + std::cerr << std::endl; +#endif + store->SendItem(*ait); + } + } + + } /********** STACK LOCKED MTX ******/ + + /* flag as new info */ + CacheData data; + + { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + data.pid = mOwnId; + } /********** STACK LOCKED MTX ******/ + + data.cid = CacheId(CacheSource::getCacheType(), subid); + + data.path = path; + data.name = tmpname; + + data.hash = bio->gethash(); + data.size = bio->bytecount(); + data.recvd = time(NULL); + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::publishMsgs() refreshing Cache"; + std::cerr << std::endl; + std::cerr << "\tCache Path: " << data.path; + std::cerr << std::endl; + std::cerr << "\tCache Name: " << data.name; + std::cerr << std::endl; + std::cerr << "\tCache Hash: " << data.hash; + std::cerr << std::endl; + std::cerr << "\tCache Size: " << data.size; + std::cerr << std::endl; +#endif + if (data.size > 0) /* don't refresh zero sized caches */ + { + refreshCache(data); + } + + delete store; +} + + + +void p3Ranking::addRankMsg(RsRankLinkMsg *msg) +{ + /* find msg */ + std::string id = msg->PeerId(); + std::string rid = msg->rid; + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() Item:"; + std::cerr << std::endl; + msg->print(std::cerr, 10); + std::cerr << std::endl; +#endif + + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it; + it = mData.find(rid); + if (it == mData.end()) + { + /* add a new one */ + RankGroup grp; + grp.rid = rid; + grp.ownTag = false; + grp.rank = 0.0f; + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ + + grp.link = msg->link; + grp.title = msg->title; + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ + + mData[rid] = grp; + it = mData.find(rid); + + if (id == "") + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() New Anon Link: mUpdated = true"; + std::cerr << std::endl; +#endif + locked_reSortGroup(it->second); + mUpdated = true; + } + } + + /**** If it is an anonymous Link (ie Friend of a Friend) Drop out now ***/ + if (id == "") + { + return; + } + + /* check for old comment */ + std::map::iterator cit; + cit = (it->second).comments.find(id); + + /* Check that it is different! */ + bool newComment = false; + if ((it->second).comments.end() == cit) + { + newComment = true; + } + else + { + RsRankLinkMsg *old = cit->second; + if ((msg->timestamp != old->timestamp) || + (msg->comment != old->comment)) + { + newComment = true; + } + } + + if (newComment) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() New Comment"; + std::cerr << std::endl; +#endif + /* clean up old */ + if ((it->second).comments.end() != cit) + { + delete (cit->second); + (it->second).comments.erase(cit); + } + + /* add in */ + (it->second).comments[id] = msg; + + /* republish? */ + if (id == mOwnId) + { + it->second.ownTag = true; + mRepublish = true; +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() Own Comment: mRepublish = true"; + std::cerr << std::endl; +#endif + } + else + { + mRepublishFriends = true; +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() Other Comment: mRepublishFriends = true"; + std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; + std::cerr << std::endl; +#endif + } + + locked_reSortGroup(it->second); + + mUpdated = true; + } + else + { + delete msg; +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; + std::cerr << std::endl; +#endif + } +} + + +/***************** Sorting ****************/ + +bool p3Ranking::setSortPeriod(uint32_t period) +{ + bool reSort = false; + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + reSort = (mViewPeriod != period); + mViewPeriod = period; + } + + + if (reSort) + { + sortAllMsgs(); + } + + return true; +} + +bool p3Ranking::setSortMethod(uint32_t type) +{ + bool reSort = false; + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + reSort = (mSortType != type); + mSortType = type; + } + + if (reSort) + { + sortAllMsgs(); + } + + return true; +} + +bool p3Ranking::clearPeerFilter() +{ + bool reSort = false; + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + reSort = (mPeerFilter.size() > 0); + mPeerFilter.clear(); + } + + + if (reSort) + { + sortAllMsgs(); + } + + return true; +} + +bool p3Ranking::setPeerFilter(std::list peers) +{ + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + mPeerFilter = peers; + } + + sortAllMsgs(); + + return true; +} + +float p3Ranking::locked_calcRank(RankGroup &grp) +{ + /* Ranking Calculations ..... + */ + + time_t now = time(NULL); + time_t minTime = now-mViewPeriod; + bool doFilter = (mPeerFilter.size() > 0); + bool doScore = (mSortType & RS_RANK_SCORE); + bool doTime = (mSortType & RS_RANK_TIME); + + uint32_t count = 0; + float algScore = 0; + float comboScore = 0; + float popScore = 0; + +#ifdef RANK_DEBUG + std::string normlink(grp.link.begin(), grp.link.end()); + std::cerr << "p3Ranking::locked_calcRank() for: " << normlink; + std::cerr << std::endl; + std::cerr << "Period: " << mViewPeriod; + std::cerr << " doFilter: " << doFilter; + std::cerr << " doScore: " << doScore; + std::cerr << " doTime: " << doTime; + std::cerr << std::endl; +#endif + + std::map::iterator it; + for(it = grp.comments.begin(); it != grp.comments.end(); it++) + { +#ifdef RANK_DEBUG + std::cerr << "Comment by:" << it->first << " age: " << now - it->second->timestamp; + std::cerr << std::endl; +#endif + if (doFilter) + { + if (mPeerFilter.end() == + std::find(mPeerFilter.begin(), mPeerFilter.end(), it->first)) + { + continue; /* skip it */ +#ifdef RANK_DEBUG + std::cerr << "\tFiltered Out"; + std::cerr << std::endl; +#endif + + } + } + + /* if Scoring is involved... drop old ones */ + if ((doScore) && ((time_t) it->second->timestamp < minTime)) + { +#ifdef RANK_DEBUG + std::cerr << "\tToo Old"; + std::cerr << std::endl; +#endif + continue; + } + + time_t deltaT; + if ((time_t) it->second->timestamp > now) + { + deltaT = it->second->timestamp - now; + } + else + { + deltaT = now - it->second->timestamp; + } + float timeScore = ((float) mViewPeriod - deltaT) / (mViewPeriod + 0.01); + +#ifdef RANK_DEBUG + std::cerr << "\tTimeScore: " << timeScore; + std::cerr << std::endl; +#endif + + /* algScore is sum of (filtered) timeScores */ + /* timeScore is average of (all) timeScores */ + /* popScore is just count of valid scores */ + + algScore += timeScore; + count++; + + /* for more advanced scoring (where each peer gives a score +2 -> -2) */ + /* combo = SUM value * timeScore */ + /* time = same as before (average) */ + /* popScore = SUM value */ + + float value = it->second->score; + comboScore += value * timeScore; + popScore += value; + } + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::locked_calcRank() algScore: " << algScore; + std::cerr << " Count: " << count; + std::cerr << std::endl; +#endif + + if ((count <= 0) || (algScore <= 0)) + { +#ifdef RANK_DEBUG + std::cerr << "Final score: 0"; + std::cerr << std::endl; +#endif + return 0; + } + + if ((doScore) && (doTime)) + { +#ifdef RANK_DEBUG + std::cerr << "Old (alg) score:" << algScore; + std::cerr << std::endl; + std::cerr << "Final (Combo) score:" << comboScore; + std::cerr << std::endl; +#endif + + if (comboScore < 0) + { +#ifdef RANK_DEBUG + std::cerr << "Combo score reset = 0"; + std::cerr << std::endl; +#endif + comboScore = 0; + } + return comboScore; + + } + else if (doScore) + { +#ifdef RANK_DEBUG + std::cerr << "Old (tally) score:" << count; + std::cerr << std::endl; + std::cerr << "Final (pop) score:" << popScore; + std::cerr << std::endl; +#endif + if (popScore < 0) + { +#ifdef RANK_DEBUG + std::cerr << "Pop score reset = 0"; + std::cerr << std::endl; +#endif + popScore = 0; + } + return popScore; + } + else if (doTime) + { +#ifdef RANK_DEBUG + std::cerr << "Final (time) score:" << algScore / count; + std::cerr << std::endl; +#endif + return algScore / count; + } + return 0; +} + + +void p3Ranking::locked_reSortGroup(RankGroup &grp) +{ + std::string rid = grp.rid; + + /* remove from existings rankings */ + std::multimap::iterator rit; + rit = mRankings.lower_bound(grp.rank); + for(; (rit != mRankings.end()) && (rit->first == grp.rank); rit++) + { + if (rit->second == rid) + { + mRankings.erase(rit); + break; + } + } + + /* add it back in */ + grp.rank = locked_calcRank(grp); + mRankings.insert( + std::pair(grp.rank, rid)); +} + +void p3Ranking::sortAllMsgs() +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + /* iterate through list and re-score each one */ + std::map::iterator it; + + mRankings.clear(); + + for(it = mData.begin(); it != mData.end(); it++) + { + (it->second).rank = locked_calcRank(it->second); + if (it->second.rank < 0) + { + it->second.rank = 0; + } + + mRankings.insert( + std::pair + (it->second.rank, it->first)); + } +} + +/******** ACCESS *************/ + + /* get Ids */ +uint32_t p3Ranking::getRankingsCount() +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + return mRankings.size(); +} + +float p3Ranking::getMaxRank() +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + if (mRankings.size() == 0) + return 0; + + return mRankings.rbegin()->first; +} + +bool p3Ranking::getRankings(uint32_t first, uint32_t count, std::list &rids) +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::getRankings() First: " << first << " Count: " << count; + std::cerr << std::endl; +#endif + + uint32_t i = 0; + std::multimap::reverse_iterator rit; + for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++); + + i = 0; + for(; (i < count) && (rit != mRankings.rend()); rit++, i++) + { + rids.push_back(rit->second); + } + return true; +} + + +bool p3Ranking::getRankDetails(std::string rid, RsRankDetails &details) +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + /* get the details. */ + + std::map::iterator it; + it = mData.find(rid); + if (mData.end() == it) + { + return false; + } + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ + + details.rid = it->first; + details.link = (it->second).link; + details.title = (it->second).title; + details.rank = (it->second).rank; + details.ownTag = (it->second).ownTag; + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ + + std::map::iterator cit; + for(cit = (it->second).comments.begin(); + cit != (it->second).comments.end(); cit++) + { + RsRankComment comm; + comm.id = (cit->second)->PeerId(); + comm.timestamp = (cit->second)->timestamp; + comm.comment = (cit->second)->comment; + comm.score = (cit->second)->score; + + details.comments.push_back(comm); + } + + return true; +} + + +void p3Ranking::tick() +{ + bool repub = false; + bool repubFriends = false; + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + repub = mRepublish; + repubFriends = mRepublishFriends && (time(NULL) > mRepublishFriendTS); + } + + if (repub) + { + publishMsgs(true); + + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + mRepublish = false; + } + + + if (repubFriends) + { + publishMsgs(false); + + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + mRepublishFriends = false; + mRepublishFriendTS = time(NULL) + FRIEND_RANK_REPUBLISH_PERIOD; + } + + +} + +bool p3Ranking::updated() +{ + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + if (mUpdated) + { + mUpdated = false; + return true; + } + return false; +} + +/***** NEW CONTENT *****/ +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ +std::string p3Ranking::newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) +{ + /* generate an id */ + std::string rid = generateRandomLinkId(); + + RsRankLinkMsg *msg = new RsRankLinkMsg(); + + time_t now = time(NULL); + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + msg->PeerId(mOwnId); + msg->pid = mOwnId; + } + + msg->rid = rid; + msg->title = title; + msg->timestamp = now; + msg->comment = comment; + msg->score = score; + + msg->linktype = RS_LINK_TYPE_WEB; + msg->link = link; + + + addRankMsg(msg); + + return rid; +} + + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ +bool p3Ranking::updateComment(std::string rid, std::wstring comment, int32_t score) +{ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::updateComment() rid:" << rid; + std::cerr << std::endl; +#endif + RsRankLinkMsg *msg = NULL; + + { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it; + it = mData.find(rid); + if (it == mData.end()) + { + /* missing group -> fail */ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::updateComment() Failed - noData"; + std::cerr << std::endl; +#endif + return false; + } + + msg = new RsRankLinkMsg(); + + time_t now = time(NULL); + + msg->PeerId(mOwnId); + msg->pid = mOwnId; + msg->rid = rid; + msg->timestamp = now; + msg->title = (it->second).title; + msg->comment = comment; + msg->score = score; + + msg->linktype = RS_LINK_TYPE_WEB; + msg->link = (it->second).link; + + } /********** STACK UNLOCKED MTX ******/ + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::updateComment() Item:"; + std::cerr << std::endl; + msg->print(std::cerr, 10); + std::cerr << std::endl; +#endif + + addRankMsg(msg); + return true; +} + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ +std::string p3Ranking::anonRankMsg(std::string rid, std::wstring link, std::wstring title) +{ + bool alreadyExists = true; + + if (rid == "") + { + alreadyExists = false; + /* generate an id */ + rid = generateRandomLinkId(); + } + + RsRankLinkMsg *msg1 = new RsRankLinkMsg(); + RsRankLinkMsg *msg2 = new RsRankLinkMsg(); + + time_t now = time(NULL); + + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + msg1->PeerId(""); + msg1->pid = ""; + + msg2->PeerId(""); + msg2->pid = ""; + } + + msg1->rid = rid; + msg1->title = title; + msg1->timestamp = now; + msg1->comment.clear(); + msg1->score = 0; + + msg1->linktype = RS_LINK_TYPE_WEB; + msg1->link = link; + + msg2->rid = rid; + msg2->title = title; + msg2->timestamp = now; + msg2->comment.clear(); + msg2->score = 0; + + msg2->linktype = RS_LINK_TYPE_WEB; + msg2->link = link; + + if (alreadyExists) + { + delete msg1; + } + else + { + addRankMsg(msg1); + } + + addAnonToList(msg2); + + return rid; +} + + + +pqistore *createStore(std::string file, std::string src, bool reading) +{ + + RsSerialiser *rsSerialiser = new RsSerialiser(); + rsSerialiser->addSerialType(new RsRankSerialiser()); + + uint32_t bioflags = BIN_FLAGS_HASH_DATA; + if (reading) + { + bioflags |= BIN_FLAGS_READABLE; + } + else + { + bioflags |= BIN_FLAGS_WRITEABLE; + } + + /* bin flags: READ | WRITE | HASH_DATA */ + BinInterface *bio = new BinFileInterface(file.c_str(), bioflags); + /* store flags: NO_DELETE (yes) | NO_CLOSE (no) */ + pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_NO_DELETE | (bioflags & BIN_FLAGS_WRITEABLE)); + + return store; +} + +std::string generateRandomLinkId() +{ + std::ostringstream out; + out << std::hex; +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#ifndef WINDOWS_SYS + /* 4 bytes per random number: 4 x 4 = 16 bytes */ + for(int i = 0; i < 4; i++) + { + out << std::setw(8) << std::setfill('0'); + uint32_t rint = random(); + out << rint; + } +#else + srand(time(NULL)); + /* 2 bytes per random number: 8 x 2 = 16 bytes */ + for(int i = 0; i < 8; i++) + { + out << std::setw(4) << std::setfill('0'); + uint16_t rint = rand(); /* only gives 16 bits */ + out << rint; + } +#endif +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + return out.str(); +} + + +/*************************************************************************/ +/****************************** LINK SPECIFIC ****************************/ +/*************************************************************************/ +void p3Ranking::createDummyData() +{ + RsRankLinkMsg *msg = new RsRankLinkMsg(); + + time_t now = time(NULL); + + msg->PeerId(mOwnId); + msg->pid = mOwnId; + msg->rid = "0001"; + msg->title = L"Original Awesome Site!"; + msg->timestamp = now - 60 * 60 * 24 * 15; + msg->link = L"http://www.retroshare.org"; + msg->comment = L"Retroshares Website"; + msg->score = 1; + + addRankMsg(msg); + + msg = new RsRankLinkMsg(); + msg->PeerId(mOwnId); + msg->pid = mOwnId; + msg->rid = "0002"; + msg->title = L"Awesome Site!"; + msg->timestamp = now - 123; + msg->link = L"http://www.lunamutt.org"; + msg->comment = L"Lunamutt's Website"; + msg->score = 1; + + addRankMsg(msg); + + msg = new RsRankLinkMsg(); + msg->PeerId("ALTID"); + msg->pid = "ALTID"; + msg->rid = "0002"; + msg->title = L"Awesome Site!"; + msg->timestamp = now - 60 * 60 * 24 * 29; + msg->link = L"http://www.lunamutt.org"; + msg->comment = L"Lunamutt's Website (TWO) How Long can this comment be!\n"; + msg->comment += L"What happens to the second line?\n"; + msg->comment += L"And a 3rd!"; + msg->score = 1; + + addRankMsg(msg); + + msg = new RsRankLinkMsg(); + msg->PeerId("ALTID2"); + msg->pid = "ALTID2"; + msg->rid = "0002"; + msg->title = L"Awesome Site!"; + msg->timestamp = now - 60 * 60 * 7; + msg->link = L"http://www.lunamutt.org"; + msg->comment += L"A Short Comment"; + msg->score = 1; + + addRankMsg(msg); + + + /***** Third one ****/ + + msg = new RsRankLinkMsg(); + msg->PeerId(mOwnId); + msg->pid = mOwnId; + msg->rid = "0003"; + msg->title = L"Weird Site!"; + msg->timestamp = now - 60 * 60; + msg->link = L"http://www.lunamutt.com"; + msg->comment = L""; + msg->score = 1; + + addRankMsg(msg); + + msg = new RsRankLinkMsg(); + msg->PeerId("ALTID"); + msg->pid = "ALTID"; + msg->rid = "0003"; + msg->title = L"Weird Site!"; + msg->timestamp = now - 60 * 60 * 24 * 2; + msg->link = L"http://www.lunamutt.com"; + msg->comment = L""; + msg->score = 1; + + addRankMsg(msg); + +} + + +/***************************************************************************/ +/****************************** CONFIGURATION HANDLING *********************/ +/***************************************************************************/ + +/**** Store Anon Links: OVERLOADED FROM p3Config ****/ + +RsSerialiser *p3Ranking::setupSerialiser() +{ + RsSerialiser *rss = new RsSerialiser(); + + /* add in the types we need! */ + rss->addSerialType(new RsRankSerialiser()); + return rss; +} + +bool p3Ranking::addAnonToList(RsRankLinkMsg *msg) +{ + { + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + std::list::iterator it; + for(it = mAnon.begin(); it != mAnon.end(); it++) + { + if (msg->rid == (*it)->rid) + break; + } + + if (it != mAnon.end()) + { + delete msg; + return false; + } + + mAnon.push_back(msg); + mRepublishFriends = true; + } + + IndicateConfigChanged(); /**** INDICATE CONFIG CHANGED! *****/ + return true; +} + +bool p3Ranking::saveList(bool &cleanup, std::list & saveData) +{ + + mRankMtx.lock(); /*********************** LOCK *******/ + + cleanup = false; + + std::list::iterator it; + for(it = mAnon.begin(); it != mAnon.end(); it++) + { + saveData.push_back(*it); + } + + /* list completed! */ + return true; +} + +void p3Ranking::saveDone() +{ + mRankMtx.unlock(); /*********************** UNLOCK *******/ + return; +} + +bool p3Ranking::loadList(std::list& load) +{ + std::list::iterator it; + RsRankLinkMsg *msg; + +#ifdef SERVER_DEBUG + std::cerr << "p3Ranking::loadList() Item Count: " << load.size(); + std::cerr << std::endl; +#endif + + time_t now = time(NULL); + time_t min, max; + + { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + + min = now - mStorePeriod; + max = now + RANK_MAX_FWD_OFFSET; + + } /********** STACK LOCKED MTX ******/ + + for(it = load.begin(); it != load.end(); it++) + { + /* switch on type */ + if (NULL != (msg = dynamic_cast(*it))) + { + /* check date -> if old expire */ + if (((time_t) msg->timestamp < min) || + ((time_t) msg->timestamp > max)) + { +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadList() Outside TimeRange (deleting Own Anon):"; + std::cerr << std::endl; +#endif + /* if outside range -> remove */ + delete msg; + continue; + } + +#ifdef RANK_DEBUG + std::cerr << "p3Ranking::loadList() Anon TimeRange ok"; + std::cerr << std::endl; +#endif + msg->PeerId(""); + msg->pid = ""; + + RsRankLinkMsg *msg2 = new RsRankLinkMsg(); + msg2->clear(); + msg2->PeerId(msg->PeerId()); + msg2->pid = msg->pid; + msg2->rid = msg->rid; + msg2->title = msg->title; + msg2->timestamp = msg->timestamp; + msg2->comment.clear(); + msg2->score = 0; + + msg2->linktype = msg->linktype; + msg2->link = msg->link; + + /* make a copy to add into standard map */ + addRankMsg(msg); + + RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ + mAnon.push_back(msg2); + } + else + { + /* cleanup */ + delete (*it); + } + } + + return true; + +} + diff --git a/plugins/LinksCloud/p3ranking.h b/plugins/LinksCloud/p3ranking.h new file mode 100644 index 000000000..6b5abac7f --- /dev/null +++ b/plugins/LinksCloud/p3ranking.h @@ -0,0 +1,165 @@ +/* + * libretroshare/src/services: p3ranking.h + * + * 3P/PQI network interface for RetroShare. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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 "retroshare@lunamutt.com". + * + */ + +#ifndef P3_GENERIC_RANKING_HEADER +#define P3_GENERIC_RANKING_HEADER + +class pqistore ; + +#include "retroshare/rsplugin.h" +#include "plugins/pluginclasses.h" + +#include "rsrank.h" + +/* + * A Generic Ranking system. + * Each User provides one cache... + * + * can be overloaded for specific types + * (links, shares, photos etc) + * + * This is not generic yet!!! + */ + +class RsRankMsg; +class RsRankLinkMsg; + +const uint16_t RS_SERVICE_TYPE_RANK = 0x0002 ; +const uint32_t CONFIG_TYPE_RANK_LINK = 0x0011 ; + +class RankGroup +{ + public: + + std::string rid; /* Random Id */ + std::wstring link; + std::wstring title; + float rank; + bool ownTag; + std::map comments; +}; + +class p3Ranking: public RsCacheService, public RsRanks +{ + public: + + p3Ranking() ; + + + /******************************* CACHE SOURCE / STORE Interface *********************/ + + /* overloaded functions from Cache Source */ + virtual bool loadLocalCache(const CacheData &data); + + /* overloaded functions from Cache Store */ + virtual int loadCache(const CacheData &data); + + /******************************* CACHE SOURCE / STORE Interface *********************/ + + public: + + /************* Extern Interface *******/ + + /* changed */ + virtual bool updated(); + + /* Set Sort Methods */ + virtual bool setSortPeriod(uint32_t period); + virtual bool setSortMethod(uint32_t type); + virtual bool clearPeerFilter(); + virtual bool setPeerFilter(std::list peers); + + /* get Ids */ + virtual uint32_t getRankingsCount(); + virtual float getMaxRank(); + virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids); + virtual bool getRankDetails(std::string rid, RsRankDetails &details); + + /* Add New Comment / Msg */ + virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score); + virtual bool updateComment(std::string rid, std::wstring comment, int32_t score); + virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title); + + + virtual void tick(); + + void loadRankFile(std::string filename, std::string src); + void addRankMsg(RsRankLinkMsg *msg); + void publishMsgs(bool own); + + float locked_calcRank(RankGroup &grp); /* returns 0->100 */ + void locked_reSortGroup(RankGroup &grp); + + void sortAllMsgs(); + pqistore *createStore(std::string file, std::string src, bool reading); + + + /****************** p3Config STUFF *******************/ + protected: + bool addAnonToList(RsRankLinkMsg *msg); + + virtual RsSerialiser *setupSerialiser(); + virtual bool saveList(bool &cleanup, std::list&); + virtual bool loadList(std::list& load); + virtual void saveDone(); + + private: + + void createDummyData(); + + uint32_t storePeriod; + p3ConnectMgr *mConnMgr; + + RsMutex mRankMtx; + + /***** below here is locked *****/ + + bool mRepublish; + bool mRepublishFriends; + time_t mRepublishFriendTS; + + uint32_t mStorePeriod; + + std::string mOwnId; + bool mUpdated; + bool mRepost; + + std::map mData; + std::multimap mRankings; + + /* Filter/Sort params */ + std::list mPeerFilter; + uint32_t mViewPeriod; + uint32_t mSortType; + + /* Anonymous Link List */ + std::list mAnon; + +}; + +#endif + + + diff --git a/plugins/LinksCloud/rsrank.h b/plugins/LinksCloud/rsrank.h new file mode 100644 index 000000000..a69425c91 --- /dev/null +++ b/plugins/LinksCloud/rsrank.h @@ -0,0 +1,96 @@ +#ifndef RETROSHARE_RANKING_GUI_INTERFACE_H +#define RETROSHARE_RANKING_GUI_INTERFACE_H + +/* + * libretroshare/src/rsiface: rsrank.h + * + * RetroShare C++ Interface. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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 "retroshare@lunamutt.com". + * + */ + +#include +#include +#include + +/* The Main Interface Class - for information about your Peers */ +class RsRanks; +extern RsRanks *rsRanks; + +class RsRankComment +{ + public: + + std::string id; + std::wstring comment; + int32_t score; + time_t timestamp; +}; + +class RsRankDetails +{ + public: + + std::string rid; + std::wstring link; + std::wstring title; + float rank; + bool ownTag; + + std::list comments; +}; + +const uint32_t RS_RANK_SCORE = 0x0001; +const uint32_t RS_RANK_TIME = 0x0002; +const uint32_t RS_RANK_ALG = 0x0003; + +std::ostream &operator<<(std::ostream &out, const RsRankDetails &detail); + +class RsRanks +{ + public: + + RsRanks() { return; } +virtual ~RsRanks() { return; } + + /* needs update? */ +virtual bool updated() = 0; + + /* Set Sort Methods */ +virtual bool setSortPeriod(uint32_t period) = 0; +virtual bool setSortMethod(uint32_t type) = 0; +virtual bool clearPeerFilter() = 0; +virtual bool setPeerFilter(std::list peers) = 0; + + /* get Ids */ +virtual uint32_t getRankingsCount() = 0; +virtual float getMaxRank() = 0; +virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids) = 0; +virtual bool getRankDetails(std::string rid, RsRankDetails &details) = 0; + + /* Add New Comment / Msg */ +virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) = 0; +virtual bool updateComment(std::string rid, std::wstring comment, int32_t score) = 0; + +virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title) = 0; + +}; + +#endif diff --git a/plugins/LinksCloud/rsrankitems.cc b/plugins/LinksCloud/rsrankitems.cc new file mode 100644 index 000000000..dbae0de68 --- /dev/null +++ b/plugins/LinksCloud/rsrankitems.cc @@ -0,0 +1,253 @@ + +/* + * libretroshare/src/serialiser: rsbaseitems.cc + * + * RetroShare Serialiser. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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 "retroshare@lunamutt.com". + * + */ + +#include "serialiser/rsbaseserial.h" +#include "serialiser/rstlvbase.h" +#include "rsrankitems.h" + +#define RSSERIAL_DEBUG 1 +#include + +/*************************************************************************/ + +void RsRankMsg::clear() +{ + rid.clear(); + timestamp = 0; + title.clear(); + comment.clear(); +} + +std::ostream &RsRankMsg::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsRankMsg", indent); + uint16_t int_Indent = indent + 2; + printIndent(out, int_Indent); + out << "rid: " << rid << std::endl; + + printIndent(out, int_Indent); + out << "timestamp: " << timestamp << std::endl; + + + printIndent(out, int_Indent); + + std::string cnv_title(title.begin(), title.end()); + out << "msg: " << cnv_title << std::endl; + + printIndent(out, int_Indent); + std::string cnv_comment(comment.begin(), comment.end()); + out << "comment: " << cnv_comment << std::endl; + + printIndent(out, int_Indent); + out << "score: " << score << std::endl; + + printRsItemEnd(out, "RsRankMsg", indent); + return out; +} + +/*************************************************************************/ + +void RsRankLinkMsg::clear() +{ + rid.clear(); + pid.clear(); + timestamp = 0; + title.clear(); + comment.clear(); + score = 0; + linktype = 0; + link.clear(); +} + +std::ostream &RsRankLinkMsg::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsRankLinkMsg", indent); + uint16_t int_Indent = indent + 2; + printIndent(out, int_Indent); + out << "rid: " << rid << std::endl; + printIndent(out, int_Indent); + out << "pid: " << pid << std::endl; + + printIndent(out, int_Indent); + out << "timestamp: " << timestamp << std::endl; + + printIndent(out, int_Indent); + + std::string cnv_title(title.begin(), title.end()); + out << "msg: " << cnv_title << std::endl; + + printIndent(out, int_Indent); + std::string cnv_comment(comment.begin(), comment.end()); + out << "comment: " << cnv_comment << std::endl; + + printIndent(out, int_Indent); + out << "score: " << score << std::endl; + + printIndent(out, int_Indent); + out << "linktype: " << linktype << std::endl; + printIndent(out, int_Indent); + std::string cnv_link(link.begin(), link.end()); + out << "link: " << cnv_link << std::endl; + + printRsItemEnd(out, "RsRankLinkMsg", indent); + return out; +} + + +uint32_t RsRankSerialiser::sizeLink(RsRankLinkMsg *item) +{ + uint32_t s = 8; /* header */ + s += GetTlvStringSize(item->rid); + s += GetTlvStringSize(item->pid); + s += 4; /* timestamp */ + s += GetTlvWideStringSize(item->title); + s += GetTlvWideStringSize(item->comment); + s += 4; /* score */ + s += 4; /* linktype */ + s += GetTlvWideStringSize(item->link); + + return s; +} + +/* serialise the data to the buffer */ +bool RsRankSerialiser::serialiseLink(RsRankLinkMsg *item, void *data, uint32_t *pktsize) +{ + uint32_t tlvsize = sizeLink(item); + uint32_t offset = 0; + + if (*pktsize < tlvsize) + return false; /* not enough space */ + + *pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GENID, item->rid); + ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_PEERID, item->pid); + + ok &= setRawUInt32(data, tlvsize, &offset, item->timestamp); + + ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_TITLE, item->title); + ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); + + ok &= setRawUInt32(data, tlvsize, &offset, *((uint32_t *) &(item->score))); + + ok &= setRawUInt32(data, tlvsize, &offset, item->linktype); + + ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_LINK, item->link); + + if (offset != tlvsize) + { + ok = false; + std::cerr << "RsRankLinkSerialiser::serialiseLink() Size Error! " << std::endl; + } + + return ok; +} + +RsRankLinkMsg *RsRankSerialiser::deserialiseLink(void *data, uint32_t *pktsize) +{ + /* get the type and size */ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + + uint32_t offset = 0; + + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || + (RS_SERVICE_TYPE_RANK != getRsItemService(rstype)) || + (RS_PKT_SUBTYPE_RANK_LINK3 != getRsItemSubType(rstype))) + { + return NULL; /* wrong type */ + } + + if (*pktsize < rssize) /* check size */ + return NULL; /* not enough data */ + + /* set the packet length */ + *pktsize = rssize; + + bool ok = true; + + /* ready to load */ + RsRankLinkMsg *item = new RsRankLinkMsg(); + item->clear(); + + /* skip the header */ + offset += 8; + + /* get mandatory parts first */ + ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_GENID, item->rid); + ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_PEERID, item->pid); + ok &= getRawUInt32(data, rssize, &offset, &(item->timestamp)); + ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_TITLE, item->title); + ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); + ok &= getRawUInt32(data, rssize, &offset, (uint32_t *) &(item->score)); + ok &= getRawUInt32(data, rssize, &offset, &(item->linktype)); + ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_LINK, item->link); + + if (offset != rssize) + { + /* error */ + delete item; + return NULL; + } + + if (!ok) + { + delete item; + return NULL; + } + + return item; +} + + +uint32_t RsRankSerialiser::size(RsItem *item) +{ + return sizeLink((RsRankLinkMsg *) item); +} + +bool RsRankSerialiser::serialise(RsItem *item, void *data, uint32_t *pktsize) +{ + return serialiseLink((RsRankLinkMsg *) item, data, pktsize); +} + +RsItem *RsRankSerialiser::deserialise(void *data, uint32_t *pktsize) +{ + return deserialiseLink(data, pktsize); +} + + + +/*************************************************************************/ + diff --git a/plugins/LinksCloud/rsrankitems.h b/plugins/LinksCloud/rsrankitems.h new file mode 100644 index 000000000..a3ddc78aa --- /dev/null +++ b/plugins/LinksCloud/rsrankitems.h @@ -0,0 +1,110 @@ +#ifndef RS_RANK_ITEMS_H +#define RS_RANK_ITEMS_H + +/* + * libretroshare/src/serialiser: rsrankitems.h + * + * RetroShare Serialiser. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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 "retroshare@lunamutt.com". + * + */ + +#include "serialiser/rsserial.h" +#include "serialiser/rstlvtypes.h" + +#include "p3ranking.h" + +const uint8_t RS_PKT_SUBTYPE_RANK_LINK3 = 0x04; +const uint8_t RS_PKT_SUBTYPE_RANK_PHOTO = 0x05; + +/**************************************************************************/ + + +class RsRankMsg: public RsItem +{ + public: + RsRankMsg(uint8_t subtype) :RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK, subtype) { return; } + + virtual ~RsRankMsg() { return; } + virtual void clear(); + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + std::string rid; /* Random Id */ + std::string pid; /* Peer Id (cannot use RsItem::PeerId - as FoF transport!) */ + uint32_t timestamp; + std::wstring title; + std::wstring comment; + int32_t score; +}; + + +/* Flags */ +const uint32_t RS_LINK_TYPE_WEB = 0x0001; +const uint32_t RS_LINK_TYPE_OFF = 0x0002; + +class RsRankLinkMsg: public RsRankMsg +{ + public: + RsRankLinkMsg() + :RsRankMsg(RS_PKT_SUBTYPE_RANK_LINK3) { return; } +virtual ~RsRankLinkMsg() { return; } +virtual void clear(); +virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + /**** SAME as RsRankMsg **** + std::string rid; + uint32_t timestamp; + std::wstring title; + std::wstring comment; + int32_t score; + ***************************/ + + /* Link specific Fields */ + uint32_t linktype; /* to be used later! */ + std::wstring link; +}; + +class RsRankSerialiser: public RsSerialType +{ + public: + RsRankSerialiser() + :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK) + { return; } +virtual ~RsRankSerialiser() + { return; } + +virtual uint32_t size(RsItem *); +virtual bool serialise (RsItem *item, void *data, uint32_t *size); +virtual RsItem * deserialise(void *data, uint32_t *size); + + private: + + /* For RS_PKT_SUBTYPE_RANK_LINK */ +virtual uint32_t sizeLink(RsRankLinkMsg *); +virtual bool serialiseLink (RsRankLinkMsg *item, void *data, uint32_t *size); +virtual RsRankLinkMsg *deserialiseLink(void *data, uint32_t *size); + +}; + +/**************************************************************************/ + +#endif /* RS_RANK_ITEMS_H */ + + diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 4c9983d4f..cd37c501b 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -1,5 +1,4 @@ CONFIG += qt gui uic qrc resources uitools idle bitdht # framecatcher# blogs -#CONFIG += use_links QT += network xml script TEMPLATE = app @@ -39,6 +38,7 @@ linux-* { LIBS += ../../libretroshare/src/lib/libretroshare.a LIBS += -lssl -lgpgme -lupnp -lXss -lgnome-keyring + LIBS *= -rdynamic DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions DEFINES *= UBUNTU } @@ -660,18 +660,18 @@ SOURCES += gui/unfinished/blogs/BlogsDialog.cpp \ DEFINES += BLOGS } -use_links { -HEADERS += gui/AddLinksDialog.h \ - gui/LinksDialog.h - -FORMS += gui/AddLinksDialog.ui \ - gui/LinksDialog.ui - -SOURCES += gui/AddLinksDialog.cpp \ - gui/LinksDialog.cpp - -DEFINES += RS_USE_LINKS -} +# use_links { +# HEADERS += gui/AddLinksDialog.h \ +# gui/LinksDialog.h +# +# FORMS += gui/AddLinksDialog.ui \ +# gui/LinksDialog.ui +# +# SOURCES += gui/AddLinksDialog.cpp \ +# gui/LinksDialog.cpp +# +# DEFINES += RS_USE_LINKS +# } unfinished { diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index d99f28efa..e873d0226 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -32,6 +32,7 @@ #include "gui/unfinished/blogs/BlogsDialog.h" #endif +#include #include "rshare.h" #include "MainWindow.h" #include "MessengerWindow.h" @@ -43,9 +44,6 @@ #include "PluginsPage.h" #include "ShareManager.h" #include "NetworkView.h" -#ifdef RS_USE_LINKS -#include "LinksDialog.h" -#endif #include "ForumsDialog.h" #include "FriendsDialog.h" #include "HelpDialog.h" @@ -96,7 +94,6 @@ #define IMAGE_PEERS ":/images/groupchat.png" #define IMAGE_SEARCH ":/images/filefind.png" #define IMAGE_TRANSFERS ":/images/ktorrent32.png" -#define IMAGE_LINKS ":/images/irkick.png" #define IMAGE_FILES ":/images/fileshare32.png" #define IMAGE_CHANNELS ":/images/channels.png" #define IMAGE_FORUMS ":/images/konversation.png" @@ -244,17 +241,22 @@ MainWindow::MainWindow(QWidget* parent, Qt::WFlags flags) channelAction = createPageAction(QIcon(IMAGE_CHANNELS), tr("Channels"), grp)); #ifdef BLOGS - ui.stackPages->add(blogsFeed = new BlogsDialog(ui.stackPages), - createPageAction(QIcon(IMAGE_BLOGS), tr("Blogs"), grp)); + ui.stackPages->add(blogsFeed = new BlogsDialog(ui.stackPages), createPageAction(QIcon(IMAGE_BLOGS), tr("Blogs"), grp)); #endif ui.stackPages->add(forumsDialog = new ForumsDialog(ui.stackPages), forumAction = createPageAction(QIcon(IMAGE_FORUMS), tr("Forums"), grp)); -#ifdef RS_USE_LINKS - ui.stackPages->add(linksDialog = new LinksDialog(ui.stackPages), - createPageAction(QIcon(IMAGE_LINKS), tr("Links Cloud"), grp)); -#endif + 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) + { + 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(linksDialog = new LinksDialog(ui.stackPages), createPageAction(QIcon(IMAGE_LINKS), tr("Links Cloud"), grp)); + } #ifndef RS_RELEASE_VERSION #ifdef PLUGINMGR @@ -913,11 +915,6 @@ void MainWindow::addAction(QAction *action, const char *slot) case Messages: Page = _instance->messagesDialog; break; -#ifdef RS_USE_LINKS - case Links: - Page = _instance->linksDialog; - break; -#endif case Channels: Page = _instance->channelFeed; break; diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index bfed4a542..b093229a4 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -9,8 +9,7 @@ images/pgp.png images/rs_wizard.png images/about.png - images/irkick.png - images/backblue.png + images/backblue.png images/backchat.png images/buttonframe.png images/btn1.png