diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index 401fa4c08..5f634ca7b 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -48,6 +48,7 @@ #define DEBUG_RSLINK 1 #define HOST_FILE "file" +#define HOST_EXTRAFILE "extra" #define HOST_PERSON "person" #define HOST_FORUM "forum" #define HOST_CHANNEL "channel" @@ -59,6 +60,7 @@ #define FILE_NAME "name" #define FILE_SIZE "size" #define FILE_HASH "hash" +#define FILE_SOURCE "src" #define PERSON_NAME "name" #define PERSON_HASH "hash" @@ -179,6 +181,27 @@ void RetroShareLink::fromUrl(const QUrl& url) } } + if (url.host() == HOST_EXTRAFILE) { + bool ok ; + + _type = TYPE_EXTRAFILE; + _name = url.queryItemValue(FILE_NAME); + _size = url.queryItemValue(FILE_SIZE).toULongLong(&ok); + _hash = url.queryItemValue(FILE_HASH).left(40); // normally not necessary, but it's a security. + _SSLid = url.queryItemValue(FILE_SOURCE); + + if (ok) { +#ifdef DEBUG_RSLINK + std::cerr << "New RetroShareLink forged:" << std::endl ; + std::cerr << " name = \"" << _name.toStdString() << "\"" << std::endl ; + std::cerr << " hash = \"" << _hash.toStdString() << "\"" << std::endl ; + std::cerr << " size = " << _size << std::endl ; + std::cerr << " src = " << _SSLid.toStdString() << std::endl ; +#endif + check(); + return; + } + } if (url.host() == HOST_PERSON) { _type = TYPE_PERSON; _name = url.queryItemValue(PERSON_NAME); @@ -246,6 +269,21 @@ RetroShareLink::RetroShareLink() clear(); } +bool RetroShareLink::createExtraFile(const QString& name, uint64_t size, const QString& hash,const QString& ssl_id) +{ + clear(); + + _name = name; + _size = size; + _hash = hash; + _SSLid = ssl_id; + + _type = TYPE_EXTRAFILE; + + check(); + + return valid(); +} bool RetroShareLink::createFile(const QString& name, uint64_t size, const QString& hash) { clear(); @@ -463,6 +501,9 @@ void RetroShareLink::check() case TYPE_UNKNOWN: _valid = false; break; + case TYPE_EXTRAFILE: + if(!checkSSLId(_SSLid)) + _valid = false; // no break! We also test file stuff below. case TYPE_FILE: if(_size > (((uint64_t)1)<<40)) // 1TB. Who has such large files? _valid = false; @@ -538,6 +579,8 @@ QString RetroShareLink::title() const switch (_type) { case TYPE_UNKNOWN: break; + case TYPE_EXTRAFILE: + return QString("%1 (%2, Extra - Source included)").arg(hash()).arg(misc::friendlyUnit(size())); case TYPE_FILE: return QString("%1 (%2)").arg(hash()).arg(misc::friendlyUnit(size())); case TYPE_PERSON: @@ -576,6 +619,19 @@ QString RetroShareLink::toString() const return url.toString(); } + case TYPE_EXTRAFILE: + { + QUrl url; + url.setScheme(RSLINK_SCHEME); + url.setHost(HOST_EXTRAFILE); + url.addQueryItem(FILE_NAME, encodeItem(_name)); + url.addQueryItem(FILE_SIZE, QString::number(_size)); + url.addQueryItem(FILE_HASH, _hash); + url.addQueryItem(FILE_SOURCE, _SSLid); + + return url.toString(); + } + case TYPE_PERSON: { QUrl url; @@ -699,6 +755,7 @@ QString RetroShareLink::toHtmlFull() const QString RetroShareLink::toHtmlSize() const { QString size = QString("(%1)").arg(misc::friendlyUnit(_size)); + if (type() == TYPE_FILE && RsCollectionFile::isCollectionFile(name())) { FileInfo finfo; if (rsFiles->FileDetails(hash().toStdString(), RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL, finfo)) { @@ -740,6 +797,23 @@ QUrl RetroShareLink::toUrl() const return QUrl::fromEncoded(toString().toUtf8().constData()); } +bool RetroShareLink::checkSSLId(const QString& ssl_id) +{ + if(ssl_id.length() != 32) + return false ; + + QByteArray qb(ssl_id.toAscii()) ; + + for(int i=0;i47 && b<58) || (b>96 && b<103))) + return false ; + } + + return true ; +} bool RetroShareLink::checkHash(const QString& hash) { if(hash.length() != 40) @@ -816,6 +890,7 @@ static void processList(const QStringList &list, const QString &textSingular, co break; case TYPE_FILE: + case TYPE_EXTRAFILE: fileAdd.append(link.name()); break; @@ -953,15 +1028,27 @@ static void processList(const QStringList &list, const QString &textSingular, co break ; case TYPE_FILE: + case TYPE_EXTRAFILE: { #ifdef DEBUG_RSLINK std::cerr << " RetroShareLink::process FileRequest : fileName : " << link.name().toUtf8().constData() << ". fileHash : " << link.hash().toStdString() << ". fileSize : " << link.size() << std::endl; #endif needNotifySuccess = true; + std::list srcIds; + + // Add the link built-in source. This is needed for EXTRA files, where the source is specified in the link. + + if(link.type() == TYPE_EXTRAFILE) + { +#ifdef DEBUG_RSLINK + std::cerr << " RetroShareLink::process Adding built-in source " << link.SSLId().toStdString() << std::endl; +#endif + srcIds.push_back(link.SSLId().toStdString()) ; + } // Get a list of available direct sources, in case the file is browsable only. - std::list srcIds; + // FileInfo finfo ; rsFiles->FileDetails(link.hash().toStdString(), RS_FILE_HINTS_REMOTE, finfo) ; diff --git a/retroshare-gui/src/gui/RetroShareLink.h b/retroshare-gui/src/gui/RetroShareLink.h index 8b5df7544..dfc706c39 100644 --- a/retroshare-gui/src/gui/RetroShareLink.h +++ b/retroshare-gui/src/gui/RetroShareLink.h @@ -46,11 +46,12 @@ #define RSLINK_SCHEME "retroshare" #define RSLINK_SUBTYPE_CERTIFICATE_USER_REQUEST 1 +#define RSLINK_SUBTYPE_FILE_EXTRA 2 class RetroShareLink { public: - enum enumType { TYPE_UNKNOWN, TYPE_FILE, TYPE_PERSON, TYPE_FORUM, TYPE_CHANNEL, TYPE_SEARCH, TYPE_MESSAGE, TYPE_CERTIFICATE }; + enum enumType { TYPE_UNKNOWN, TYPE_FILE, TYPE_PERSON, TYPE_FORUM, TYPE_CHANNEL, TYPE_SEARCH, TYPE_MESSAGE, TYPE_CERTIFICATE,TYPE_EXTRAFILE }; public: RetroShareLink(); @@ -58,6 +59,7 @@ class RetroShareLink RetroShareLink(const QString& url); bool createFile(const QString& name, uint64_t size, const QString& hash); + bool createExtraFile(const QString& name, uint64_t size, const QString& hash, const QString& ssl_id); bool createPerson(const std::string& id); bool createForum(const std::string& id, const std::string& msgId); bool createChannel(const std::string& id, const std::string& msgId); @@ -116,6 +118,7 @@ class RetroShareLink void check(); static bool checkHash(const QString& hash); static bool checkName(const QString& name); + static bool checkSSLId(const QString& name); bool _valid; enumType _type; diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 7bebd75ae..72446b521 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -629,7 +629,7 @@ void ChatWidget::fileHashingFinished(QList hashedFiles) QString ext = QFileInfo(hashedFile.filename).suffix(); RetroShareLink link; - link.createFile(hashedFile.filename, hashedFile.size, QString::fromStdString(hashedFile.hash)); + link.createExtraFile(hashedFile.filename, hashedFile.size, QString::fromStdString(hashedFile.hash),QString::fromStdString(rsPeers->getOwnId())); if (hashedFile.flag & HashedFile::Picture) { message += QString("").arg(hashedFile.filepath); diff --git a/retroshare-gui/src/gui/common/LinkTextBrowser.cpp b/retroshare-gui/src/gui/common/LinkTextBrowser.cpp index dddc6124b..96438a43d 100644 --- a/retroshare-gui/src/gui/common/LinkTextBrowser.cpp +++ b/retroshare-gui/src/gui/common/LinkTextBrowser.cpp @@ -15,5 +15,22 @@ void LinkTextBrowser::linkClicked(const QUrl &url) { // some links are opened directly in the QTextBrowser with open external links set to true, // so we handle links by our own - QDesktopServices::openUrl(url); + +#ifdef TO_DO + // If we want extra file links to be anonymous, we need to insert the actual source here. + if(url.host() == HOST_EXTRAFILE) + { + std::cerr << "Extra file link detected. Adding parent id " << _target_sslid << " to sourcelist" << std::endl; + + RetroShareLink link ; + link.fromUrl(url) ; + + link.createExtraFile( link.name(),link.size(),link.hash(), _target_ssl_id) ; + + QDesktopServices::openUrl(link.toUrl()); + } + else +#endif + QDesktopServices::openUrl(url); } +